UNPKG

ethernet-ip

Version:

A feature-complete EtherNet/IP client for Rockwell ControlLogix/CompactLogix PLCs

93 lines 3.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SIZE = exports.EIP_HEADER_SIZE = void 0; exports.buildHeader = buildHeader; exports.parseHeader = parseHeader; const commands_1 = require("./commands"); /** * EIP Encapsulation Header — 24 bytes fixed size. * Per CIP Vol 2, Table 2-2.1 — Encapsulation Header * * Byte layout: * Offset Size Field * ------ ---- ----- * 0 2 Command (UINT16LE) * 2 2 Length (UINT16LE) — byte count of Data field only * 4 4 Session Handle (UINT32LE) * 8 4 Status (UINT32LE) * 12 8 Sender Context (8 bytes, echoed back by target) * 20 4 Options (UINT32LE) * 24 N Data (variable length) */ exports.EIP_HEADER_SIZE = 24; /** Byte offsets within the EIP header */ const OFFSET = { COMMAND: 0, LENGTH: 2, SESSION: 4, STATUS: 8, SENDER_CONTEXT: 12, OPTIONS: 20, DATA: 24, }; /** Field sizes in bytes */ exports.SIZE = { COMMAND: 2, LENGTH: 2, SESSION: 4, STATUS: 4, SENDER_CONTEXT: 8, OPTIONS: 4, }; /** * Build an EIP encapsulation packet (header + data payload). * * @param cmd - EIP command code * @param session - Session handle (0 for RegisterSession) * @param data - Data payload to encapsulate */ function buildHeader(cmd, session = 0, data) { if (!(0, commands_1.isValidCommand)(cmd)) { throw new Error(`Invalid EIP command: 0x${cmd.toString(16)}`); } const payload = data ? Buffer.from(data) : Buffer.alloc(0); const buf = Buffer.alloc(exports.EIP_HEADER_SIZE + payload.length); buf.writeUInt16LE(cmd, OFFSET.COMMAND); // Command code buf.writeUInt16LE(payload.length, OFFSET.LENGTH); // Length of data payload buf.writeUInt32LE(session, OFFSET.SESSION); // Session handle // Status (offset 8) = 0x00 — always zero for requests // Sender Context (offset 12) = 0x00 — zeroed by Buffer.alloc // Options (offset 20) = 0x00 — always zero if (payload.length > 0) { payload.copy(buf, OFFSET.DATA); } return buf; } /** * Parse an EIP encapsulation packet from a raw buffer. * * @param buf - Raw buffer received from target (must be >= 24 bytes) */ function parseHeader(buf) { if (buf.length < exports.EIP_HEADER_SIZE) { throw new Error(`Buffer too short for EIP header: ${buf.length} < ${exports.EIP_HEADER_SIZE}`); } const commandCode = buf.readUInt16LE(OFFSET.COMMAND); const length = buf.readUInt16LE(OFFSET.LENGTH); const session = buf.readUInt32LE(OFFSET.SESSION); const statusCode = buf.readUInt32LE(OFFSET.STATUS); const options = buf.readUInt32LE(OFFSET.OPTIONS); // Extract data payload starting after the 24-byte header const data = buf.subarray(OFFSET.DATA, OFFSET.DATA + length); return { commandCode, command: (0, commands_1.getCommandName)(commandCode), length, session, statusCode, status: (0, commands_1.parseStatus)(statusCode), options, data, }; } //# sourceMappingURL=header.js.map