feat(modbus-rtu): add ModbusRtuFraming (ADU build + FC-aware length-less deframe)
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests;
|
||||
|
||||
public sealed class ModbusRtuFramingTests
|
||||
{
|
||||
private static MemoryStream Canned(params byte[] frame) => new(frame);
|
||||
|
||||
[Fact]
|
||||
public void BuildAdu_prefixes_unit_and_appends_crc()
|
||||
{
|
||||
var adu = ModbusRtuFraming.BuildAdu(0x01, new byte[] { 0x03, 0x00, 0x00, 0x00, 0x01 });
|
||||
adu.ShouldBe(new byte[] { 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReadResponse_FC03_returns_bare_pdu()
|
||||
{
|
||||
// addr=01 fc=03 byteCount=02 data=00 0A + CRC(lo,hi)
|
||||
var body = new byte[] { 0x01, 0x03, 0x02, 0x00, 0x0A };
|
||||
var frame = ModbusCrc.Append(body);
|
||||
await using var s = Canned(frame);
|
||||
var pdu = await ModbusRtuFraming.ReadResponsePduAsync(s, 0x01, TestContext.Current.CancellationToken);
|
||||
pdu.ShouldBe(new byte[] { 0x03, 0x02, 0x00, 0x0A }); // fc + byteCount + data, no addr/CRC
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReadResponse_exception_frame_throws_ModbusException()
|
||||
{
|
||||
// addr=01 fc=0x83 exc=0x02 + CRC
|
||||
var frame = ModbusCrc.Append(new byte[] { 0x01, 0x83, 0x02 });
|
||||
await using var s = Canned(frame);
|
||||
var ex = await Should.ThrowAsync<ModbusException>(
|
||||
ModbusRtuFraming.ReadResponsePduAsync(s, 0x01, TestContext.Current.CancellationToken));
|
||||
ex.FunctionCode.ShouldBe((byte)0x03);
|
||||
ex.ExceptionCode.ShouldBe((byte)0x02);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReadResponse_bad_crc_throws_desync()
|
||||
{
|
||||
var frame = ModbusCrc.Append(new byte[] { 0x01, 0x03, 0x02, 0x00, 0x0A });
|
||||
frame[^1] ^= 0xFF; // corrupt CRC high byte
|
||||
await using var s = Canned(frame);
|
||||
await Should.ThrowAsync<ModbusTransportDesyncException>(
|
||||
ModbusRtuFraming.ReadResponsePduAsync(s, 0x01, TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReadResponse_FC06_write_echo_returns_four_byte_pdu()
|
||||
{
|
||||
// addr=01 fc=06 addr=00 07 value=00 2A + CRC -> PDU = 06 00 07 00 2A
|
||||
var frame = ModbusCrc.Append(new byte[] { 0x01, 0x06, 0x00, 0x07, 0x00, 0x2A });
|
||||
await using var s = Canned(frame);
|
||||
var pdu = await ModbusRtuFraming.ReadResponsePduAsync(s, 0x01, TestContext.Current.CancellationToken);
|
||||
pdu.ShouldBe(new byte[] { 0x06, 0x00, 0x07, 0x00, 0x2A });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user