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;
///
/// UniPro structure:
/// 0. .... - Start Byte
/// 1. .... - Direction
/// 2. .... - Length
/// .. .... - Payload
/// n-1. .... - Stop Byte
///
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;
}
///
/// UniPro structure:
/// 0. .... - Start Byte
/// 1. .... - Direction
/// 2. .... - Length
/// .. .... - Payload
/// n-1. .... - Stop Byte
///
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;
///
/// Irda structure:
/// 0. .... - Start Byte
/// 1. .... - Direction
/// 2. .... - Length / 2
/// 3+n. .... - Payload
/// n-3. .... - aligned Byte
/// n-2. .... - CRC16 0
/// n-1. .... - CRC16 1
///
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;
}
///
/// Irda structure:
/// 0. .... - Start Byte
/// 1. .... - Direction
/// 2. .... - Length / 2
/// 3+n. .... - Payload
/// n-3. .... - aligned Byte
/// n-2. .... - CRC16 0
/// n-1. .... - CRC16 1
///
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;
///
/// UI1236 structure:
/// 0. 0x0D - Start Byte
/// 1. .... - Length: max. 254
/// 2. .... - Control Byte
/// 3+n. .... - Payload
/// n-2. .... - Checksum 0
/// n-1. .... - Checksum 1
///
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;
}
///
/// UI1236 structure:
/// 0. 0x0D - Start Byte
/// 1. .... - Length: max. 254
/// 2. .... - Control Byte
/// 3+n. .... - Payload
/// n-2. .... - Checksum 0
/// n-1. .... - Checksum 1
///
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);
}
}
}