knx.js
Version:
KNXnetIP (KNX over IP) deriver for nodejs.
154 lines (135 loc) • 10.2 kB
JavaScript
/**
* Created by aborovsky on 26.08.2015.
*/
var KnxData = require('./KnxData');
function KnxReceiver(/*KnxConnection*/ connection) {
this.connection = connection;
}
KnxReceiver.prototype.ProcessCEMI = function (/*KnxDatagram*/ datagram, /*buffer*/ cemi) {
try {
// CEMI
// +--------+--------+--------+--------+----------------+----------------+--------+----------------+
// | Msg |Add.Info| Ctrl 1 | Ctrl 2 | Source Address | Dest. Address | Data | APDU |
// | Code | Length | | | | | Length | |
// +--------+--------+--------+--------+----------------+----------------+--------+----------------+
// 1 byte 1 byte 1 byte 1 byte 2 bytes 2 bytes 1 byte 2 bytes
//
// Message Code = 0x11 - a L_Data.req primitive
// COMMON EMI MESSAGE CODES FOR DATA LINK LAYER PRIMITIVES
// FROM NETWORK LAYER TO DATA LINK LAYER
// +---------------------------+--------------+-------------------------+---------------------+------------------+
// | Data Link Layer Primitive | Message Code | Data Link Layer Service | Service Description | Common EMI Frame |
// +---------------------------+--------------+-------------------------+---------------------+------------------+
// | L_Raw.req | 0x10 | | | |
// +---------------------------+--------------+-------------------------+---------------------+------------------+
// | | | | Primitive used for | Sample Common |
// | L_Data.req | 0x11 | Data Service | transmitting a data | EMI frame |
// | | | | frame | |
// +---------------------------+--------------+-------------------------+---------------------+------------------+
// | L_Poll_Data.req | 0x13 | Poll Data Service | | |
// +---------------------------+--------------+-------------------------+---------------------+------------------+
// | L_Raw.req | 0x10 | | | |
// +---------------------------+--------------+-------------------------+---------------------+------------------+
// FROM DATA LINK LAYER TO NETWORK LAYER
// +---------------------------+--------------+-------------------------+---------------------+
// | Data Link Layer Primitive | Message Code | Data Link Layer Service | Service Description |
// +---------------------------+--------------+-------------------------+---------------------+
// | L_Poll_Data.con | 0x25 | Poll Data Service | |
// +---------------------------+--------------+-------------------------+---------------------+
// | | | | Primitive used for |
// | L_Data.ind | 0x29 | Data Service | receiving a data |
// | | | | frame |
// +---------------------------+--------------+-------------------------+---------------------+
// | L_Busmon.ind | 0x2B | Bus Monitor Service | |
// +---------------------------+--------------+-------------------------+---------------------+
// | L_Raw.ind | 0x2D | | |
// +---------------------------+--------------+-------------------------+---------------------+
// | | | | Primitive used for |
// | | | | local confirmation |
// | L_Data.con | 0x2E | Data Service | that a frame was |
// | | | | sent (does not mean |
// | | | | successful receive) |
// +---------------------------+--------------+-------------------------+---------------------+
// | L_Raw.con | 0x2F | | |
// +---------------------------+--------------+-------------------------+---------------------+
// Add.Info Length = 0x00 - no additional info
// Control Field 1 = see the bit structure above
// Control Field 2 = see the bit structure above
// Source Address = 0x0000 - filled in by router/gateway with its source address which is
// part of the KNX subnet
// Dest. Address = KNX group or individual address (2 byte)
// Data Length = Number of bytes of data in the APDU excluding the TPCI/APCI bits
// APDU = Application Protocol Data Unit - the actual payload including transport
// protocol control information (TPCI), application protocol control
// information (APCI) and data passed as an argument from higher layers of
// the KNX communication stack
//
datagram.message_code = cemi[0];
datagram.additional_info_length = cemi[1];
if (datagram.additional_info_length > 0) {
datagram.additional_info = new Buffer(datagram.additional_info_length);
for (var i = 0; i < datagram.additional_info_length; i++) {
datagram.additional_info[i] = cemi[2 + i];
}
}
datagram.control_field_1 = cemi[2 + datagram.additional_info_length];
datagram.control_field_2 = cemi[3 + datagram.additional_info_length];
var buf = new Buffer(2);
buf[0] = cemi[4 + datagram.additional_info_length];
buf[1] = cemi[5 + datagram.additional_info_length];
datagram.source_address = KnxHelper.GetIndividualAddress(buf);
buf = new Buffer(2);
buf[0] = cemi[6 + datagram.additional_info_length];
buf[1] = cemi[7 + datagram.additional_info_length];
datagram.destination_address =
(KnxHelper.GetKnxDestinationAddressType(datagram.control_field_2) === KnxHelper.KnxDestinationAddressType.INDIVIDUAL) ?
KnxHelper.GetIndividualAddress(buf) :
KnxHelper.GetGroupAddress(buf, this.connection.ThreeLevelGroupAddressing);
datagram.data_length = cemi[8 + datagram.additional_info_length];
datagram.apdu = new Buffer(datagram.data_length + 1);
for (var i = 0; i < datagram.apdu.length; i++)
datagram.apdu[i] = cemi[9 + i + datagram.additional_info_length];
datagram.data = KnxHelper.GetData(datagram.data_length, datagram.apdu);
datagram.dptData = new KnxData(datagram.apdu);
if (this.connection.debug) {
console.log("-----------------------------------------------------------------------------------------------------");
console.log(cemi.toString('hex'));
console.log("Event Header Length: " + datagram.header_length);
console.log("Event Protocol Version: " + datagram.protocol_version);
console.log("Event Service Type: 0x" + datagram.service_type.toString('hex'));
console.log("Event Total Length: " + datagram.total_length);
console.log("Event Message Code: " + datagram.message_code);
console.log("Event Aditional Info Length: " + datagram.additional_info_length);
if (datagram.additional_info_length > 0)
console.log("Event Aditional Info: 0x" + datagram.additional_info.toString('hex'));
console.log("Event Control Field 1: " + datagram.control_field_1);
console.log("Event Control Field 2: " + datagram.control_field_2);
console.log("Event Source Address: " + datagram.source_address);
console.log("Event Destination Address: " + datagram.destination_address);
console.log("Event Data Length: " + datagram.data_length);
console.log("Event APDU: 0x" + datagram.apdu.toString('hex'));
console.log("Event Data: " + datagram.data.toString('hex'));
console.log("-----------------------------------------------------------------------------------------------------");
}
if (datagram.message_code != 0x29)
return;
var type = datagram.apdu[1] >> 4;
switch (type) {
case 8:
this.connection.emit('event', datagram.destination_address, datagram.data, datagram);
this.connection.emit('event.' + datagram.destination_address.toString(), datagram.destination_address, datagram.data, datagram);
break;
case 4:
this.connection.emit('status', datagram.destination_address, datagram.data, datagram);
this.connection.emit('status.' + datagram.destination_address.toString(), datagram.destination_address, datagram.data, datagram);
break;
default:
console.log('Unknown type[' + type + '] received in datagram[' + datagram.data.toString('hex') + ']');
break;
}
}
catch (e) {
// ignore, missing warning information
}
}
module.exports = KnxReceiver;