440 lines
12 KiB
C#
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|