private void ProcessConnectResponse(byte[] datagram) { // HEADER var knxDatagram = new KnxDatagram { header_length = datagram[0], protocol_version = datagram[1], service_type = new[] { datagram[2], datagram[3] }, total_length = datagram[4] + datagram[5], channel_id = datagram[6], status = datagram[7] }; if (knxDatagram.channel_id == 0x00 && knxDatagram.status == 0x24) { Logger.Info(ClassName, "KNXLib received connect response - No more connections available"); } else { KnxConnectionTunneling.ChannelId = knxDatagram.channel_id; KnxConnectionTunneling.ResetSequenceNumber(); KnxConnectionTunneling.Connected(); } }
private void ProcessDatagramHeaders(byte[] datagram) { // HEADER var knxDatagram = new KnxDatagram { header_length = datagram[0], protocol_version = datagram[1], service_type = new[] { datagram[2], datagram[3] }, total_length = datagram[4] + datagram[5] }; var cemi = new byte[datagram.Length - 6]; Array.Copy(datagram, 6, cemi, 0, datagram.Length - 6); ProcessCEMI(knxDatagram, cemi); }
private void ProcessDatagramHeaders(byte[] datagram) { // HEADER // TODO: Might be interesting to take out these magic numbers for the datagram indices var knxDatagram = new KnxDatagram { header_length = datagram[0], protocol_version = datagram[1], service_type = new[] { datagram[2], datagram[3] }, total_length = datagram[4] + datagram[5] }; var channelId = datagram[7]; if (channelId != KnxConnectionTunneling.ChannelId) { return; } var sequenceNumber = datagram[8]; var process = true; lock (_rxSequenceNumberLock) { if (sequenceNumber <= _rxSequenceNumber) { process = false; } _rxSequenceNumber = sequenceNumber; } if (process) { // TODO: Magic number 10, what is it? var cemi = new byte[datagram.Length - 10]; Array.Copy(datagram, 10, cemi, 0, datagram.Length - 10); ProcessCEMI(knxDatagram, cemi); } ((KnxSenderTunneling)KnxConnectionTunneling.KnxSender).SendTunnelingAck(sequenceNumber); }
private void ProcessConnectionStateResponse(byte[] datagram) { // HEADER // 06 10 02 08 00 08 -- 48 21 var knxDatagram = new KnxDatagram { header_length = datagram[0], protocol_version = datagram[1], service_type = new[] { datagram[2], datagram[3] }, total_length = datagram[4] + datagram[5], channel_id = datagram[6] }; var response = datagram[7]; if (response != 0x21) { return; } Logger.Debug(ClassName, "Received connection state response - No active connection with channel ID {0}", knxDatagram.channel_id); KnxConnection.Disconnect(); }
private void ProcessDatagramHeaders(byte[] datagram) { // HEADER // TODO: Might be interesting to take out these magic numbers for the datagram indices var knxDatagram = new KnxDatagram { header_length = datagram[0], protocol_version = datagram[1], service_type = new[] { datagram[2], datagram[3] }, total_length = datagram[4] + datagram[5] }; var channelId = datagram[7]; if (channelId != KnxConnectionTunneling.ChannelId) return; var sequenceNumber = datagram[8]; var process = true; lock (_rxSequenceNumberLock) { if (sequenceNumber <= _rxSequenceNumber) process = false; _rxSequenceNumber = sequenceNumber; } if (process) { // TODO: Magic number 10, what is it? var cemi = new byte[datagram.Length - 10]; Array.Copy(datagram, 10, cemi, 0, datagram.Length - 10); ProcessCEMI(knxDatagram, cemi); } ((KnxSenderTunneling)KnxConnectionTunneling.KnxSender).SendTunnelingAck(sequenceNumber); }
private void ProcessConnectResponse(byte[] datagram) { // HEADER var knxDatagram = new KnxDatagram { header_length = datagram[0], protocol_version = datagram[1], service_type = new[] { datagram[2], datagram[3] }, total_length = datagram[4] + datagram[5], channel_id = datagram[6], status = datagram[7] }; if (knxDatagram.channel_id == 0x00 && knxDatagram.status == 0x24) { if (KnxConnection.Debug) Console.WriteLine("KnxReceiverTunneling: Received connect response - No more connections available"); } else { KnxConnectionTunneling.ChannelId = knxDatagram.channel_id; KnxConnectionTunneling.ResetSequenceNumber(); KnxConnectionTunneling.Connected(); } }
private void ProcessConnectionStateResponse(byte[] datagram) { // HEADER // 06 10 02 08 00 08 -- 48 21 var knxDatagram = new KnxDatagram { header_length = datagram[0], protocol_version = datagram[1], service_type = new[] { datagram[2], datagram[3] }, total_length = datagram[4] + datagram[5], channel_id = datagram[6] }; var response = datagram[7]; if (response != 0x21) return; if (KnxConnection.Debug) Console.WriteLine("KnxReceiverTunneling: Received connection state response - No active connection with channel ID {0}", knxDatagram.channel_id); KnxConnection.Disconnect(); }
protected void ProcessCEMI(KnxDatagram datagram, byte[] 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.aditional_info_length = cemi[1]; if (datagram.aditional_info_length > 0) { datagram.aditional_info = new byte[datagram.aditional_info_length]; for (var i = 0; i < datagram.aditional_info_length; i++) { datagram.aditional_info[i] = cemi[2 + i]; } } datagram.control_field_1 = cemi[2 + datagram.aditional_info_length]; datagram.control_field_2 = cemi[3 + datagram.aditional_info_length]; datagram.source_address = KnxHelper.GetIndividualAddress(new[] { cemi[4 + datagram.aditional_info_length], cemi[5 + datagram.aditional_info_length] }); datagram.destination_address = KnxHelper.GetKnxDestinationAddressType(datagram.control_field_2).Equals(KnxHelper.KnxDestinationAddressType.INDIVIDUAL) ? KnxHelper.GetIndividualAddress(new[] { cemi[6 + datagram.aditional_info_length], cemi[7 + datagram.aditional_info_length] }) : KnxHelper.GetGroupAddress(new[] { cemi[6 + datagram.aditional_info_length], cemi[7 + datagram.aditional_info_length] }, KnxConnection.ThreeLevelGroupAddressing); datagram.data_length = cemi[8 + datagram.aditional_info_length]; datagram.apdu = new byte[datagram.data_length + 1]; for (var i = 0; i < datagram.apdu.Length; i++) { datagram.apdu[i] = cemi[9 + i + datagram.aditional_info_length]; } datagram.data = KnxHelper.GetData(datagram.data_length, datagram.apdu); if (KnxConnection.Debug) { Logger.Debug(ClassName, "-----------------------------------------------------------------------------------------------------"); Logger.Debug(ClassName, BitConverter.ToString(cemi)); Logger.Debug(ClassName, "Event Header Length: " + datagram.header_length); Logger.Debug(ClassName, "Event Protocol Version: " + datagram.protocol_version.ToString("x")); Logger.Debug(ClassName, "Event Service Type: 0x" + BitConverter.ToString(datagram.service_type).Replace("-", string.Empty)); Logger.Debug(ClassName, "Event Total Length: " + datagram.total_length); Logger.Debug(ClassName, "Event Message Code: " + datagram.message_code.ToString("x")); Logger.Debug(ClassName, "Event Aditional Info Length: " + datagram.aditional_info_length); if (datagram.aditional_info_length > 0) { Logger.Debug(ClassName, "Event Aditional Info: 0x" + BitConverter.ToString(datagram.aditional_info).Replace("-", string.Empty)); } Logger.Debug(ClassName, "Event Control Field 1: " + Convert.ToString(datagram.control_field_1, 2)); Logger.Debug(ClassName, "Event Control Field 2: " + Convert.ToString(datagram.control_field_2, 2)); Logger.Debug(ClassName, "Event Source Address: " + datagram.source_address); Logger.Debug(ClassName, "Event Destination Address: " + datagram.destination_address); Logger.Debug(ClassName, "Event Data Length: " + datagram.data_length); Logger.Debug(ClassName, "Event APDU: 0x" + BitConverter.ToString(datagram.apdu).Replace("-", string.Empty)); Logger.Debug(ClassName, "Event Data: 0x" + string.Join("", datagram.data.Select(c => ((int)c).ToString("X2")))); Logger.Debug(ClassName, "-----------------------------------------------------------------------------------------------------"); } if (datagram.message_code != 0x29) { return; } var type = datagram.apdu[1] >> 4; switch (type) { case 8: _rxDatagrams.Add(datagram); break; case 4: KnxConnection.Status(datagram.destination_address, datagram.data); break; } } catch (Exception e) { Logger.Error(ClassName, e); } }
protected void ProcessCEMI(KnxDatagram datagram, byte[] 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.aditional_info_length = cemi[1]; if (datagram.aditional_info_length > 0) { datagram.aditional_info = new byte[datagram.aditional_info_length]; for (var i = 0; i < datagram.aditional_info_length; i++) { datagram.aditional_info[i] = cemi[2 + i]; } } datagram.control_field_1 = cemi[2 + datagram.aditional_info_length]; datagram.control_field_2 = cemi[3 + datagram.aditional_info_length]; datagram.source_address = KnxHelper.GetIndividualAddress(new[] { cemi[4 + datagram.aditional_info_length], cemi[5 + datagram.aditional_info_length] }); datagram.destination_address = KnxHelper.GetKnxDestinationAddressType(datagram.control_field_2).Equals(KnxHelper.KnxDestinationAddressType.INDIVIDUAL) ? KnxHelper.GetIndividualAddress(new[] { cemi[6 + datagram.aditional_info_length], cemi[7 + datagram.aditional_info_length] }) : KnxHelper.GetGroupAddress(new[] { cemi[6 + datagram.aditional_info_length], cemi[7 + datagram.aditional_info_length] }, KnxConnection.ThreeLevelGroupAddressing); datagram.data_length = cemi[8 + datagram.aditional_info_length]; datagram.apdu = new byte[datagram.data_length + 1]; for (var i = 0; i < datagram.apdu.Length; i++) datagram.apdu[i] = cemi[9 + i + datagram.aditional_info_length]; datagram.data = KnxHelper.GetData(datagram.data_length, datagram.apdu); if (KnxConnection.Debug) { Console.WriteLine("-----------------------------------------------------------------------------------------------------"); Console.WriteLine(BitConverter.ToString(cemi)); Console.WriteLine("Event Header Length: " + datagram.header_length); Console.WriteLine("Event Protocol Version: " + datagram.protocol_version.ToString("x")); Console.WriteLine("Event Service Type: 0x" + BitConverter.ToString(datagram.service_type).Replace("-", string.Empty)); Console.WriteLine("Event Total Length: " + datagram.total_length); Console.WriteLine("Event Message Code: " + datagram.message_code.ToString("x")); Console.WriteLine("Event Aditional Info Length: " + datagram.aditional_info_length); if (datagram.aditional_info_length > 0) Console.WriteLine("Event Aditional Info: 0x" + BitConverter.ToString(datagram.aditional_info).Replace("-", string.Empty)); Console.WriteLine("Event Control Field 1: " + Convert.ToString(datagram.control_field_1, 2)); Console.WriteLine("Event Control Field 2: " + Convert.ToString(datagram.control_field_2, 2)); Console.WriteLine("Event Source Address: " + datagram.source_address); Console.WriteLine("Event Destination Address: " + datagram.destination_address); Console.WriteLine("Event Data Length: " + datagram.data_length); Console.WriteLine("Event APDU: 0x" + BitConverter.ToString(datagram.apdu).Replace("-", string.Empty)); Console.WriteLine("Event Data: " + datagram.data); Console.WriteLine("-----------------------------------------------------------------------------------------------------"); } if (datagram.message_code != 0x29) return; var type = datagram.apdu[1] >> 4; switch (type) { case 8: KnxConnection.Event(datagram.destination_address, datagram.data); break; case 4: KnxConnection.Status(datagram.destination_address, datagram.data); break; } } catch { // ignore, missing warning information } }