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}