using Shouldly;
using Xunit;
namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;
///
/// Verifies the DL205/DL260 low-byte-first ASCII string packing quirk against the
/// dl205.json 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
/// the driver decodes "eHllo" garbage
/// even though the bytes on the wire are identical.
///
///
///
/// Requires the dl205 profile (Pymodbus\serve.ps1 -Profile dl205). The standard
/// profile does not seed HR[1040..1042] with string bytes, so running this against the
/// standard profile returns "\0\0\0\0\0" and the test fails. Skip when the env
/// var MODBUS_SIM_PROFILE is not set to dl205.
///
///
[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");
}
}