1use super::*;
7use byteorder::{BigEndian, ByteOrder};
8
9pub mod client;
10pub mod server;
11pub use crate::frame::rtu::*;
12
13pub const MAX_FRAME_LEN: usize = 256;
16
17#[cfg_attr(all(feature = "defmt", target_os = "none"), derive(defmt::Format))]
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct DecodedFrame<'a> {
21 pub slave: SlaveId,
22 pub pdu: &'a [u8],
23}
24
25#[cfg_attr(all(feature = "defmt", target_os = "none"), derive(defmt::Format))]
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub struct FrameLocation {
29 pub start: usize,
31 pub size: usize,
33}
34
35pub fn decode(
37 decoder_type: DecoderType,
38 buf: &[u8],
39) -> Result<Option<(DecodedFrame<'_>, FrameLocation)>> {
40 use DecoderType::{Request, Response};
41 let mut drop_cnt = 0;
42
43 if buf.is_empty() {
44 return Err(Error::BufferSize);
45 }
46
47 loop {
48 let mut retry = false;
49 if drop_cnt + 1 >= buf.len() {
50 return Ok(None);
51 }
52 let raw_frame = &buf[drop_cnt..];
53 let res = match decoder_type {
54 Request => request_pdu_len(raw_frame),
55 Response => response_pdu_len(raw_frame),
56 }
57 .and_then(|pdu_len| {
58 retry = false;
59 let Some(pdu_len) = pdu_len else {
60 return Ok(None);
62 };
63 extract_frame(raw_frame, pdu_len).map(|x| {
64 x.map(|res| {
65 let frame_location = FrameLocation {
66 start: drop_cnt,
67 size: pdu_len + 3, };
69 (res, frame_location)
70 })
71 })
72 })
73 .or_else(|err| {
74 if drop_cnt + 1 >= MAX_FRAME_LEN {
75 #[cfg(feature = "log")]
76 log::error!(
77 "Giving up to decode frame after dropping {drop_cnt} byte(s): {:X?}",
78 &buf[0..drop_cnt]
79 );
80 return Err(err);
81 }
82 #[cfg(feature = "log")]
83 log::warn!(
84 "Failed to decode {} frame: {err}",
85 match decoder_type {
86 Request => "request",
87 Response => "response",
88 }
89 );
90 drop_cnt += 1;
91 retry = true;
92 Ok(None)
93 });
94
95 if !retry {
96 return res;
97 }
98 }
99}
100
101#[allow(clippy::similar_names)]
103pub fn extract_frame(buf: &[u8], pdu_len: usize) -> Result<Option<DecodedFrame<'_>>> {
104 if buf.is_empty() {
105 return Err(Error::BufferSize);
106 }
107
108 let adu_len = 1 + pdu_len;
109 if buf.len() >= adu_len + 2 {
110 let (adu_buf, buf) = buf.split_at(adu_len);
111 let (crc_buf, _) = buf.split_at(2);
112 let expected_crc = BigEndian::read_u16(crc_buf);
114 let actual_crc = crc16(adu_buf);
115 if expected_crc != actual_crc {
116 return Err(Error::Crc(expected_crc, actual_crc));
117 }
118 let (slave_id, pdu_data) = adu_buf.split_at(1);
119 let slave_id = slave_id[0];
120 return Ok(Some(DecodedFrame {
121 slave: slave_id,
122 pdu: pdu_data,
123 }));
124 }
125 Ok(None)
127}
128
129#[must_use]
131pub fn crc16(data: &[u8]) -> u16 {
132 let mut crc = 0xFFFF;
133 for x in data {
134 crc ^= u16::from(*x);
135 for _ in 0..8 {
136 #[allow(clippy::branches_sharing_code)]
139 if (crc & 0x0001) != 0 {
140 crc >>= 1;
141 crc ^= 0xA001;
142 } else {
143 crc >>= 1;
144 }
145 }
146 }
147 crc.rotate_right(8)
148}
149
150pub const fn request_pdu_len(adu_buf: &[u8]) -> Result<Option<usize>> {
152 if adu_buf.len() < 2 {
153 return Ok(None);
154 }
155 let fn_code = adu_buf[1];
156 let len = match fn_code {
157 0x01..=0x06 => Some(5),
158 0x07 | 0x0B | 0x0C | 0x11 => Some(1),
159 0x0F | 0x10 => {
160 if adu_buf.len() > 4 {
161 Some(6 + adu_buf[4] as usize)
162 } else {
163 None
165 }
166 }
167 0x16 => Some(7),
168 0x18 => Some(3),
169 0x17 => {
170 if adu_buf.len() > 10 {
171 Some(10 + adu_buf[10] as usize)
172 } else {
173 None
175 }
176 }
177 _ => {
178 return Err(Error::FnCode(fn_code));
179 }
180 };
181 Ok(len)
182}
183
184pub fn response_pdu_len(adu_buf: &[u8]) -> Result<Option<usize>> {
186 if adu_buf.len() < 2 {
187 return Ok(None);
188 }
189 let fn_code = adu_buf[1];
190 let len = match fn_code {
191 0x01..=0x04 | 0x0C | 0x17 => {
192 if adu_buf.len() > 2 {
193 Some(2 + adu_buf[2] as usize)
194 } else {
195 None
197 }
198 }
199 0x05 | 0x06 | 0x0B | 0x0F | 0x10 => Some(5),
200 0x07 | 0x81..=0xAB => Some(2),
201 0x16 => Some(7),
202 0x18 => {
203 if adu_buf.len() > 3 {
204 Some(3 + BigEndian::read_u16(&adu_buf[2..=3]) as usize)
205 } else {
206 None
208 }
209 }
210 _ => return Err(Error::FnCode(fn_code)),
211 };
212 Ok(len)
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218
219 #[test]
220 fn test_calc_crc16() {
221 let msg = &[0x01, 0x03, 0x08, 0x2B, 0x00, 0x02];
222 assert_eq!(crc16(msg), 0xB663);
223
224 let msg = &[0x01, 0x03, 0x04, 0x00, 0x20, 0x00, 0x00];
225 assert_eq!(crc16(msg), 0xFBF9);
226 }
227
228 #[test]
229 fn test_request_pdu_len() {
230 let buf = &mut [0x66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
231 assert!(request_pdu_len(buf).is_err());
232
233 buf[1] = 0x01;
234 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
235
236 buf[1] = 0x02;
237 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
238
239 buf[1] = 0x03;
240 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
241
242 buf[1] = 0x04;
243 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
244
245 buf[1] = 0x05;
246 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
247
248 buf[1] = 0x06;
249 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
250
251 buf[1] = 0x07;
252 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
253
254 buf[1] = 0x0B;
257 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
258
259 buf[1] = 0x0C;
260 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
261
262 buf[1] = 0x0F;
263 buf[4] = 99;
264 assert_eq!(request_pdu_len(buf).unwrap(), Some(105));
265
266 buf[1] = 0x10;
267 buf[4] = 99;
268 assert_eq!(request_pdu_len(buf).unwrap(), Some(105));
269
270 buf[1] = 0x11;
271 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
272
273 buf[1] = 0x16;
278 assert_eq!(request_pdu_len(buf).unwrap(), Some(7));
279
280 buf[1] = 0x17;
281 buf[10] = 99; assert_eq!(request_pdu_len(buf).unwrap(), Some(109));
283
284 buf[1] = 0x18;
285 assert_eq!(request_pdu_len(buf).unwrap(), Some(3));
286
287 }
289
290 #[test]
291 fn test_get_response_pdu_len() {
292 let buf = &mut [0x66, 0x01, 99];
293 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
294
295 let buf = &mut [0x66, 0x00, 99, 0x00];
296 assert_eq!(response_pdu_len(buf).err().unwrap(), Error::FnCode(0));
297
298 let buf = &mut [0x66, 0xee, 99, 0x00];
299 assert_eq!(response_pdu_len(buf).err().unwrap(), Error::FnCode(0xee));
300
301 buf[1] = 0x01;
302 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
303
304 buf[1] = 0x02;
305 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
306
307 buf[1] = 0x03;
308 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
309
310 buf[1] = 0x04;
311 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
312
313 buf[1] = 0x05;
314 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
315
316 buf[1] = 0x06;
317 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
318
319 buf[1] = 0x07;
320 assert_eq!(response_pdu_len(buf).unwrap(), Some(2));
321
322 buf[1] = 0x0B;
325 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
326
327 buf[1] = 0x0C;
328 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
329
330 buf[1] = 0x0F;
331 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
332
333 buf[1] = 0x10;
334 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
335
336 buf[1] = 0x16;
343 assert_eq!(response_pdu_len(buf).unwrap(), Some(7));
344
345 buf[1] = 0x17;
346 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
347
348 buf[1] = 0x18;
349 buf[2] = 0x01; buf[3] = 0x00; assert_eq!(response_pdu_len(buf).unwrap(), Some(259));
352
353 for i in 0x81..0xAB {
356 buf[1] = i;
357 assert_eq!(response_pdu_len(buf).unwrap(), Some(2));
358 }
359 }
360
361 mod frame_decoder {
362
363 use super::*;
364
365 #[test]
366 fn extract_partly_received_rtu_frame() {
367 let buf = &[
368 0x12, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, ];
377 let pdu_len = request_pdu_len(buf).unwrap().unwrap();
378 let res = extract_frame(buf, pdu_len).unwrap();
379 assert!(res.is_none());
380 }
381
382 #[test]
383 fn extract_usual_rtu_response_frame() {
384 let buf = &[
385 0x01, 0x03, 0x04, 0x89, 0x02, 0x42, 0xC7, 0x00, 0x9D, 0x03, ];
396 let pdu_len = response_pdu_len(buf).unwrap().unwrap();
397 let DecodedFrame { slave, pdu } = extract_frame(buf, pdu_len).unwrap().unwrap();
398 assert_eq!(slave, 0x01);
399 assert_eq!(pdu.len(), 6);
400 }
401
402 #[test]
403 fn decode_rtu_response_drop_invalid_bytes() {
404 let buf = &[
405 0x42, 0x43, 0x01, 0x03, 0x04, 0x89, 0x02, 0x42, 0xC7, 0x00, 0x9D, 0x00,
417 ];
418 let (frame, location) = decode(DecoderType::Response, buf).unwrap().unwrap();
419 assert_eq!(frame.slave, 0x01);
420 assert_eq!(frame.pdu.len(), 6);
421 assert_eq!(location.start, 2);
422 assert_eq!(location.size, 9);
423 }
424
425 #[test]
426 fn decode_rtu_response_with_max_drops() {
427 let buf = &[0x42; 10];
428 assert!(decode(DecoderType::Response, buf).unwrap().is_none());
429
430 let buf = &mut [0x42; MAX_FRAME_LEN * 2];
431 buf[256] = 0x01; buf[257] = 0x03; buf[258] = 0x04; buf[259] = 0x89; buf[260] = 0x02; buf[261] = 0x42; buf[262] = 0xC7; buf[263] = 0x00; buf[264] = 0x9D; assert!(decode(DecoderType::Response, buf).is_err());
441 }
442 }
443}