common/Hardware/Common.Hardware.Ports/SerialPortExtensions.cs
2026-04-23 17:50:07 +02:00

440 lines
12 KiB
C#

namespace Common.Hardware.Ports
{
using System;
public static partial class SerialPortExtensions
{
public const Byte UNIPRO_START = 0x53;
public const Byte UNIPRO_PC2REG = 0x57;
public const Byte UNIPRO_REG2PC = 0x52;
public const Byte UNIPRO_STOP = 0x0D;
public const Byte UNIPRO_MIN_LENGTH = 4;
/// <summary>
/// <para>UniPro structure:</para>
/// <para> 0. .... - Start Byte</para>
/// <para> 1. .... - Direction</para>
/// <para> 2. .... - Length</para>
/// <para> .. .... - Payload</para>
/// <para>n-1. .... - Stop Byte</para>
/// </summary>
public static Boolean TryParseToUniPro(this Byte[] data, out Byte[] bytes)
{
if (data is null)
{
data = new Byte[0];
}
var dataLength = data.Length;
var bytesLength = dataLength + UNIPRO_MIN_LENGTH;
bytes = new Byte[bytesLength];
bytes[0] = UNIPRO_START;
bytes[1] = UNIPRO_PC2REG;
bytes[2] = (Byte)bytesLength;
bytes[bytesLength - 1] = UNIPRO_STOP;
Array.Copy(data, 0, bytes, 3, dataLength);
return true;
}
/// <summary>
/// <para>UniPro structure:</para>
/// <para> 0. .... - Start Byte</para>
/// <para> 1. .... - Direction</para>
/// <para> 2. .... - Length</para>
/// <para> .. .... - Payload</para>
/// <para>n-1. .... - Stop Byte</para>
/// </summary>
public static Boolean TryParseFromUniPro(this Byte[] bytes, out Byte[] data)
{
data = new Byte[0];
if (bytes is null)
{
return false;
}
var start = Array.IndexOf(bytes, UNIPRO_START);
if (start < 0)
{
return false;
}
var direction = Array.IndexOf(bytes, UNIPRO_REG2PC, start + 1);
if (direction < 0)
{
return false;
}
var bytesLength = bytes.Length;
var lengthIndex = direction + 1;
if (lengthIndex >= bytesLength)
{
return false;
}
var dataIndex = lengthIndex + 1;
if (dataIndex >= bytesLength)
{
return false;
}
var dataLength = bytes[lengthIndex] - UNIPRO_MIN_LENGTH;
if (dataLength < 0 || dataIndex + dataLength > bytesLength)
{
return false;
}
data = new Byte[dataLength];
Array.Copy(bytes, dataIndex, data, 0, dataLength);
return true;
}
public const Byte IRDA_START = 0x9B;
public const Byte IRDA_PING = 0x82;
public const Byte IRDA_PC2REG = 0x33;
public const Byte IRDA_REG2PC = 0x43;
public const Byte IRDA_LEN_INDEX = 2;
public const Byte IRDA_DATA_INDEX = 3;
public const Byte IRDA_MIN_LENGTH = 5;
/// <summary>
/// <para>Irda structure:</para>
/// <para> 0. .... - Start Byte</para>
/// <para> 1. .... - Direction</para>
/// <para> 2. .... - Length / 2</para>
/// <para>3+n. .... - Payload</para>
/// <para>n-3. .... - aligned Byte</para>
/// <para>n-2. .... - CRC16 0 </para>
/// <para>n-1. .... - CRC16 1 </para>
/// </summary>
public static Boolean TryParseToIrda(this Byte[] data, out Byte[] bytes)
{
bytes = new Byte[0];
if (data is null)
{
data = new Byte[0];
}
var offset = data.Length % 2;
var dataLength = data.Length + offset;
var bytesLength = dataLength + IRDA_MIN_LENGTH;
bytes = new Byte[bytesLength];
bytes[0] = IRDA_START;
bytes[1] = IRDA_PC2REG;
bytes[2] = (Byte)(dataLength / 2);
Array.Copy(data, 0, bytes, 3, data.Length);
var crc = bytes.CalculateCRC8408(1, bytesLength - 2);
bytes[bytesLength - 2] = crc[0];
bytes[bytesLength - 1] = crc[1];
return true;
}
/// <summary>
/// <para>Irda structure:</para>
/// <para> 0. .... - Start Byte</para>
/// <para> 1. .... - Direction</para>
/// <para> 2. .... - Length / 2</para>
/// <para>3+n. .... - Payload</para>
/// <para>n-3. .... - aligned Byte</para>
/// <para>n-2. .... - CRC16 0 </para>
/// <para>n-1. .... - CRC16 1 </para>
/// </summary>
public static Boolean TryParseFromIrda(this Byte[] bytes, out Byte[] data)
{
data = new Byte[0];
if (bytes is null)
{
return false;
}
var bytesLength = bytes.Length;
var directionIX = -1;
var startIX = 0;
while (bytesLength > startIX)
{
startIX = Array.IndexOf(bytes, IRDA_START, startIX);
if (startIX < 0)
{
break;
}
directionIX = Array.IndexOf(bytes, IRDA_REG2PC, ++startIX);
if (directionIX > 0)
{
break;
}
else
{
directionIX = Array.IndexOf(bytes, (Byte)0x82, startIX++);
if (directionIX >= 0)
{
directionIX = -1;
}
}
}
if (startIX < 0)
{
return false;
}
var lengthIndex = directionIX + 1;
if (lengthIndex >= bytesLength)
{
return false;
}
var dataIndex = lengthIndex + 1;
if (dataIndex >= bytesLength)
{
return false;
}
var dataLength = bytes[lengthIndex] * 2;
if (dataIndex + dataLength > bytesLength)
{
return false;
}
data = new Byte[dataLength];
Array.Copy(bytes, dataIndex, data, 0, dataLength);
return true;
}
public const Byte UI1236_START = 0x0D;
public const Byte UI1236_LEN_INDEX = 1;
public const Byte UI1236_DATA_INDEX = 3;
public const Byte UI1236_MIN_LENGTH = 5;
/// <summary>
/// <para>UI1236 structure:</para>
/// <para> 0. 0x0D - Start Byte</para>
/// <para> 1. .... - Length: max. 254</para>
/// <para> 2. .... - Control Byte</para>
/// <para>3+n. .... - Payload</para>
/// <para>n-2. .... - Checksum 0 </para>
/// <para>n-1. .... - Checksum 1 </para>
/// </summary>
public static Boolean TryParseToUI1236(this Byte[] data, out Byte[] bytes)
{
bytes = new Byte[0];
if (data is null)
{
data = new Byte[0];
}
var dataLength = data.Length;
var bytesLength = dataLength + UI1236_MIN_LENGTH;
bytes = new Byte[bytesLength];
bytes[0] = UI1236_START;
bytes[1] = (Byte)(bytesLength - 2);
UI1236Control control = 0;
control.ReturnResponse = true;
bytes[2] = control;
Array.Copy(data, 0, bytes, 3, dataLength);
var checksum = bytes.CalculateCheckSUM(bytes.Length - 2);
bytes[bytesLength - 2] = checksum[1];
bytes[bytesLength - 1] = checksum[0];
return true;
}
/// <summary>
/// <para>UI1236 structure:</para>
/// <para> 0. 0x0D - Start Byte</para>
/// <para> 1. .... - Length: max. 254</para>
/// <para> 2. .... - Control Byte</para>
/// <para>3+n. .... - Payload</para>
/// <para>n-2. .... - Checksum 0 </para>
/// <para>n-1. .... - Checksum 1 </para>
/// </summary>
public static Boolean TryParseFromUI1236(this Byte[] bytes, out Byte[] data)
{
data = new Byte[0];
if (bytes is null)
{
return false;
}
var start = Array.IndexOf(bytes, UI1236_START);
if (start < 0)
{
return false;
}
var bytesLength = bytes.Length;
var lengthIndex = start + 1;
if (lengthIndex >= bytesLength)
{
return false;
}
var dataIndex = lengthIndex + 2;
if (dataIndex >= bytesLength)
{
return false;
}
var dataLength = bytes[lengthIndex] - 3; // 3 = protocol bytes length (start|control|length)
if (dataIndex + dataLength > bytesLength)
{
return false;
}
data = new Byte[dataLength];
Array.Copy(bytes, dataIndex, data, 0, dataLength);
return true;
}
public static Byte[] CalculateCRC8408(this Byte[] bytes, Int32 start, Int32 length)
{
var crc = 0xFFFF;
while (start < length)
{
crc ^= 0x00FF & bytes[start];
for (var i = 8; i > 0; i--)
{
if ((crc & 0x0001) != 0)
{
crc = (crc >> 1) ^ 0x8408;
}
else
{
crc >>= 1;
}
}
start++;
}
crc = ~crc;
return BitConverter.GetBytes((UInt16)crc);
}
public static Byte[] CalculateCheckSUM(this Byte[] bytes, Int32 length)
{
UInt16 checksum = 0;
for (var i = 0; i < length; i++)
{
checksum += bytes[i];
}
return BitConverter.GetBytes(checksum);
}
public static Byte[] CalculateCRC16(this Byte[] data, Int32 start, Int32 length)
{
var dataLength = data.Length;
var maxLength = start + length;
var crc = (UInt16)0xFFFF;
Byte test;
Byte current;
if (data.Length > maxLength)
{
while (start < maxLength)
{
current = data[start];
for (Byte h = 0; h < 8; h++)
{
test = 0;
if ((crc & 0x8000) != 0)
{
test = 0x80;
}
crc <<= 1;
if (((current & 0x80) ^ test) != 0)
{
crc ^= 0x1021;
}
current <<= 1;
}
start++;
}
}
return BitConverter.GetBytes(crc);
}
public static Byte[] CalculateCRC1021(this Byte[] bytes, Int32 start, Int32 length)
{
UInt16 crcSum = 0xFFFF;
while (start < length)
{
var @byte = bytes[start];
for (int bit = 0; bit < 8; bit++)
{
var test = default(Byte);
if ((crcSum & 0x8000) != 0)
{
test = 0x80;
}
crcSum <<= 1;
if (((@byte & 0x80) ^ test) != 0)
{
crcSum ^= 0x1021;
}
@byte <<= 1;
}
start++;
}
return BitConverter.GetBytes(crcSum);
}
}
}