227 lines
8.0 KiB
C#
227 lines
8.0 KiB
C#
using System;
|
|
|
|
namespace Xylem.Common.Utils.Crc16Ccitt
|
|
{
|
|
/// <summary>
|
|
/// Class for CRC16 CCITT calculation
|
|
/// </summary>
|
|
public static class Crc16Ccitt
|
|
{
|
|
/// <summary>
|
|
/// Initial CRC value
|
|
/// </summary>
|
|
private const UInt16 CrcSeedFfff = 0xFFFF;
|
|
/// <summary>
|
|
/// Initial CRC value
|
|
/// </summary>
|
|
private const UInt16 CrcSeed3791 = 0x3791;
|
|
|
|
/// <summary>
|
|
/// Generator polynomial MagFlux - Modbus RTU
|
|
/// </summary>
|
|
private const UInt16 CrcGpA001 = 0xA001;
|
|
/// <summary>
|
|
/// Generator polynomial GENESIS
|
|
/// </summary>
|
|
private const UInt16 CrcGp1021 = 0x1021;
|
|
|
|
/// <summary>
|
|
/// Generator polynomial RFID
|
|
/// </summary>
|
|
private const UInt16 CrcGp0408 = 0x0408;
|
|
|
|
/// <summary>
|
|
/// Generator polynomial for reversed IrDA
|
|
/// </summary>
|
|
private const UInt16 CrcGp8408 = 0x8408;
|
|
|
|
/// <summary>
|
|
/// Calculates the CRC (LSB first, reversed, CRC CCITT 0x8408) from a data array of bytes.
|
|
/// </summary>
|
|
/// <param name="data">data to be processed</param>
|
|
/// <returns>Calculated CRC</returns>
|
|
public static UInt16 CalculateReversedLsb8408(Byte[] data)
|
|
{
|
|
var crc = CrcSeedFfff;
|
|
foreach (var t in data)
|
|
{
|
|
//copy data byte to lower word because of LSB will be XORed
|
|
var dataWord = (UInt16)(t & 0x00FF);
|
|
for (var i = 0; i < 8; i++)
|
|
{
|
|
//test if CRC lowest bit is XORed set to one
|
|
if (0x0001 == ((crc ^ dataWord) & 0x0001))
|
|
{
|
|
crc >>= 1;
|
|
//apply generator polynomial
|
|
crc ^= CrcGp8408;
|
|
}
|
|
else
|
|
{
|
|
crc >>= 1;
|
|
}
|
|
|
|
dataWord >>= 1;
|
|
}
|
|
}
|
|
return ((UInt16)~crc);
|
|
}
|
|
/// <summary>
|
|
/// Calculates the bitwise inverted CRC (MSB first, CRCCCITT 0x1021)
|
|
/// from a data array of bytes.
|
|
/// </summary>
|
|
/// <param name="data">data to be processed</param>
|
|
/// <returns>Calculated CRC</returns>
|
|
public static UInt16 CalculateInvertedMsb1021(Byte[] data)
|
|
{
|
|
return (UInt16)~CalculateMsb1021(data);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the Modbus RTU CRC (LSB first, CRCCCITT 0xA001)
|
|
/// from a data array of bytes.
|
|
/// </summary>
|
|
/// <param name="data">data to be processed</param>
|
|
/// <returns>Calculated CRC</returns>
|
|
public static UInt16 ModbusRtuLsbA001(Byte[] data)
|
|
{
|
|
var crc = CrcSeedFfff;
|
|
|
|
for (var t = 0; t < data.Length; t++)
|
|
{
|
|
crc ^= data[t]; // XOR byte into least sig. byte of crc
|
|
|
|
for (var i = 8; i != 0; i--)
|
|
{
|
|
if ((crc & 0x0001) != 0)
|
|
{
|
|
crc >>= 1;
|
|
crc ^= CrcGpA001;
|
|
}
|
|
else
|
|
{
|
|
crc >>= 1;
|
|
}
|
|
}
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the CRC (MSB first, CRCCCITT 0x1021) from a data array of bytes.
|
|
/// <para>18.07.2024 - optional parameters start and length added - for more flexibility by calculating a CRC of a message.</para>
|
|
/// <para>18.07.2024 - length checks: if length less or equal 0 or grater than the data length: the data length is taken as length.</para>
|
|
/// </summary>
|
|
/// <param name="start">optional, default = 0</param>
|
|
/// <param name="length">optional, default = 0</param>
|
|
/// <param name="data">data to be processed</param>
|
|
/// <returns>Calculated CRC</returns>
|
|
public static UInt16 CalculateMsb1021(Byte[] data, Int32 start = 0, Int32 length = 0)
|
|
{
|
|
var dataLength = data.Length;
|
|
|
|
if (length <= 0 || length > dataLength)
|
|
{
|
|
length = dataLength;
|
|
}
|
|
|
|
var crc = CrcSeedFfff;
|
|
|
|
for (var b = start; b < length; b++)
|
|
{
|
|
var t = data[b];
|
|
|
|
//copy data byte to higher word because of MSB will be XORed
|
|
var dataWord = (UInt16)((t << 8) & 0xFF00);
|
|
|
|
for (var i = 0; i < 8; i++)
|
|
{
|
|
//test if CRC highest bit or data input highest bit is XORed set to one
|
|
if (0x8000 == ((crc ^ dataWord) & 0x8000)) //shifted in MSB first
|
|
{
|
|
//shift CRC high bit out
|
|
crc <<= 1;
|
|
//apply generator polynomial
|
|
crc ^= CrcGp1021;
|
|
}
|
|
else //CRC highest bit and data input highest bit is equal
|
|
{
|
|
crc <<= 1;
|
|
}
|
|
dataWord <<= 1; //MSB first shifted out
|
|
}
|
|
}
|
|
//foreach (var t in data)
|
|
//{
|
|
// //copy data byte to higher word because of MSB will be XORed
|
|
// var dataWord = (UInt16)((t << 8) & 0xFF00);
|
|
// for (var i = 0; i < 8; i++)
|
|
// {
|
|
// //test if CRC highest bit or data input highest bit is XORed set to one
|
|
// if (0x8000 == ((crc ^ dataWord) & 0x8000)) //shifted in MSB first
|
|
// {
|
|
// //shift CRC high bit out
|
|
// crc <<= 1;
|
|
// //apply generator polynomial
|
|
// crc ^= CrcGp1021;
|
|
// }
|
|
// else //CRC highest bit and data input highest bit is equal
|
|
// {
|
|
// crc <<= 1;
|
|
// }
|
|
// dataWord <<= 1; //MSB first shifted out
|
|
// }
|
|
// }
|
|
return crc;
|
|
}
|
|
|
|
public static Byte[] CalculateCRC1021LSBFirst(Byte[] bytes, Int32 start, Int32 length)
|
|
{
|
|
var crc = CalculateMsb1021(bytes, start, length);
|
|
|
|
return BitConverter.GetBytes(crc);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the CRC (LSB first, CRCCCITT 0x0408) from a data array of bytes.
|
|
/// </summary>
|
|
/// <param name="data">data to be processed</param>
|
|
/// <returns>Calculated CRC</returns>
|
|
public static UInt16 CalculateLsb0408(Byte[] data)
|
|
{
|
|
var crc = CrcSeed3791;
|
|
foreach (var t in data)
|
|
{
|
|
var dataByte = t;
|
|
for (var i = 0; i < 8; i++)
|
|
{
|
|
//test if CRC lowest bit is set to one
|
|
if (1 == (crc & 1))
|
|
{
|
|
//shift CRC low bit out
|
|
crc >>= 1;
|
|
//test lowest bit of data word
|
|
if (1 == (dataByte & 1))
|
|
crc |= 0x8000;
|
|
//invert CRC MSB
|
|
crc ^= 0x8000;
|
|
}
|
|
else //CRC lowest bit not set
|
|
{
|
|
//shift CRC low bit out
|
|
crc >>= 1;
|
|
//test lowest bit of data word
|
|
if (1 == (dataByte & 1))
|
|
crc |= 0x8000;
|
|
}
|
|
if (0x8000 == (crc & 0x8000))
|
|
//apply generator polynomial
|
|
crc ^= CrcGp0408;
|
|
|
|
dataByte >>= 1; //LSB first shifted out
|
|
}
|
|
}
|
|
return crc;
|
|
}
|
|
}
|
|
} |