예제 #1
0
        public static KnxNetTunnelingDatagram FromBytes(byte[] datagram)
        {
            if ((datagram == null) || (datagram.Length < 8))
            {
                Debug.WriteLine("Received parial datagram " + BitConverter.ToString(datagram));
                return(null);
            }

            if (datagram[4] + datagram[5] != datagram.Length)
            {
                Debug.WriteLine("Datagram length validaton failed " + BitConverter.ToString(datagram));
                return(null);
            }

            var header = new KnxNetTunnelingDatagram()
            {
                header_length    = datagram[0],
                protocol_version = datagram[1],
                service_type     = (ushort)((datagram[2] << 8) + datagram[3]),
                total_length     = datagram[4] + datagram[5],
                channel_id       = datagram[6],
                status           = datagram[7]
            };

            if (datagram.Length >= 10)
            {
                header.sequence_number = datagram[8];

                header.data = new byte[datagram.Length - 10];
                Array.Copy(datagram, 10, header.data, 0, header.data.Length);
            }

            return(header);
        }
예제 #2
0
        private void UdpClientDataReceived(object sender, Spark.Universal.Net.DataReceivedEventArgs e)
        {
            // parse datagram
            byte[] datagram = e.Data;
            var    tt       = KnxNetTunnelingDatagram.FromBytes(e.Data);

            switch (tt.service_type)
            {
            case (ushort)KnxHelper.SERVICE_TYPE.CONNECT_RESPONSE:
                this.ProcessConnectResponse(datagram);
                break;

            case (ushort)KnxHelper.SERVICE_TYPE.CONNECTIONSTATE_RESPONSE:
                this.ProcessStateResponse(datagram);
                break;

            case (ushort)KnxHelper.SERVICE_TYPE.TUNNELLING_ACK:
                this.ProcessTunnelingAck(datagram);
                break;

            case (ushort)KnxHelper.SERVICE_TYPE.DISCONNECT_REQUEST:
                this.ProcessDisconnectRequest(datagram);
                break;

            case (ushort)KnxHelper.SERVICE_TYPE.TUNNELLING_REQUEST:
                ProcessDatagramHeaders(datagram);
                break;
            }
        }
예제 #3
0
        private void ProcessDatagramHeaders(byte[] datagram)
        {
            // HEADER
            // TODO: Might be interesting to take out these magic numbers for the datagram indices
            var knxDatagram = new KnxNetTunnelingDatagram
            {
                header_length    = datagram[0],
                protocol_version = datagram[1],
                service_type     = (ushort)((datagram[2] << 8) + datagram[3]),
                total_length     = datagram[4] + datagram[5]
            };

            var channelId = datagram[7];

            if (channelId != _channelId)
            {
                return;
            }

            var sequenceNumber = datagram[8];
            var process        = sequenceNumber > _rxSequenceNo;

            _rxSequenceNo = sequenceNumber;

            if (process)
            {
                // TODO: Magic number 10, what is it?
                var cemiBytes = new byte[datagram.Length - 10];
                Array.Copy(datagram, 10, cemiBytes, 0, datagram.Length - 10);

                var knxCEMI = KnxCEMI.FromBytes(_threeLevelGroupAssigning, cemiBytes);
                if (knxCEMI.IsEvent)
                {
                    Debug.WriteLine("KNX Event " + knxCEMI.destination_address + "  " + BitConverter.ToString(knxCEMI.apdu));

                    this.KnxEvent?.Invoke(this, new KnxEventArgs()
                    {
                        Address = knxCEMI.destination_address,
                        Data    = knxCEMI.apdu
                    });
                }
                else if (knxCEMI.IsStatus)
                {
                    Debug.WriteLine("KNX Status " + knxCEMI.destination_address + "  " + BitConverter.ToString(knxCEMI.apdu));

                    this.KnxStatus?.Invoke(this, new KnxEventArgs()
                    {
                        Address = knxCEMI.destination_address,
                        Data    = knxCEMI.apdu
                    });
                }
            }

            this.SendTunnelingAck(sequenceNumber);
        }
예제 #4
0
        private void ProcessStateResponse(byte[] datagram)
        {
            var knxDatagram = KnxNetTunnelingDatagram.FromBytes(datagram);

            if (knxDatagram == null)
            {
                return;
            }

            if (knxDatagram.status != 0x21)
            {
                return;                             /* TODO: status should be 0 */
            }
            this.Disconnect();
        }
예제 #5
0
        private void ProcessDisconnectRequest(byte[] datagram)
        {
            var knxDatagram = KnxNetTunnelingDatagram.FromBytes(datagram);

            if (knxDatagram == null)
            {
                return;
            }

            if (knxDatagram.channel_id != _channelId)
            {
                return;
            }

            this.Disconnected?.Invoke(this, EventArgs.Empty);
        }
예제 #6
0
        private void ProcessConnectResponse(byte[] datagram)
        {
            // HEADER
            var knxDatagram = KnxNetTunnelingDatagram.FromBytes(datagram);

            if (knxDatagram == null)
            {
                return;
            }

            if (knxDatagram.channel_id == 0x00 && knxDatagram.status == 0x24) /* TODO: status should be 0 */
            {
                // no more connections available
                return;
            }

            _channelId  = knxDatagram.channel_id;
            _sequenceNo = 0;

            this.Connected?.Invoke(this, EventArgs.Empty);
        }