common/Utils/Crc16Ccitt/Crc16Ccitt.cs
2026-04-23 17:50:07 +02:00

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;
}
}
}