55 lines
1.7 KiB
C#
55 lines
1.7 KiB
C#
namespace SSPCTester.Devices.Protocol;
|
|
|
|
public static class ModbusRtuProtocol
|
|
{
|
|
public static ushort ComputeCrc(ReadOnlySpan<byte> data)
|
|
{
|
|
ushort crc = 0xFFFF;
|
|
foreach (byte value in data)
|
|
{
|
|
crc ^= value;
|
|
for (int i = 0; i < 8; i++)
|
|
crc = (ushort)((crc & 1) != 0 ? (crc >> 1) ^ 0xA001 : crc >> 1);
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
public static byte[] BuildRequest(byte slave, byte function, ushort address, ushort valueOrCount)
|
|
{
|
|
var frame = new byte[8];
|
|
frame[0] = slave;
|
|
frame[1] = function;
|
|
frame[2] = (byte)(address >> 8);
|
|
frame[3] = (byte)address;
|
|
frame[4] = (byte)(valueOrCount >> 8);
|
|
frame[5] = (byte)valueOrCount;
|
|
ushort crc = ComputeCrc(frame.AsSpan(0, 6));
|
|
frame[6] = (byte)crc;
|
|
frame[7] = (byte)(crc >> 8);
|
|
return frame;
|
|
}
|
|
|
|
public static void ValidateCrc(ReadOnlySpan<byte> frame)
|
|
{
|
|
if (frame.Length < 5) throw new InvalidDataException("Modbus 响应长度不足。");
|
|
ushort expected = ComputeCrc(frame[..^2]);
|
|
ushort actual = (ushort)(frame[^2] | frame[^1] << 8);
|
|
if (expected != actual)
|
|
throw new InvalidDataException($"Modbus CRC 错误,期望 {expected:X4},实际 {actual:X4}。");
|
|
}
|
|
}
|
|
|
|
public static class ModbusValueConverter
|
|
{
|
|
public static double ConvertRaw(ushort rawBits, bool signed, string formula, double range)
|
|
{
|
|
double raw = signed ? unchecked((short)rawBits) : rawBits;
|
|
return formula switch
|
|
{
|
|
"A" => raw / 10000.0 * range,
|
|
"B" => raw / range,
|
|
_ => throw new InvalidDataException($"不支持换算公式 {formula}")
|
|
};
|
|
}
|
|
}
|