fix(modbus): review r0 - FC23 opt-in, explicit maxReadGap 0 = off, legacy coil types load, one health writer
Coordinator rulings and Important findings from review r0: 1. FC23 is opt-in (new UseFC23ForMultiRegisterWrites, default false); a config without it - including the persisted "disableFC23": false every form-saved config carries - keeps the FC16 wire. DisableFC23 stays the hard kill-switch. 2. An explicit maxReadGap 0 means coalescing off again (its pre-lane meaning); the gap-8 default applies only to an absent key. 3. Coils/DiscreteInputs tags persisted with a register dataType (the old editor saved Int16) are coerced to Bool, never refused, with no deploy warning (a warning can be promoted to a blocking error). The editor loads them as Bool. Register region + Bool is still refused. 4. One comms-fault slot for reads and writes: a good read clears a write's transport fault and vice versa. Minors: Dispose writes its own Unknown health (m1); persisted region/address are authoritative over addressString so a Family change cannot remap a live tag (m2); a malformed-but-delivered reply no longer fails the unit fast (m3); a fresh socket published after a concurrent dispose is torn down (m4); the editor resets address text per tag (m5); master merged (m6); the FC23 latch log says re-init restores it (m7). Back-compat tests use the old persisted JSON shapes and fail without the fixes. Refs #741 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -49,6 +49,32 @@ public sealed class ModbusCoalescingDefaultsTests
|
||||
r.Select(s => (short)s.Value!).ShouldBe(Enumerable.Range(1, 10).Select(i => (short)i));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fix round 1 (coordinator ruling 2): an explicitly authored maxReadGap 0 — what the pre-#741 form
|
||||
/// persisted on every driver — keeps its old meaning, NO coalescing; the gap-8 default applies only to an
|
||||
/// absent key (positive control).
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[InlineData("""{"host":"h","maxReadGap":0,"disableFC23":false}""", 2)]
|
||||
[InlineData("""{"host":"h"}""", 1)]
|
||||
public async Task A_persisted_maxReadGap_0_keeps_coalescing_off(string legacyConfig, int expectedReads)
|
||||
{
|
||||
var parsed = ModbusDriverFactoryExtensions.ParseOptions("m1", legacyConfig);
|
||||
var tags = new[]
|
||||
{
|
||||
new ModbusTagDefinition("A", ModbusRegion.HoldingRegisters, 100, ModbusDataType.Int16),
|
||||
new ModbusTagDefinition("B", ModbusRegion.HoldingRegisters, 101, ModbusDataType.Int16),
|
||||
};
|
||||
var (drv, t) = await StartAsync(new ModbusDriverOptions
|
||||
{
|
||||
Host = "f", MaxReadGap = parsed.MaxReadGap, DisableReadCoalescing = parsed.DisableReadCoalescing,
|
||||
RawTags = ModbusRawTags.Entries(tags), Probe = new ModbusProbeOptions { Enabled = false },
|
||||
});
|
||||
await using var _ = drv;
|
||||
await drv.ReadAsync(["A", "B"], TestContext.Current.CancellationToken);
|
||||
t.Requests(0x03).Count.ShouldBe(expectedReads);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DisableReadCoalescing_reads_every_tag_alone()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user