Skip to main content

rusty_modbus_codec/response/
reg_write.rs

1//! Response types for register-write function codes (FC 06, 10, 16, 17).
2
3use crate::error::{DecodeError, EncodeError};
4use crate::request::Encode;
5use rusty_modbus_types::{Address, FunctionCode, MAX_WRITE_REGISTERS, Quantity};
6
7/// Response to a Write Single Register request (FC 0x06).
8///
9/// This is an echo of the request.
10#[derive(Debug)]
11pub struct WriteSingleRegisterResponse {
12    /// Address of the register that was written.
13    pub address: Address,
14    /// Value that was written to the register.
15    pub value: u16,
16}
17
18impl WriteSingleRegisterResponse {
19    /// Decode from the data bytes following the function code.
20    ///
21    /// # Errors
22    ///
23    /// Returns `DecodeError::Truncated` if `data` is too short.
24    /// Returns `DecodeError::LengthMismatch` if `data` has extra bytes.
25    pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {
26        DecodeError::check_exact_len(data, 4)?;
27        let address = Address(u16::from_be_bytes([data[0], data[1]]));
28        let value = u16::from_be_bytes([data[2], data[3]]);
29        Ok(Self { address, value })
30    }
31}
32
33impl Encode for WriteSingleRegisterResponse {
34    fn encode_into(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
35        let len = self.encoded_len();
36        if buf.len() < len {
37            return Err(EncodeError::BufferTooSmall {
38                required: len,
39                available: buf.len(),
40            });
41        }
42        EncodeError::check_pdu_len(len)?;
43        buf[0] = FunctionCode::WriteSingleRegister.code();
44        let addr = self.address.0.to_be_bytes();
45        buf[1] = addr[0];
46        buf[2] = addr[1];
47        let val = self.value.to_be_bytes();
48        buf[3] = val[0];
49        buf[4] = val[1];
50        Ok(len)
51    }
52
53    fn encoded_len(&self) -> usize {
54        1 + 4
55    }
56}
57
58/// Response to a Write Multiple Registers request (FC 0x10).
59#[derive(Debug)]
60pub struct WriteMultipleRegistersResponse {
61    /// Starting address of registers that were written.
62    pub address: Address,
63    /// Number of registers that were written.
64    pub quantity: Quantity,
65}
66
67impl WriteMultipleRegistersResponse {
68    /// Decode from the data bytes following the function code.
69    ///
70    /// # Errors
71    ///
72    /// Returns `DecodeError::Truncated` if `data` is too short.
73    /// Returns `DecodeError::LengthMismatch` if `data` has extra bytes.
74    pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {
75        DecodeError::check_exact_len(data, 4)?;
76        let address = Address(u16::from_be_bytes([data[0], data[1]]));
77        let quantity = Quantity(u16::from_be_bytes([data[2], data[3]]));
78        Ok(Self { address, quantity })
79    }
80}
81
82impl Encode for WriteMultipleRegistersResponse {
83    fn encode_into(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
84        let len = self.encoded_len();
85        if buf.len() < len {
86            return Err(EncodeError::BufferTooSmall {
87                required: len,
88                available: buf.len(),
89            });
90        }
91        EncodeError::check_quantity(self.quantity.0, MAX_WRITE_REGISTERS)?;
92        EncodeError::check_pdu_len(len)?;
93        buf[0] = FunctionCode::WriteMultipleRegisters.code();
94        let addr = self.address.0.to_be_bytes();
95        buf[1] = addr[0];
96        buf[2] = addr[1];
97        let qty = self.quantity.0.to_be_bytes();
98        buf[3] = qty[0];
99        buf[4] = qty[1];
100        Ok(len)
101    }
102
103    fn encoded_len(&self) -> usize {
104        1 + 4
105    }
106}
107
108/// Response to a Mask Write Register request (FC 0x16).
109///
110/// This is an echo of the request.
111#[derive(Debug)]
112pub struct MaskWriteRegisterResponse {
113    /// Address of the register.
114    pub address: Address,
115    /// AND mask applied to the register.
116    pub and_mask: u16,
117    /// OR mask applied to the register.
118    pub or_mask: u16,
119}
120
121impl MaskWriteRegisterResponse {
122    /// Decode from the data bytes following the function code.
123    ///
124    /// # Errors
125    ///
126    /// Returns `DecodeError::Truncated` if `data` is too short.
127    /// Returns `DecodeError::LengthMismatch` if `data` has extra bytes.
128    pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {
129        DecodeError::check_exact_len(data, 6)?;
130        let address = Address(u16::from_be_bytes([data[0], data[1]]));
131        let and_mask = u16::from_be_bytes([data[2], data[3]]);
132        let or_mask = u16::from_be_bytes([data[4], data[5]]);
133        Ok(Self {
134            address,
135            and_mask,
136            or_mask,
137        })
138    }
139}
140
141impl Encode for MaskWriteRegisterResponse {
142    fn encode_into(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
143        let len = self.encoded_len();
144        if buf.len() < len {
145            return Err(EncodeError::BufferTooSmall {
146                required: len,
147                available: buf.len(),
148            });
149        }
150        EncodeError::check_pdu_len(len)?;
151        buf[0] = FunctionCode::MaskWriteRegister.code();
152        let addr = self.address.0.to_be_bytes();
153        buf[1] = addr[0];
154        buf[2] = addr[1];
155        let and_m = self.and_mask.to_be_bytes();
156        buf[3] = and_m[0];
157        buf[4] = and_m[1];
158        let or_m = self.or_mask.to_be_bytes();
159        buf[5] = or_m[0];
160        buf[6] = or_m[1];
161        Ok(len)
162    }
163
164    fn encoded_len(&self) -> usize {
165        1 + 6
166    }
167}
168
169/// Response to a Read/Write Multiple Registers request (FC 0x17).
170#[derive(Debug)]
171pub struct ReadWriteMultipleRegistersResponse<'buf> {
172    /// Number of data bytes that follow (should be 2 * register count).
173    pub byte_count: u8,
174    /// Raw register data in big-endian byte order.
175    pub register_data: &'buf [u8],
176}
177
178impl<'buf> ReadWriteMultipleRegistersResponse<'buf> {
179    /// Returns the number of registers in this response.
180    #[must_use]
181    pub fn count(&self) -> usize {
182        self.register_data.len() / 2
183    }
184
185    /// Returns the register value at the given zero-based index.
186    ///
187    /// # Panics
188    ///
189    /// Panics if `index` is out of range.
190    #[must_use]
191    pub fn register(&self, index: usize) -> u16 {
192        let off = index * 2;
193        u16::from_be_bytes([self.register_data[off], self.register_data[off + 1]])
194    }
195
196    /// Returns an iterator over all register values.
197    pub fn registers(&self) -> impl Iterator<Item = u16> + '_ {
198        self.register_data
199            .chunks_exact(2)
200            .map(|c| u16::from_be_bytes([c[0], c[1]]))
201    }
202
203    /// Returns the raw register data bytes.
204    #[must_use]
205    pub fn raw(&self) -> &'buf [u8] {
206        self.register_data
207    }
208
209    /// Decode from the data bytes following the function code.
210    ///
211    /// # Errors
212    ///
213    /// Returns `DecodeError::Truncated` if `data` is too short.
214    /// Returns `DecodeError::ByteCountMismatch` if the declared byte count
215    /// does not match the remaining data length.
216    pub fn decode(data: &'buf [u8]) -> Result<Self, DecodeError> {
217        if data.is_empty() {
218            return Err(DecodeError::Truncated {
219                expected: 1,
220                actual: 0,
221            });
222        }
223        let byte_count = data[0];
224        let register_data = &data[1..];
225        if register_data.len() != usize::from(byte_count) {
226            return Err(DecodeError::ByteCountMismatch {
227                declared: usize::from(byte_count),
228                actual: register_data.len(),
229            });
230        }
231        Ok(Self {
232            byte_count,
233            register_data,
234        })
235    }
236}
237
238impl Encode for ReadWriteMultipleRegistersResponse<'_> {
239    fn encode_into(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
240        let len = self.encoded_len();
241        if buf.len() < len {
242            return Err(EncodeError::BufferTooSmall {
243                required: len,
244                available: buf.len(),
245            });
246        }
247        EncodeError::check_byte_count(usize::from(self.byte_count), self.register_data.len())?;
248        EncodeError::check_pdu_len(len)?;
249        buf[0] = FunctionCode::ReadWriteMultipleRegisters.code();
250        buf[1] = self.byte_count;
251        buf[2..2 + usize::from(self.byte_count)].copy_from_slice(self.register_data);
252        Ok(len)
253    }
254
255    fn encoded_len(&self) -> usize {
256        1 + 1 + usize::from(self.byte_count)
257    }
258}