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); }
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; } }
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); }
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(); }
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); }
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); }