8d0f60ec51
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
49 lines
1.7 KiB
C#
49 lines
1.7 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus;
|
|
|
|
/// <summary>
|
|
/// CRC-16/MODBUS helper: reflected polynomial <c>0xA001</c>, initial value <c>0xFFFF</c>.
|
|
/// On the wire the CRC is appended low byte first, high byte second — <see cref="Append"/>
|
|
/// does that; <see cref="Compute"/> just returns the 16-bit value. Byte-stream-agnostic:
|
|
/// no socket or framing knowledge lives here.
|
|
/// </summary>
|
|
public static class ModbusCrc
|
|
{
|
|
/// <summary>Computes the CRC-16/MODBUS checksum over <paramref name="data"/>.</summary>
|
|
/// <param name="data">The bytes to checksum (e.g. the RTU frame minus the trailing CRC).</param>
|
|
/// <returns>The 16-bit CRC value.</returns>
|
|
public static ushort Compute(ReadOnlySpan<byte> data)
|
|
{
|
|
ushort crc = 0xFFFF;
|
|
foreach (var b in data)
|
|
{
|
|
crc ^= b;
|
|
for (var i = 0; i < 8; i++)
|
|
{
|
|
var carry = (crc & 0x0001) != 0;
|
|
crc >>= 1;
|
|
if (carry)
|
|
{
|
|
crc ^= 0xA001;
|
|
}
|
|
}
|
|
}
|
|
|
|
return crc;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <paramref name="body"/> with its CRC-16/MODBUS appended, low byte first.
|
|
/// </summary>
|
|
/// <param name="body">The frame body to checksum.</param>
|
|
/// <returns>A new array: <paramref name="body"/> followed by <c>[crc & 0xFF, crc >> 8]</c>.</returns>
|
|
public static byte[] Append(ReadOnlySpan<byte> body)
|
|
{
|
|
var crc = Compute(body);
|
|
var result = new byte[body.Length + 2];
|
|
body.CopyTo(result);
|
|
result[^2] = (byte)(crc & 0xFF);
|
|
result[^1] = (byte)(crc >> 8);
|
|
return result;
|
|
}
|
|
}
|