170 lines
7.4 KiB
C#
170 lines
7.4 KiB
C#
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;
|
|
/// <inheritdoc />
|
|
public override void SetResponseTimeout(Int32 responseTimeoutMs)
|
|
{
|
|
_responseTimeoutMs = responseTimeoutMs;
|
|
}
|
|
/// <inheritdoc />
|
|
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<Byte> DecodeDataForLogicLayer(String ident, List<Byte> 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<Byte>();
|
|
}
|
|
|
|
//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<Byte>();
|
|
}
|
|
|
|
//the request protocol needs the requestProtocolCommand and the requestProtocolPayload
|
|
var ret = new List<Byte> {uartRecord[UartCommandIndex]};
|
|
//add the requestProtocolCommand
|
|
//add the request protocol payload
|
|
ret.AddRange(uartRecord.GetRange(UartPayloadIndex, uartRecord.Count - UartProtocolFrameLength));
|
|
return ret;
|
|
}
|
|
|
|
public virtual List<Byte> SpecificCrcCalc()
|
|
{
|
|
//for the pure UART transmit protocol the CRC fields will be set
|
|
//to 0x00 and used for the CRC calculation
|
|
return new List<Byte>() { 0x00, 0x00 };
|
|
}
|
|
public UInt16 CrcCalc(List<Byte> header, List<Byte> payload)
|
|
{
|
|
//the CRC calculation excludes the syncByte and optional includes the
|
|
//CRC fields filled up with 0x00
|
|
var tmpArr = new List<Byte>();
|
|
tmpArr.AddRange(header);
|
|
|
|
//this adds the optional CRC fields
|
|
tmpArr.AddRange(SpecificCrcCalc());
|
|
tmpArr.AddRange(payload);
|
|
|
|
return Crc16Ccitt.CalculateMsb1021(tmpArr.ToArray());
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override List<Byte> DecodeDataForPhysicalLayer(String ident, Byte requestProtocolCommand,
|
|
Byte[] requestProtocolPayload, Boolean hideDataInLog = false)
|
|
{
|
|
var uartHeader = new List<Byte>();
|
|
var uartPayload = requestProtocolPayload.ToList();
|
|
var uartRecord = new List<Byte>();
|
|
|
|
//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;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
/// <remarks date="2022-Aug-24" author="R.Drabesch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
public override List<Byte> DecodeDataForPhysicalLayerUI1236(String ident, Byte[] requestProtocolPayload,
|
|
Boolean hideDataInLog = false)
|
|
{
|
|
var uartHeader = new List<Byte>();
|
|
var uartPayload = requestProtocolPayload.ToList();
|
|
var uartRecord = new List<Byte>();
|
|
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;
|
|
}
|
|
}
|
|
}
|