rusty_modbus_codec/response/
bit_read.rs1use crate::error::{DecodeError, EncodeError};
4use crate::request::Encode;
5use rusty_modbus_types::FunctionCode;
6
7#[derive(Debug)]
11pub struct ReadCoilsResponse<'buf> {
12 pub byte_count: u8,
14 pub coil_status: &'buf [u8],
16}
17
18impl<'buf> ReadCoilsResponse<'buf> {
19 #[must_use]
25 pub fn coil(&self, index: usize) -> bool {
26 let byte_idx = index / 8;
27 let bit_idx = index % 8;
28 (self.coil_status[byte_idx] >> bit_idx) & 1 == 1
29 }
30
31 pub fn decode(data: &'buf [u8]) -> Result<Self, DecodeError> {
39 if data.is_empty() {
40 return Err(DecodeError::Truncated {
41 expected: 1,
42 actual: 0,
43 });
44 }
45 let byte_count = data[0];
46 let coil_status = &data[1..];
47 if coil_status.len() != usize::from(byte_count) {
48 return Err(DecodeError::ByteCountMismatch {
49 declared: usize::from(byte_count),
50 actual: coil_status.len(),
51 });
52 }
53 Ok(Self {
54 byte_count,
55 coil_status,
56 })
57 }
58}
59
60impl Encode for ReadCoilsResponse<'_> {
61 fn encode_into(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
62 let len = self.encoded_len();
63 if buf.len() < len {
64 return Err(EncodeError::BufferTooSmall {
65 required: len,
66 available: buf.len(),
67 });
68 }
69 EncodeError::check_byte_count(usize::from(self.byte_count), self.coil_status.len())?;
70 EncodeError::check_pdu_len(len)?;
71 buf[0] = FunctionCode::ReadCoils.code();
72 buf[1] = self.byte_count;
73 buf[2..2 + usize::from(self.byte_count)].copy_from_slice(self.coil_status);
74 Ok(len)
75 }
76
77 fn encoded_len(&self) -> usize {
78 1 + 1 + usize::from(self.byte_count)
79 }
80}
81
82#[derive(Debug)]
86pub struct ReadDiscreteInputsResponse<'buf> {
87 pub byte_count: u8,
89 pub coil_status: &'buf [u8],
91}
92
93impl<'buf> ReadDiscreteInputsResponse<'buf> {
94 #[must_use]
100 pub fn coil(&self, index: usize) -> bool {
101 let byte_idx = index / 8;
102 let bit_idx = index % 8;
103 (self.coil_status[byte_idx] >> bit_idx) & 1 == 1
104 }
105
106 pub fn decode(data: &'buf [u8]) -> Result<Self, DecodeError> {
114 if data.is_empty() {
115 return Err(DecodeError::Truncated {
116 expected: 1,
117 actual: 0,
118 });
119 }
120 let byte_count = data[0];
121 let coil_status = &data[1..];
122 if coil_status.len() != usize::from(byte_count) {
123 return Err(DecodeError::ByteCountMismatch {
124 declared: usize::from(byte_count),
125 actual: coil_status.len(),
126 });
127 }
128 Ok(Self {
129 byte_count,
130 coil_status,
131 })
132 }
133}
134
135impl Encode for ReadDiscreteInputsResponse<'_> {
136 fn encode_into(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
137 let len = self.encoded_len();
138 if buf.len() < len {
139 return Err(EncodeError::BufferTooSmall {
140 required: len,
141 available: buf.len(),
142 });
143 }
144 EncodeError::check_byte_count(usize::from(self.byte_count), self.coil_status.len())?;
145 EncodeError::check_pdu_len(len)?;
146 buf[0] = FunctionCode::ReadDiscreteInputs.code();
147 buf[1] = self.byte_count;
148 buf[2..2 + usize::from(self.byte_count)].copy_from_slice(self.coil_status);
149 Ok(len)
150 }
151
152 fn encoded_len(&self) -> usize {
153 1 + 1 + usize::from(self.byte_count)
154 }
155}