namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus; /// /// CRC-16/MODBUS helper: reflected polynomial 0xA001, initial value 0xFFFF. /// On the wire the CRC is appended low byte first, high byte second — /// does that; just returns the 16-bit value. Byte-stream-agnostic: /// no socket or framing knowledge lives here. /// public static class ModbusCrc { /// Computes the CRC-16/MODBUS checksum over . /// The bytes to checksum (e.g. the RTU frame minus the trailing CRC). /// The 16-bit CRC value. public static ushort Compute(ReadOnlySpan 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; } /// /// Returns with its CRC-16/MODBUS appended, low byte first. /// /// The frame body to checksum. /// A new array: followed by [crc & 0xFF, crc >> 8]. public static byte[] Append(ReadOnlySpan 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; } }