A. #566 on a real CompactLogix (Z-35162, read-only): a class-3 connection idled 60 s past its 16 s timeout is closed at the TCP level, not with CIP 0x0107/0x0203; the next request fails on its write (Broken pipe -> BadConnection) in 9 ms and the one after reopens. The transport already handles this, so no production behaviour changed; the shape is pinned offline by CipConnectionTests.A_target_that_resets_an_idle_session_... (FakeEipServer.ResetAllConnections), proven red with a reconnect-skipping mutation. The diagnostics-only exchange tap now also sees Forward Open replies (granted RPIs). B. Native STRING write through the driver on Program:ES03_TemperatureControl._StrTmp: write, read back, restored byte-exact (user-approved). Array write NOT run: the census's unreferenced DINT[32] _SEQ_EP arrays are aliased sequencer step registers (raw L5X grep), so none qualifies. #567 still impossible (a 128 B array / 88 B STRING never fragments). New env-gated harness: AbCip.IntegrationTests/HardwareGate (IdleConnectionEvidenceTests, StringWriteGateTests). Docs: gate results (hw5 section + raw output), AbCip.md, CLAUDE.md. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -221,7 +221,9 @@ public sealed class CipConnection : ICipChannel, IAsyncDisposable
|
||||
_o.RpiMicros, size, _route);
|
||||
var frame = ConnectionManagerServices.ForwardOpen(p);
|
||||
_diagnostics.CountForwardOpen();
|
||||
return CipReply.Parse(await client.SendRRDataAsync(frame, _o.Timeout, ct).ConfigureAwait(false));
|
||||
var raw = await client.SendRRDataAsync(frame, _o.Timeout, ct).ConfigureAwait(false);
|
||||
_diagnostics.NotifyExchange(frame, raw); // evidence tap: the granted RPIs / connection ids (#566 gate)
|
||||
return CipReply.Parse(raw);
|
||||
}
|
||||
|
||||
private ushort NextConnectionSerial()
|
||||
|
||||
@@ -92,8 +92,8 @@ internal sealed class ConnectionDiagnostics
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evidence tap for the gate harness (#582 / #572): sees the CIP request and the raw CIP reply of every
|
||||
/// completed exchange. Null in production; set only by the read-only differential harness. A throwing
|
||||
/// Evidence tap for the gate harness (#582 / #572 / #566): sees the CIP request and the raw CIP reply of every
|
||||
/// completed exchange, Forward Opens included (their replies carry the granted RPIs). Null in production; set only by the read-only differential harness. A throwing
|
||||
/// observer is swallowed so it can never affect a request.
|
||||
/// </summary>
|
||||
internal Action<ReadOnlyMemory<byte>, ReadOnlyMemory<byte>>? ExchangeObserver { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user