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