public static KnxCEMI FromBytes(bool threeLevelGroupAssigning, byte[] cemiBytes) { var cemi = new KnxCEMI(); cemi.message_code = cemiBytes[0]; cemi.aditional_info_length = cemiBytes[1]; if (cemi.aditional_info_length > 0) { cemi.aditional_info = new byte[cemi.aditional_info_length]; Array.Copy(cemiBytes, 2, cemi.aditional_info, 0, cemi.aditional_info_length); } cemi.control_field_1 = cemiBytes[2 + cemi.aditional_info_length]; cemi.control_field_2 = cemiBytes[3 + cemi.aditional_info_length]; cemi.source_address = KnxHelper.GetIndividualAddress(new[] { cemiBytes[4 + cemi.aditional_info_length], cemiBytes[5 + cemi.aditional_info_length] }); cemi.destination_address = KnxHelper.GetKnxDestinationAddressType(cemi.control_field_2).Equals(KnxHelper.KnxDestinationAddressType.INDIVIDUAL) ? KnxHelper.GetIndividualAddress(new[] { cemiBytes[6 + cemi.aditional_info_length], cemiBytes[7 + cemi.aditional_info_length] }) : KnxHelper.GetGroupAddress(new[] { cemiBytes[6 + cemi.aditional_info_length], cemiBytes[7 + cemi.aditional_info_length] }, threeLevelGroupAssigning); var data_length = Math.Min(cemiBytes[8 + cemi.aditional_info_length], cemiBytes.Length - 10); // AR if (data_length > 0) { cemi.apdu = new byte[data_length]; Array.Copy(cemiBytes, 10 + cemi.aditional_info_length, cemi.apdu, 0, data_length); } return(cemi); }
/// <summary> /// Send a byte array value as data to specified address /// </summary> /// <param name="address">KNX Address</param> /// <param name="data">Byte array value</param> public async void Action(string address, string type, object value) { byte[] asdu = DataPointTranslator.Instance.ToASDU(type, value); var cemi = KnxCEMI.CreateActionCEMI(_messageCode, address, asdu); var cemiBytes = cemi.ToBytes(); // header var header = new byte[10]; header[00] = 0x06; /* 06 - Header Length */ header[01] = 0x10; /* 10 - KNXnet version (1.0) */ header[02] = 0x04; /* 04 - hi-byte Service type descriptor (TUNNELLING_REQUEST) */ header[03] = 0x20; /* 20 - lo-byte Service type descriptor (TUNNELLING_REQUEST) */ var totalLength = BitConverter.GetBytes(header.Length + cemiBytes.Length); header[04] = totalLength[1]; header[05] = totalLength[0]; /* Connection Header (4 Bytes) */ header[06] = 0x04; /* 04 - Structure length */ header[07] = _channelId; header[08] = _sequenceNo++; header[09] = 0x00; /* 00 - Reserved */ var datagram = new byte[header.Length + cemiBytes.Length]; Array.Copy(header, datagram, header.Length); Array.Copy(cemiBytes, 0, datagram, header.Length, cemiBytes.Length); await _udpClient?.Send(datagram); }
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); }
public static KnxCEMI CreateStatusCEMI(byte messageCode, string destinationAddress) { KnxCEMI cemi = new KnxCEMI() { message_code = messageCode != 0x00 ? messageCode : (byte)0x11, aditional_info_length = 0, control_field_1 = 0xAC, control_field_2 = KnxHelper.IsAddressIndividual(destinationAddress) ? (byte)0x50 : (byte)0xF0, destination_address = destinationAddress, apdu = new byte[] { 0x00 }, _isstatus = true }; return(cemi); }
public static KnxCEMI CreateActionCEMI(byte messageCode, string destinationAddress, byte[] asdu) { KnxCEMI cemi = new KnxCEMI() { message_code = messageCode != 0x00 ? messageCode : (byte)0x11, aditional_info_length = 0, control_field_1 = 0xAC, control_field_2 = KnxHelper.IsAddressIndividual(destinationAddress) ? (byte)0x50 : (byte)0xF0, destination_address = destinationAddress, apdu = new byte[asdu.Length] }; cemi.apdu[0] = (byte)(0x80 | (asdu[0] & 0x3f)); for (var i = 1; i < asdu.Length; i++) { cemi.apdu[i] = asdu[i]; } return(cemi); }