using System; using System.Collections.Generic; using System.Linq; using Xylem.Common.Hardware.Interfaces.Ports.PortCore; using Xylem.Common.Utils.Crc16Ccitt; namespace Xylem.Common.Hardware.Interfaces.Protocols.TransmitProtocol { public class UartTransmitProtocol : BaseTransmitProtocol { // Format of UART transmit protocol: // UartSyncByte|UartLength LSB|UartLength MSB|requestProtocolCommand| // NextRequestProtocolCommand|UartCrc LSB|UartCrc MSB|requestProtocolPayload // UartLength MSB will NOT be used, it is always 0x00 // NextRequestProtocolCommand will NOT be used, it is always 0x00 //Indexes of UART transmit protocol private const Int32 UartSyncByteIndex = 0; private const Int32 UartLengthIndex = 1; private const Int32 UartCommandIndex = 3; private const Int32 UartCrcIndex = 5; private const Int32 UartPayloadIndex = 7; //length of UART transmit protocol fields private const Int32 UartSyncByteLength = 1; //length of syncByte private const Int32 UartHeaderLength = 4; //length excluding syncByte and CRC private const Int32 UartCrcLength = 2; private const Int32 UartProtocolFrameLength = UartSyncByteLength + UartHeaderLength + UartCrcLength; private const Byte UartSyncByte = 0x5B; //The UART length covers all bytes excluding the syncByte length private const Int32 DefaultResponseTimeoutMs = 50; private Int32 _responseTimeoutMs = DefaultResponseTimeoutMs; private const UInt16 ProtAddLength = UartSyncByteLength; private const UInt32 BaudRate = 9600; private readonly UInt32? _receiveBufferFlushThreshold = null; private const Boolean UartDoubleSyncByte = true; /// public override void SetResponseTimeout(Int32 responseTimeoutMs) { _responseTimeoutMs = responseTimeoutMs; } /// public override void SetDefaultResponseTimeout() { _responseTimeoutMs = DefaultResponseTimeoutMs; } public UartTransmitProtocol(String portName) : base (portName) { } public override TransmitPortSettings GetTransmitPortSettings() { return new TransmitPortSettings(UartSyncByte, UartLengthIndex, ProtAddLength, _responseTimeoutMs, BaudRate, _receiveBufferFlushThreshold, UartDoubleSyncByte); } public override List DecodeDataForLogicLayer(String ident, List uartRecord, Boolean hideDataInLog = false) { // check the record length and start of frame information if (uartRecord.Count < uartRecord[UartLengthIndex] + UartSyncByteLength || UartSyncByte != uartRecord[UartSyncByteIndex]) { var error = new ApplicationException($"{ident} Reply from UART is invalid. Decoding of transmit layer failed."); Logger.Error(error.Message, error); return new List(); } //extract the header without syncByte and the payload, call CRC calculation var calculatedCrc = CrcCalc(uartRecord.GetRange(UartLengthIndex, UartHeaderLength), uartRecord.GetRange(UartPayloadIndex, uartRecord.Count - UartProtocolFrameLength)); //extract the received CRC, first the MSB UInt16 receivedCrc = uartRecord[UartCrcIndex + 1]; receivedCrc <<= 8; receivedCrc += uartRecord[UartCrcIndex]; if(receivedCrc != calculatedCrc) { var error = new ApplicationException($"{ident} Reply CRC failure. Decoding of transmit layer failed."); Logger.Error(error.Message, error); return new List(); } //the request protocol needs the requestProtocolCommand and the requestProtocolPayload var ret = new List {uartRecord[UartCommandIndex]}; //add the requestProtocolCommand //add the request protocol payload ret.AddRange(uartRecord.GetRange(UartPayloadIndex, uartRecord.Count - UartProtocolFrameLength)); return ret; } public virtual List SpecificCrcCalc() { //for the pure UART transmit protocol the CRC fields will be set //to 0x00 and used for the CRC calculation return new List() { 0x00, 0x00 }; } public UInt16 CrcCalc(List header, List payload) { //the CRC calculation excludes the syncByte and optional includes the //CRC fields filled up with 0x00 var tmpArr = new List(); tmpArr.AddRange(header); //this adds the optional CRC fields tmpArr.AddRange(SpecificCrcCalc()); tmpArr.AddRange(payload); return Crc16Ccitt.CalculateMsb1021(tmpArr.ToArray()); } /// public override List DecodeDataForPhysicalLayer(String ident, Byte requestProtocolCommand, Byte[] requestProtocolPayload, Boolean hideDataInLog = false) { var uartHeader = new List(); var uartPayload = requestProtocolPayload.ToList(); var uartRecord = new List(); //first assemble the list being used for CRC calculation, //this list does NOT contain the syncByte and optional //the CRC LSB and MSB if set in SpecificCrcCalc() //the length of length LSB and MSB: 2 //add the length of the requestProtocolCommand: 1 //the nextRequestProtocolCommand length: 1 //the length of the CRC MSB and LSB: 2 uartHeader.Add((Byte)(requestProtocolPayload.Length + UartHeaderLength + UartCrcLength)); //add the length MSB, always 0x00 uartHeader.Add(0x00); uartHeader.Add(requestProtocolCommand); //add the nextRequestProtocolCommand, always 0x00 uartHeader.Add(0x00); var crcResult = CrcCalc(uartHeader, uartPayload); //assemble the entire record for sending via the communication port uartRecord.Add(UartSyncByte); uartRecord.AddRange(uartHeader); uartRecord.Add((Byte)(crcResult & 0xFF)); uartRecord.Add((Byte)(crcResult >> 8)); uartRecord.AddRange(uartPayload); return uartRecord; } /// /// /// - Initial /// public override List DecodeDataForPhysicalLayerUI1236(String ident, Byte[] requestProtocolPayload, Boolean hideDataInLog = false) { var uartHeader = new List(); var uartPayload = requestProtocolPayload.ToList(); var uartRecord = new List(); uartHeader.Add((Byte)(requestProtocolPayload.Length + 4 + 2)); uartHeader.Add(0); uartHeader.Add(0); var crcResult = CrcCalc(uartHeader, uartPayload); uartRecord.Add(91); uartRecord.AddRange(uartHeader); uartRecord.Add((Byte)(crcResult & 0xFF)); uartRecord.Add((Byte)(crcResult >> 8)); uartRecord.AddRange(uartPayload); return uartRecord; } } }