private void ProcessDatagramHeaders(byte[] datagram)
        {
            // HEADER
            // TODO: Might be interesting to take out these magic numbers for the datagram indices
            var knxDatagram = new KnxDatagram
            {
                HeaderLength    = datagram[0],
                ProtocolVersion = datagram[1],
                ServiceType     = new[] { datagram[2], datagram[3] },
                TotalLength     = datagram[4] + datagram[5]
            };

            var channelId = datagram[7];

            if (channelId != ChannelId)
            {
                return;
            }

            var sequenceNumber = datagram[8];
            var process        = true;

            lock (SequenceNumberLock)
            {
                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);

                switch (DatagramProcessing.ProcessCEMI(ref knxDatagram, cemi, ThreeLevelGroupAddressing, IsDebug))
                {
                case ResponseType.Event:
                    base.EventReceived(knxDatagram.DestinationAddress, knxDatagram.Data);
                    break;

                case ResponseType.Status:
                    base.StatusReceived(knxDatagram.DestinationAddress, knxDatagram.Data);
                    break;
                }
            }

            SendTunnelingAck(sequenceNumber);
        }
        private void ProcessConnectionStateResponse(byte[] datagram)
        {
            // HEADER
            // 06 10 02 08 00 08 -- 48 21
            var knxDatagram = new KnxDatagram
            {
                HeaderLength = datagram[0],
                ProtocolVersion = datagram[1],
                ServiceType = new[] { datagram[2], datagram[3] },
                TotalLength = datagram[4] + datagram[5],
                ChannelID = datagram[6]
            };

            var response = datagram[7];

            if (response != 0x21)
                return;

            if (IsDebug)
                System.Diagnostics.Debug.WriteLine("KnxReceiverTunneling: Received connection state response - No active connection with channel ID {0}", knxDatagram.ChannelID);

            Disconnect();
        }
        private void ProcessConnectResponse(byte[] datagram)
        {
            // HEADER
            var knxDatagram = new KnxDatagram
            {
                HeaderLength = datagram[0],
                ProtocolVersion = datagram[1],
                ServiceType = new[] { datagram[2], datagram[3] },
                TotalLength = datagram[4] + datagram[5],
                ChannelID = datagram[6],
                Status = datagram[7]
            };

            if (knxDatagram.ChannelID == 0x00 && knxDatagram.Status == 0x24)
            {
                if (IsDebug)
                    System.Diagnostics.Debug.WriteLine("KnxReceiverTunneling: Received connect response - No more connections available");
            }
            else
            {
                ChannelId = knxDatagram.ChannelID;
                ResetSequenceNumber();

                InitializeStateRequest();
                base.Connected();
            }
        }
        private void ProcessDatagramHeaders(byte[] datagram)
        {
            // HEADER
            // TODO: Might be interesting to take out these magic numbers for the datagram indices
            var knxDatagram = new KnxDatagram
            {
                HeaderLength = datagram[0],
                ProtocolVersion = datagram[1],
                ServiceType = new[] { datagram[2], datagram[3] },
                TotalLength = datagram[4] + datagram[5]
            };

            var channelId = datagram[7];
            if (channelId != ChannelId)
                return;

            var sequenceNumber = datagram[8];
            var process = true;
            lock (SequenceNumberLock)
            {
                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);

                switch(DatagramProcessing.ProcessCEMI(ref knxDatagram, cemi, ThreeLevelGroupAddressing, IsDebug))
                {
                    case ResponseType.Event:
                        base.EventReceived(knxDatagram.DestinationAddress, knxDatagram.Data);
                        break;
                    case ResponseType.Status:
                        base.StatusReceived(knxDatagram.DestinationAddress, knxDatagram.Data);
                        break;
                }
            }

            SendTunnelingAck(sequenceNumber);
        }