Skip to main content

mbus_async/client/
response.rs

1//! Client response types returned through the task's oneshot channel.
2//!
3//! [`ClientResponse`] is the typed result enum that the background task sends
4//! back to the caller after successfully executing a Modbus request.  Each
5//! variant corresponds to one function-code group and is feature-gated to
6//! match the corresponding [`ClientRequest`] variants.
7//!
8//! The `connect()` path uses a plain `Result<(), MbusError>` oneshot directly
9//! and is not represented here.
10//!
11//! [`ClientRequest`]: crate::client::command::ClientRequest
12
13#[cfg(feature = "coils")]
14use mbus_core::models::coil::Coils;
15#[cfg(feature = "diagnostics")]
16use mbus_core::models::diagnostic::DeviceIdentificationResponse;
17#[cfg(feature = "discrete-inputs")]
18use mbus_core::models::discrete_input::DiscreteInputs;
19#[cfg(feature = "fifo")]
20use mbus_core::models::fifo_queue::FifoQueue;
21#[cfg(feature = "file-record")]
22use mbus_core::models::file_record::SubRequestParams;
23#[cfg(feature = "holding-registers")]
24use mbus_core::models::register::HoldingRegisters;
25#[cfg(feature = "input-registers")]
26use mbus_core::models::register::InputRegisters;
27
28#[cfg(feature = "diagnostics")]
29use mbus_core::function_codes::public::{DiagnosticSubFunction, EncapsulatedInterfaceType};
30
31#[cfg(feature = "diagnostics")]
32use mbus_core::data_unit::common::MAX_PDU_DATA_LEN;
33#[cfg(feature = "file-record")]
34use mbus_core::models::file_record::MAX_SUB_REQUESTS_PER_PDU;
35
36// ─── ClientResponse ───────────────────────────────────────────────────────────
37
38/// Typed response payload returned to the async caller via a oneshot channel.
39///
40/// The task encodes the response variant that matches the outgoing request type.
41/// [`AsyncClientCore`] pattern-matches the variant to extract the concrete return
42/// type expected by each public method.
43///
44/// [`AsyncClientCore`]: crate::client::client_core::AsyncClientCore
45// Variants use heapless::Vec (stack-allocated) and are transient one-shot
46// values sent over a oneshot channel; boxing would add heap overhead for no gain.
47#[allow(clippy::large_enum_variant)]
48#[derive(Debug)]
49pub enum ClientResponse {
50    // ── Coils ────────────────────────────────────────────────────────────
51    /// Read Coils (FC 01), Write Single Coil (FC 05), Write Multiple Coils (FC 0F).
52    #[cfg(feature = "coils")]
53    Coils(Coils),
54
55    // ── Registers ────────────────────────────────────────────────────────
56    /// Read Holding Registers (FC 03), Read Input Registers (FC 04),
57    /// Write Multiple Registers (FC 10), Read/Write Multiple Registers (FC 17).
58    #[cfg(feature = "holding-registers")]
59    HoldingRegisters(HoldingRegisters),
60    /// Read Input Registers (FC 04).
61    #[cfg(feature = "input-registers")]
62    InputRegisters(InputRegisters),
63    /// Write Single Register (FC 06) echo-back confirmation.
64    #[cfg(feature = "holding-registers")]
65    SingleRegisterWrite {
66        /// Echoed register address.
67        address: u16,
68        /// Echoed written value.
69        value: u16,
70    },
71    /// Mask Write Register (FC 16) acknowledgement.
72    #[cfg(feature = "holding-registers")]
73    MaskWriteRegister,
74
75    // ── Discrete inputs ───────────────────────────────────────────────────
76    /// Read Discrete Inputs (FC 02).
77    #[cfg(feature = "discrete-inputs")]
78    DiscreteInputs(DiscreteInputs),
79
80    // ── FIFO queue ────────────────────────────────────────────────────────
81    /// Read FIFO Queue (FC 18).
82    #[cfg(feature = "fifo")]
83    FifoQueue(FifoQueue),
84
85    // ── File record ───────────────────────────────────────────────────────
86    /// Read File Record (FC 14) — parsed sub-request results.
87    #[cfg(feature = "file-record")]
88    FileRecordRead(heapless::Vec<SubRequestParams, MAX_SUB_REQUESTS_PER_PDU>),
89    /// Write File Record (FC 15) acknowledgement.
90    #[cfg(feature = "file-record")]
91    FileRecordWrite,
92
93    // ── Diagnostics ───────────────────────────────────────────────────────
94    /// Read Device Identification (FC 43 / MEI 0E).
95    #[cfg(feature = "diagnostics")]
96    DeviceIdentification(DeviceIdentificationResponse),
97    /// Encapsulated Interface Transport (FC 43 / non-0E MEI type).
98    #[cfg(feature = "diagnostics")]
99    EncapsulatedInterfaceTransport {
100        /// MEI type code from the response.
101        mei_type: EncapsulatedInterfaceType,
102        /// Raw response bytes.
103        data: heapless::Vec<u8, MAX_PDU_DATA_LEN>,
104    },
105    /// Read Exception Status (FC 07).
106    #[cfg(feature = "diagnostics")]
107    ExceptionStatus(u8),
108    /// Diagnostics (FC 08) echo-back.
109    #[cfg(feature = "diagnostics")]
110    DiagnosticsData {
111        /// Echoed sub-function code.
112        sub_function: DiagnosticSubFunction,
113        /// Echoed data words.
114        data: heapless::Vec<u16, MAX_PDU_DATA_LEN>,
115    },
116    /// Get Comm Event Counter (FC 0B).
117    #[cfg(feature = "diagnostics")]
118    CommEventCounter {
119        /// Device communication status word.
120        status: u16,
121        /// Number of successfully completed events since last restart.
122        event_count: u16,
123    },
124    /// Get Comm Event Log (FC 0C).
125    #[cfg(feature = "diagnostics")]
126    CommEventLog {
127        /// Device communication status word.
128        status: u16,
129        /// Total events recorded.
130        event_count: u16,
131        /// Total messages processed.
132        message_count: u16,
133        /// Raw event bytes (oldest first).
134        events: heapless::Vec<u8, MAX_PDU_DATA_LEN>,
135    },
136    /// Report Server ID (FC 11).
137    #[cfg(feature = "diagnostics")]
138    ReportServerId(heapless::Vec<u8, MAX_PDU_DATA_LEN>),
139}