82 lines
3.6 KiB
C#
82 lines
3.6 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;
|
|
|
|
/// <summary>
|
|
/// Verifies the DL205/DL260 low-byte-first ASCII string packing quirk against the
|
|
/// <c>dl205.json</c> pymodbus profile. Standard Modbus packs the first char of each pair
|
|
/// in the high byte of the register; DirectLOGIC packs it in the low byte instead. Without
|
|
/// <see cref="ModbusStringByteOrder.LowByteFirst"/> the driver decodes "eHllo" garbage
|
|
/// even though the bytes on the wire are identical.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// Requires the dl205 profile (<c>Pymodbus\serve.ps1 -Profile dl205</c>). The standard
|
|
/// profile does not seed HR[1040..1042] with string bytes, so running this against the
|
|
/// standard profile returns <c>"\0\0\0\0\0"</c> and the test fails. Skip when the env
|
|
/// var <c>MODBUS_SIM_PROFILE</c> is not set to <c>dl205</c>.
|
|
/// </para>
|
|
/// </remarks>
|
|
[Collection(ModbusSimulatorCollection.Name)]
|
|
[Trait("Category", "Integration")]
|
|
[Trait("Device", "DL205")]
|
|
public sealed class DL205StringQuirkTests(ModbusSimulatorFixture sim)
|
|
{
|
|
[Fact]
|
|
public async Task DL205_string_low_byte_first_decodes_Hello_from_HR1040()
|
|
{
|
|
if (sim.SkipReason is not null) Assert.Skip(sim.SkipReason);
|
|
if (!string.Equals(Environment.GetEnvironmentVariable("MODBUS_SIM_PROFILE"), "dl205",
|
|
StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Assert.Skip("MODBUS_SIM_PROFILE != dl205 — skipping (standard profile does not seed HR[1040..1042]).");
|
|
}
|
|
|
|
var options = new ModbusDriverOptions
|
|
{
|
|
Host = sim.Host,
|
|
Port = sim.Port,
|
|
UnitId = 1,
|
|
Timeout = TimeSpan.FromSeconds(2),
|
|
Tags =
|
|
[
|
|
new ModbusTagDefinition(
|
|
Name: "DL205_Hello_Low",
|
|
Region: ModbusRegion.HoldingRegisters,
|
|
Address: 1040,
|
|
DataType: ModbusDataType.String,
|
|
Writable: false,
|
|
StringLength: 5,
|
|
StringByteOrder: ModbusStringByteOrder.LowByteFirst),
|
|
// Control: same address, HighByteFirst, to prove the driver would have decoded
|
|
// garbage without the quirk flag.
|
|
new ModbusTagDefinition(
|
|
Name: "DL205_Hello_High",
|
|
Region: ModbusRegion.HoldingRegisters,
|
|
Address: 1040,
|
|
DataType: ModbusDataType.String,
|
|
Writable: false,
|
|
StringLength: 5,
|
|
StringByteOrder: ModbusStringByteOrder.HighByteFirst),
|
|
],
|
|
Probe = new ModbusProbeOptions { Enabled = false },
|
|
};
|
|
await using var driver = new ModbusDriver(options, driverInstanceId: "dl205-string");
|
|
await driver.InitializeAsync(driverConfigJson: "{}", TestContext.Current.CancellationToken);
|
|
|
|
var results = await driver.ReadAsync(["DL205_Hello_Low", "DL205_Hello_High"],
|
|
TestContext.Current.CancellationToken);
|
|
|
|
results.Count.ShouldBe(2);
|
|
results[0].StatusCode.ShouldBe(0u);
|
|
results[0].Value.ShouldBe("Hello", "DL205 low-byte-first ordering must produce 'Hello' from HR[1040..1042]");
|
|
|
|
// The high-byte-first read of the same wire bytes should differ — not asserting the
|
|
// exact garbage string (that would couple the test to the ASCII byte math) but the two
|
|
// decodes MUST disagree, otherwise the quirk flag is a no-op.
|
|
results[1].StatusCode.ShouldBe(0u);
|
|
results[1].Value.ShouldNotBe("Hello");
|
|
}
|
|
}
|