1use super::*;
6
7pub fn decode_request(buf: &[u8]) -> Result<Option<RequestAdu<'_>>> {
9 if buf.is_empty() {
10 return Ok(None);
11 }
12 let frame = decode(DecoderType::Request, buf)?;
13 let Some((decoded_frame, _frame_pos)) = frame else {
14 return Ok(None);
15 };
16 let DecodedFrame {
17 transaction_id,
18 unit_id,
19 pdu,
20 } = decoded_frame;
21 let hdr = Header {
22 transaction_id,
23 unit_id,
24 };
25 let request = Request::try_from(pdu)
29 .map(RequestPdu)
30 .map(|pdu| Some(RequestAdu { hdr, pdu }));
31 #[cfg(feature = "log")]
32 if let Err(error) = request {
33 log::error!("Failed to decode request PDU: {error}");
35 }
36 request
37}
38
39pub fn decode_response(buf: &[u8]) -> Result<Option<ResponseAdu<'_>>> {
41 if buf.is_empty() {
42 return Err(Error::BufferSize);
43 }
44 decode(DecoderType::Response, buf)
45 .and_then(|frame| {
46 let Some((decoded_frame, _frame_pos)) = frame else {
47 return Ok(None);
48 };
49 let DecodedFrame {
50 transaction_id,
51 unit_id,
52 pdu,
53 } = decoded_frame;
54 let hdr = Header {
55 transaction_id,
56 unit_id,
57 };
58 let response = Response::try_from(pdu)
62 .map(Ok)
63 .or_else(|_| ExceptionResponse::try_from(pdu).map(Err))
64 .map(ResponsePdu)
65 .map(|pdu| Some(ResponseAdu { hdr, pdu }));
66 #[cfg(feature = "log")]
67 if let Err(error) = response {
68 log::error!("Failed to decode response PDU: {error}");
70 }
71 response
72 })
73 .map_err(|_| {
74 unreachable!();
77 })
78}
79
80pub fn encode_response(adu: ResponseAdu, buf: &mut [u8]) -> Result<usize> {
82 let ResponseAdu { hdr, pdu } = adu;
83 if buf.len() < 7 {
84 return Err(Error::BufferSize);
85 }
86 BigEndian::write_u16(&mut buf[0..2], hdr.transaction_id);
87 BigEndian::write_u16(&mut buf[2..4], 0); buf[6] = hdr.unit_id;
89 let len = pdu.encode(&mut buf[7..])?;
90 if buf.len() < len + 7 {
91 return Err(Error::BufferSize);
92 }
93 BigEndian::write_u16(&mut buf[4..6], (len + 1) as u16);
94
95 Ok(len + 7)
96}
97
98pub fn encode_request(adu: RequestAdu, buf: &mut [u8]) -> Result<usize> {
99 let RequestAdu { hdr, pdu } = adu;
100 if buf.len() < 7 {
101 return Err(Error::BufferSize);
102 }
103 BigEndian::write_u16(&mut buf[0..2], hdr.transaction_id);
104 BigEndian::write_u16(&mut buf[2..4], 0); buf[6] = hdr.unit_id;
106 let len = pdu.encode(&mut buf[7..])?;
107 if buf.len() < len + 7 {
108 return Err(Error::BufferSize);
109 }
110 BigEndian::write_u16(&mut buf[4..6], (len + 1) as u16);
111
112 Ok(len + 7)
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn decode_empty_request() {
121 let req = decode_request(&[]).unwrap();
122 assert!(req.is_none());
123 }
124
125 #[test]
126 fn decode_partly_received_request() {
127 let buf = &[
128 0x00, 0x01, ];
131 let req = decode_request(buf).unwrap();
132 assert!(req.is_none());
133 }
134
135 #[test]
136 fn decode_write_single_register_request() {
137 let buf = &[
138 0x00, 0x2a, 0x00, 0x00, 0x00, 0x06, 0x12, 0x06, 0x22, 0x22, 0xAB, 0xCD, ];
151 let adu = decode_request(buf).unwrap().unwrap();
152 let RequestAdu { hdr, pdu } = adu;
153 let RequestPdu(pdu) = pdu;
154 assert_eq!(hdr.transaction_id, 42);
155 assert_eq!(hdr.unit_id, 0x12);
156 assert_eq!(FunctionCode::from(pdu), FunctionCode::WriteSingleRegister);
157 }
158
159 #[test]
160 fn decode_wrong_protocol() {
161 let buf = &[
162 0x00, 0x2a, 0x00, 0x01, 0x00, 0x06, 0x12, 0x06, 0x22, 0x22, 0xAB, 0xCD, ];
175 assert!(decode_request(buf).unwrap().is_none());
176 }
177
178 #[test]
179 fn encode_write_single_register_response() {
180 let adu = ResponseAdu {
181 hdr: Header {
182 transaction_id: 42,
183 unit_id: 0x12,
184 },
185 pdu: ResponsePdu(Ok(Response::WriteSingleRegister(0x2222, 0xABCD))),
186 };
187 let buf = &mut [0; 100];
188 let len = encode_response(adu, buf).unwrap();
189 assert_eq!(len, 12);
190 assert_eq!(buf[0], 0x00);
191 assert_eq!(buf[1], 0x2a);
192 assert_eq!(buf[2], 0x00);
193 assert_eq!(buf[3], 0x00);
194 assert_eq!(buf[4], 0x00);
195 assert_eq!(buf[5], 0x06);
196 assert_eq!(buf[6], 0x12);
197 assert_eq!(buf[7], 0x06);
198 assert_eq!(buf[8], 0x22);
199 assert_eq!(buf[9], 0x22);
200 assert_eq!(buf[10], 0xAB);
201 assert_eq!(buf[11], 0xCD);
202 }
203
204 #[test]
205 fn response_buffer_too_small() {
206 let adu = ResponseAdu {
207 hdr: Header {
208 transaction_id: 42,
209 unit_id: 0x12,
210 },
211 pdu: ResponsePdu(Ok(Response::WriteSingleRegister(0x2222, 0xABCD))),
212 };
213 let buf = &mut [0; 11];
214 let res = encode_response(adu, buf).err().unwrap();
215 assert_eq!(res, Error::BufferSize);
216 }
217
218 #[test]
219 fn request_buffer_too_small() {
220 let adu = RequestAdu {
221 hdr: Header {
222 transaction_id: 42,
223 unit_id: 0x12,
224 },
225 pdu: RequestPdu(Request::WriteSingleRegister(0x2222, 0xABCD)),
226 };
227 let buf = &mut [0; 11];
228 let res = encode_request(adu, buf).err().unwrap();
229 assert_eq!(res, Error::BufferSize);
230 }
231}