knxnetjs
Version: 
A TypeScript library for KNXnet/IP communication
161 lines • 5.93 kB
JavaScript
;
/**
 * KNX USB Transfer Protocol implementation
 * Handles the KNX USB Transfer Protocol Header and Body structures
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.KNXUSBTransferFrame = exports.KNXUSBTransferEMIId = exports.KNXUSBTransferProtocolId = void 0;
var KNXUSBTransferProtocolId;
(function (KNXUSBTransferProtocolId) {
    KNXUSBTransferProtocolId[KNXUSBTransferProtocolId["KNXTunnel"] = 1] = "KNXTunnel";
    KNXUSBTransferProtocolId[KNXUSBTransferProtocolId["BusAccessServerFeatureService"] = 15] = "BusAccessServerFeatureService";
})(KNXUSBTransferProtocolId || (exports.KNXUSBTransferProtocolId = KNXUSBTransferProtocolId = {}));
var KNXUSBTransferEMIId;
(function (KNXUSBTransferEMIId) {
    KNXUSBTransferEMIId[KNXUSBTransferEMIId["EMI1"] = 1] = "EMI1";
    KNXUSBTransferEMIId[KNXUSBTransferEMIId["EMI2"] = 2] = "EMI2";
    KNXUSBTransferEMIId[KNXUSBTransferEMIId["cEMI"] = 3] = "cEMI";
})(KNXUSBTransferEMIId || (exports.KNXUSBTransferEMIId = KNXUSBTransferEMIId = {}));
class KNXUSBTransferFrame {
    constructor(header, body) {
        this.header = header;
        this.body = body;
    }
    /**
     * Creates a KNX USB Transfer Frame from a Buffer
     */
    static fromBuffer(buffer) {
        if (buffer.length < 8) {
            throw new Error("Buffer too short for KNX USB Transfer Header");
        }
        // Parse Header
        const header = {
            protocolVersion: buffer[0] || 0,
            headerLength: buffer[1] || 0,
            bodyLength: buffer.readUInt16BE(2),
            protocolId: buffer[4] || 0,
            emiId: buffer[5] || 0,
            manufacturerCode: buffer.readUInt16BE(6),
        };
        // Validate header
        if (header.headerLength !== 0x08) {
            throw new Error(`Invalid header length: ${header.headerLength}`);
        }
        if (buffer.length < header.headerLength + 1) {
            throw new Error("Buffer too short for KNX USB Transfer Body");
        }
        // Parse Body
        const bodyStart = header.headerLength;
        const emiMessageCode = buffer[bodyStart] || 0;
        const data = buffer.subarray(bodyStart + 1);
        const body = {
            emiMessageCode,
            data,
        };
        return new KNXUSBTransferFrame(header, body);
    }
    /**
     * Converts the frame to a Buffer
     */
    toBuffer() {
        const bodyBuffer = Buffer.allocUnsafe(1 + this.body.data.length);
        bodyBuffer[0] = this.body.emiMessageCode;
        this.body.data.copy(bodyBuffer, 1);
        const headerBuffer = Buffer.allocUnsafe(8);
        headerBuffer[0] = this.header.protocolVersion;
        headerBuffer[1] = this.header.headerLength;
        headerBuffer.writeUInt16BE(bodyBuffer.length, 2); // body length
        headerBuffer[4] = this.header.protocolId;
        headerBuffer[5] = this.header.emiId;
        headerBuffer.writeUInt16BE(this.header.manufacturerCode, 6);
        return Buffer.concat([headerBuffer, bodyBuffer]);
    }
    /**
     * Creates a KNX USB Transfer Frame for cEMI data
     */
    static createForCEMI(cemiData, manufacturerCode = 0x0000) {
        const body = {
            emiMessageCode: cemiData[0],
            data: cemiData.subarray(1),
        };
        const header = {
            protocolVersion: 0x00,
            headerLength: 0x08,
            bodyLength: 1 + cemiData.length, // message code + data
            protocolId: KNXUSBTransferProtocolId.KNXTunnel,
            emiId: KNXUSBTransferEMIId.cEMI,
            manufacturerCode,
        };
        return new KNXUSBTransferFrame(header, body);
    }
    /**
     * Creates a KNX USB Transfer Frame for bus access
     */
    static createForBusAccess(service, feature, value) {
        const body = {
            emiMessageCode: feature,
            data: value,
        };
        const header = {
            protocolVersion: 0x00,
            headerLength: 0x08,
            bodyLength: 1 + value.length, // feature + data
            protocolId: KNXUSBTransferProtocolId.BusAccessServerFeatureService,
            emiId: service,
            manufacturerCode: 0x0000,
        };
        return new KNXUSBTransferFrame(header, body);
    }
    /**
     * Validates if a buffer contains a valid KNX USB Transfer Frame
     */
    static isValid(buffer) {
        if (buffer.length < 9) {
            // Minimum: 8-byte header + 1-byte EMI message code
            return false;
        }
        const protocolVersion = buffer[0];
        const headerLength = buffer[1];
        const protocolId = buffer[4];
        const emiId = buffer[5];
        return (protocolVersion === 0x00 &&
            headerLength === 0x08 &&
            protocolId === KNXUSBTransferProtocolId.KNXTunnel &&
            emiId === KNXUSBTransferEMIId.cEMI);
    }
    /**
     * Gets the cEMI data from the frame body
     */
    getCEMIData() {
        if (this.body.emiMessageCode === 0x11) {
            // cEMI format
            return this.body.data;
        }
        return null;
    }
    /**
     * Returns frame information as a string for debugging
     */
    toString() {
        return `KNXUSBTransferFrame {
  header: {
    protocolVersion: 0x${this.header.protocolVersion
            .toString(16)
            .padStart(2, "0")},
    headerLength: 0x${this.header.headerLength.toString(16).padStart(2, "0")},
    bodyLength: ${this.header.bodyLength},
    protocolId: 0x${this.header.protocolId.toString(16).padStart(2, "0")},
    emiId: 0x${this.header.emiId.toString(16).padStart(2, "0")},
    manufacturerCode: 0x${this.header.manufacturerCode
            .toString(16)
            .padStart(4, "0")}
  },
  body: {
    emiMessageCode: 0x${this.body.emiMessageCode.toString(16).padStart(2, "0")},
    dataLength: ${this.body.data.length}
  }
}`;
    }
}
exports.KNXUSBTransferFrame = KNXUSBTransferFrame;
//# sourceMappingURL=knx-usb-transfer.js.map