namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus; /// /// Raised when a Modbus transaction leaves the single-flight socket in an unknown / /// desynchronized state — a per-op response timeout, or a framing violation (transaction-id /// mismatch, truncated frame, RTU CRC mismatch, or RTU unit-address mismatch). Unlike a Modbus /// exception PDU (a well-formed /// protocol-level error where the socket is still coherent and the request must simply /// propagate), a desync means bytes may still be in flight or half-read, so the socket is /// unusable and MUST be torn down before this is thrown. /// /// /// Derives from deliberately: the transport's existing /// reconnect-and-retry classifier (IsSocketLevelFailure) already treats /// as socket-fatal, so with auto-reconnect enabled the transport /// transparently reconnects and resends once; with auto-reconnect disabled the (already torn /// down) socket is never reused and this surfaces to the driver's status mapping as a /// communication error. /// public sealed class ModbusTransportDesyncException : IOException { /// The reason the socket was classified desynchronized. public enum DesyncReason { /// The per-op deadline (linked CancelAfter) fired — the response never arrived in time. Timeout, /// The response MBAP transaction id did not match the request's. TxIdMismatch, /// /// The frame ended before it was complete — the MBAP length field was below the mandatory /// minimum (TCP), or the stream closed mid-frame while reading a length-less RTU frame. /// TruncatedFrame, /// The RTU frame's trailing CRC-16 did not validate over the received bytes. CrcMismatch, /// /// A CRC-valid RTU frame carried a slave/unit address other than the one addressed — on an /// RS-485 multi-drop bus, a reply from the wrong slave. /// UnitMismatch, } /// Gets the reason the socket was classified desynchronized. public DesyncReason Reason { get; } /// Initializes a new instance of the class. /// The desync reason. /// A human-readable description. /// The originating exception, if any. public ModbusTransportDesyncException(DesyncReason reason, string message, Exception? inner = null) : base(message, inner) { Reason = reason; } }