Skip to main content

rusty_modbus_codec/response/
bit_write.rs

1//! Response types for bit-write function codes (FC 05, 0F).
2
3use crate::error::{DecodeError, EncodeError};
4use crate::request::Encode;
5use rusty_modbus_types::{Address, CoilValue, FunctionCode, MAX_WRITE_COILS, Quantity};
6
7/// Response to a Write Single Coil request (FC 0x05).
8///
9/// This is an echo of the request.
10#[derive(Debug)]
11pub struct WriteSingleCoilResponse {
12    /// Address of the coil that was written.
13    pub address: Address,
14    /// Value that was written to the coil.
15    pub value: CoilValue,
16}
17
18impl WriteSingleCoilResponse {
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    /// Returns `DecodeError::InvalidCoilValue` if the coil value is not
26    /// 0xFF00 or 0x0000.
27    pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {
28        DecodeError::check_exact_len(data, 4)?;
29        let address = Address(u16::from_be_bytes([data[0], data[1]]));
30        let raw_value = u16::from_be_bytes([data[2], data[3]]);
31        let value =
32            CoilValue::from_wire(raw_value).ok_or(DecodeError::InvalidCoilValue(raw_value))?;
33        Ok(Self { address, value })
34    }
35}
36
37impl Encode for WriteSingleCoilResponse {
38    fn encode_into(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
39        let len = self.encoded_len();
40        if buf.len() < len {
41            return Err(EncodeError::BufferTooSmall {
42                required: len,
43                available: buf.len(),
44            });
45        }
46        EncodeError::check_pdu_len(len)?;
47        buf[0] = FunctionCode::WriteSingleCoil.code();
48        let addr = self.address.0.to_be_bytes();
49        buf[1] = addr[0];
50        buf[2] = addr[1];
51        let val = self.value.to_wire().to_be_bytes();
52        buf[3] = val[0];
53        buf[4] = val[1];
54        Ok(len)
55    }
56
57    fn encoded_len(&self) -> usize {
58        1 + 4
59    }
60}
61
62/// Response to a Write Multiple Coils request (FC 0x0F).
63#[derive(Debug)]
64pub struct WriteMultipleCoilsResponse {
65    /// Starting address of coils that were written.
66    pub address: Address,
67    /// Number of coils that were written.
68    pub quantity: Quantity,
69}
70
71impl WriteMultipleCoilsResponse {
72    /// Decode from the data bytes following the function code.
73    ///
74    /// # Errors
75    ///
76    /// Returns `DecodeError::Truncated` if `data` is too short.
77    /// Returns `DecodeError::LengthMismatch` if `data` has extra bytes.
78    pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {
79        DecodeError::check_exact_len(data, 4)?;
80        let address = Address(u16::from_be_bytes([data[0], data[1]]));
81        let quantity = Quantity(u16::from_be_bytes([data[2], data[3]]));
82        Ok(Self { address, quantity })
83    }
84}
85
86impl Encode for WriteMultipleCoilsResponse {
87    fn encode_into(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
88        let len = self.encoded_len();
89        if buf.len() < len {
90            return Err(EncodeError::BufferTooSmall {
91                required: len,
92                available: buf.len(),
93            });
94        }
95        EncodeError::check_quantity(self.quantity.0, MAX_WRITE_COILS)?;
96        EncodeError::check_pdu_len(len)?;
97        buf[0] = FunctionCode::WriteMultipleCoils.code();
98        let addr = self.address.0.to_be_bytes();
99        buf[1] = addr[0];
100        buf[2] = addr[1];
101        let qty = self.quantity.0.to_be_bytes();
102        buf[3] = qty[0];
103        buf[4] = qty[1];
104        Ok(len)
105    }
106
107    fn encoded_len(&self) -> usize {
108        1 + 4
109    }
110}