SSPC-Tester/SSPCTester.Devices/Protocol/ModbusRtuProtocol.cs

55 lines
1.7 KiB
C#
Raw Normal View History

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