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;
}
}