UNPKG

knx

Version:

KNXnet/IP protocol implementation for Node(>=6.x)

117 lines (109 loc) 4.85 kB
/** * knx.js - a KNX protocol stack in pure Javascript * (C) 2016-2018 Elias Karakoulakis */ const KnxLog = require('./KnxLog'); const Parser = require('binary-parser').Parser; // +-----------------------------------------------+ // 16 bits | INDIVIDUAL ADDRESS | // +-----------------------+-----------------------+ // | OCTET 0 (high byte) | OCTET 1 (low byte) | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // bits | 7| 6| 5| 4| 3| 2| 1| 0| 7| 6| 5| 4| 3| 2| 1| 0| // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | Subnetwork Address | | // +-----------+-----------+ Device Address | // |(Area Adrs)|(Line Adrs)| | // +-----------------------+-----------------------+ // +-----------------------------------------------+ // 16 bits | GROUP ADDRESS (3 level) | // +-----------------------+-----------------------+ // | OCTET 0 (high byte) | OCTET 1 (low byte) | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // bits | 7| 6| 5| 4| 3| 2| 1| 0| 7| 6| 5| 4| 3| 2| 1| 0| // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | | Main Grp | Midd G | Sub Group | // +--+--------------------+-----------------------+ // +-----------------------------------------------+ // 16 bits | GROUP ADDRESS (2 level) | // +-----------------------+-----------------------+ // | OCTET 0 (high byte) | OCTET 1 (low byte) | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // bits | 7| 6| 5| 4| 3| 2| 1| 0| 7| 6| 5| 4| 3| 2| 1| 0| // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | | Main Grp | Sub Group | // +--+--------------------+-----------------------+ // NOTE: ets4 can utilise all 5 bits for the main group (0..31) const TYPE = { PHYSICAL: 0x00, GROUP: 0x01, }; const threeLevelPhysical = new Parser().bit4('l1').bit4('l2').uint8('l3'); const threeLevelGroup = new Parser().bit5('l1').bit3('l2').uint8('l3'); const twoLevel = new Parser().bit5('l1').bit11('l2'); // convert address stored in two-byte buffer to string const toString = function ( buf /*buffer*/, addrtype /*ADDRESS_TYPE*/, twoLevelAddressing /*boolean*/ ) { const group = addrtype == TYPE.GROUP; //KnxLog.get().trace('%j, type: %d, %j', buf, addrtype, knxnetprotocol.twoLevelAddressing); if (!Buffer.isBuffer(buf) || buf.length !== 2) throw 'not a buffer, or not a 2-byte address buffer'; if (group && twoLevelAddressing) { // 2 level group const { l1, l2 } = twoLevel.parse(buf); return [l1, l2].join('/'); } // 3 level physical or group address const sep = group ? '/' : '.'; const parser = group ? threeLevelGroup : threeLevelPhysical; const { l1, l2, l3 } = parser.parse(buf); return [l1, l2, l3].join(sep); }; // check for out of range integer const r = (x, max) => x < 0 || x > max; // parse address string to 2-byte Buffer const parse = function ( addr /*string*/, addrtype /*TYPE*/, twoLevelAddressing ) { if (!addr) { KnxLog.get().warn('Fix your code - no address given to Address.parse'); } const group = addrtype === TYPE.GROUP; const address = Buffer.allocUnsafe(2); const tokens = addr .split(group ? '/' : '.') .filter((w) => w.length > 0) .map((w) => parseInt(w)); if (tokens.length < 2) throw 'Invalid address (less than 2 tokens)'; const [hinibble, midnibble, lonibble] = tokens; if (group && twoLevelAddressing) { // 2 level group address if (r(hinibble, 31)) throw 'Invalid KNX 2-level main group: ' + addr; if (r(midnibble, 2047)) throw 'Invalid KNX 2-level sub group: ' + addr; address.writeUInt16BE((hinibble << 11) + midnibble, 0); return address; } if (tokens.length < 3) throw 'Invalid address - missing 3rd token'; if (group) { // 3 level group address if (r(hinibble, 31)) throw 'Invalid KNX 3-level main group: ' + addr; if (r(midnibble, 7)) throw 'Invalid KNX 3-level mid group: ' + addr; if (r(lonibble, 255)) throw 'Invalid KNX 3-level sub group: ' + addr; address.writeUInt8((hinibble << 3) + midnibble, 0); address.writeUInt8(lonibble, 1); return address; } // 3 level physical address if (r(hinibble, 15)) throw 'Invalid KNX area address: ' + addr; if (r(midnibble, 15)) throw 'Invalid KNX line address: ' + addr; if (r(lonibble, 255)) throw 'Invalid KNX device address: ' + addr; address.writeUInt8((hinibble << 4) + midnibble, 0); address.writeUInt8(lonibble, 1); return address; }; module.exports = { TYPE, toString, parse };