1use super::*;
7use byteorder::{BigEndian, ByteOrder};
8
9pub mod client;
10pub mod server;
11pub use crate::frame::tcp::*;
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 transaction_id: TransactionId,
22 pub unit_id: UnitId,
23 pub pdu: &'a [u8],
24}
25
26#[cfg_attr(all(feature = "defmt", target_os = "none"), derive(defmt::Format))]
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub struct FrameLocation {
30 pub start: usize,
32 pub size: usize,
34}
35
36pub fn decode(
38 decoder_type: DecoderType,
39 buf: &[u8],
40) -> Result<Option<(DecodedFrame<'_>, FrameLocation)>> {
41 use DecoderType::{Request, Response};
42 let mut drop_cnt = 0;
43
44 if buf.is_empty() {
45 return Err(Error::BufferSize);
46 }
47
48 loop {
49 let mut retry = false;
50 if drop_cnt + 1 >= buf.len() {
51 return Ok(None);
52 }
53 let raw_frame = &buf[drop_cnt..];
54 let res = match decoder_type {
55 Request => request_pdu_len(raw_frame),
56 Response => response_pdu_len(raw_frame),
57 }
58 .and_then(|pdu_len| {
59 retry = false;
60 if let Some(pdu_len) = pdu_len {
61 extract_frame(raw_frame, pdu_len).map(|x| {
62 x.map(|res| {
63 (
64 res,
65 FrameLocation {
66 start: drop_cnt,
67 size: pdu_len + 7,
68 },
69 )
70 })
71 })
72 } else {
73 Ok(None)
75 }
76 })
77 .or_else(|err| {
78 if drop_cnt + 1 >= MAX_FRAME_LEN {
79 #[cfg(feature = "log")]
80 log::error!(
81 "Giving up to decode frame after dropping {drop_cnt} byte(s): {:X?}",
82 &buf[0..drop_cnt]
83 );
84 return Err(err);
85 }
86 #[cfg(feature = "log")]
87 log::warn!(
88 "Failed to decode {pdu_type} frame: {err}",
89 pdu_type = match decoder_type {
90 Request => "request",
91 Response => "response",
92 }
93 );
94 drop_cnt += 1;
95 retry = true;
96 Ok(None)
97 });
98
99 if !retry {
100 return res;
101 }
102 }
103}
104
105pub fn extract_frame(buf: &[u8], pdu_len: usize) -> Result<Option<DecodedFrame<'_>>> {
107 if buf.is_empty() {
108 return Err(Error::BufferSize);
109 }
110 let adu_len = 7 + pdu_len;
111 if buf.len() >= adu_len {
112 let (adu_buf, _next_frame) = buf.split_at(adu_len);
113 let (adu_buf, pdu_data) = adu_buf.split_at(7);
114 let (transaction_buf, adu_buf) = adu_buf.split_at(2);
115 let (protocol_buf, adu_buf) = adu_buf.split_at(2);
116 let (length_buf, adu_buf) = adu_buf.split_at(2);
117 let protocol_id = BigEndian::read_u16(protocol_buf);
118 if protocol_id != 0 {
119 return Err(Error::ProtocolNotModbus(protocol_id));
120 }
121 let transaction = BigEndian::read_u16(transaction_buf);
122 let m_length = BigEndian::read_u16(length_buf) as usize;
123 let unit = adu_buf[0];
124 if m_length != pdu_len + 1 {
125 return Err(Error::LengthMismatch(m_length, pdu_len + 1));
126 }
127 return Ok(Some(DecodedFrame {
128 transaction_id: transaction,
129 unit_id: unit,
130 pdu: pdu_data,
131 }));
132 }
133 Ok(None)
135}
136
137pub const fn request_pdu_len(adu_buf: &[u8]) -> Result<Option<usize>> {
139 if adu_buf.len() < 8 {
140 return Ok(None);
141 }
142 let fn_code = adu_buf[7];
143 let len = match fn_code {
144 0x01..=0x06 => Some(5),
145 0x07 | 0x0B | 0x0C | 0x11 => Some(1),
146 0x0F | 0x10 => {
147 if adu_buf.len() > 10 {
148 Some(6 + adu_buf[12] as usize)
149 } else {
150 None
152 }
153 }
154 0x16 => Some(7),
155 0x18 => Some(3),
156 0x17 => {
157 if adu_buf.len() > 16 {
158 Some(10 + adu_buf[16] as usize)
159 } else {
160 None
162 }
163 }
164 _ => {
165 return Err(Error::FnCode(fn_code));
166 }
167 };
168 Ok(len)
169}
170
171pub fn response_pdu_len(adu_buf: &[u8]) -> Result<Option<usize>> {
173 if adu_buf.len() < 8 {
174 return Ok(None);
175 }
176 let fn_code = adu_buf[7];
177 let len = match fn_code {
178 0x01..=0x04 | 0x0C | 0x17 => {
179 if adu_buf.len() > 8 {
180 Some(2 + adu_buf[8] as usize)
181 } else {
182 None
184 }
185 }
186 0x05 | 0x06 | 0x0B | 0x0F | 0x10 => Some(5),
187 0x07 | 0x81..=0xAB => Some(2),
188 0x16 => Some(7),
189 0x18 => {
190 if adu_buf.len() > 9 {
191 Some(3 + BigEndian::read_u16(&adu_buf[8..=9]) as usize)
192 } else {
193 None
195 }
196 }
197 _ => return Err(Error::FnCode(fn_code)),
198 };
199 Ok(len)
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_request_pdu_len() {
208 let buf = &mut [0x66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
209 assert!(request_pdu_len(buf).is_err());
210
211 buf[7] = 0x01;
212 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
213
214 buf[7] = 0x02;
215 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
216
217 buf[7] = 0x03;
218 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
219
220 buf[7] = 0x04;
221 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
222
223 buf[7] = 0x05;
224 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
225
226 buf[7] = 0x06;
227 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
228
229 buf[7] = 0x07;
230 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
231
232 buf[7] = 0x0B;
235 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
236
237 buf[7] = 0x0C;
238 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
239
240 buf[7] = 0x0F;
241 buf[12] = 99;
242 assert_eq!(request_pdu_len(buf).unwrap(), Some(105));
243
244 buf[7] = 0x10;
245 buf[12] = 99;
246 assert_eq!(request_pdu_len(buf).unwrap(), Some(105));
247
248 buf[7] = 0x11;
249 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
250
251 buf[7] = 0x16;
256 assert_eq!(request_pdu_len(buf).unwrap(), Some(7));
257
258 buf[7] = 0x17;
259 buf[16] = 99; assert_eq!(request_pdu_len(buf).unwrap(), Some(109));
261
262 buf[7] = 0x18;
263 assert_eq!(request_pdu_len(buf).unwrap(), Some(3));
264
265 }
267
268 #[test]
269 fn test_get_response_pdu_len() {
270 let buf = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x01, 99];
271 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
272
273 let buf = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 99, 0x00];
274 assert_eq!(response_pdu_len(buf).err().unwrap(), Error::FnCode(0));
275
276 let buf = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xee, 99, 0x00];
277 assert_eq!(response_pdu_len(buf).err().unwrap(), Error::FnCode(0xee));
278
279 buf[7] = 0x01;
280 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
281
282 buf[7] = 0x02;
283 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
284
285 buf[7] = 0x03;
286 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
287
288 buf[7] = 0x04;
289 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
290
291 buf[7] = 0x05;
292 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
293
294 buf[7] = 0x06;
295 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
296
297 buf[7] = 0x07;
298 assert_eq!(response_pdu_len(buf).unwrap(), Some(2));
299
300 buf[7] = 0x0B;
303 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
304
305 buf[7] = 0x0C;
306 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
307
308 buf[7] = 0x0F;
309 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
310
311 buf[7] = 0x10;
312 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
313
314 buf[7] = 0x16;
321 assert_eq!(response_pdu_len(buf).unwrap(), Some(7));
322
323 buf[7] = 0x17;
324 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
325
326 buf[7] = 0x18;
327 buf[8] = 0x01; buf[9] = 0x00; assert_eq!(response_pdu_len(buf).unwrap(), Some(259));
330
331 for i in 0x81..0xAB {
334 buf[7] = i;
335 assert_eq!(response_pdu_len(buf).unwrap(), Some(2));
336 }
337 }
338
339 mod frame_decoder {
340
341 use super::*;
342
343 #[test]
344 fn extract_partly_received_tcp_frame() {
345 let buf = &[
346 0x01, 0x02, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x03, 0x00, 0x00, ];
359 let pdu_len = request_pdu_len(buf).unwrap().unwrap();
360 let res = extract_frame(buf, pdu_len).unwrap();
361 assert!(res.is_none());
362 }
363
364 #[test]
365 fn extract_usual_tcp_response_frame() {
366 let buf = &[
367 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x01, 0x03, 0x04, 0x89, 0x02, 0x42, 0xC7, 0x03, ];
382 let pdu_len = response_pdu_len(buf).unwrap().unwrap();
383 let DecodedFrame {
384 transaction_id,
385 unit_id,
386 pdu,
387 } = extract_frame(buf, pdu_len).unwrap().unwrap();
388 assert_eq!(transaction_id, 258);
389 assert_eq!(unit_id, 0x01);
390 assert_eq!(pdu.len(), 6);
391 }
392
393 #[test]
394 fn decode_tcp_response_drop_invalid_bytes() {
395 let buf = &[
396 0x42, 0x43, 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x01, 0x03, 0x04, 0x89, 0x02, 0x42, 0xC7, 0x00, ];
413 let (frame, location) = decode(DecoderType::Response, buf).unwrap().unwrap();
414 assert_eq!(frame.transaction_id, 258);
415 assert_eq!(frame.unit_id, 0x01);
416 assert_eq!(frame.pdu.len(), 6);
417 assert_eq!(location.start, 2);
418 assert_eq!(location.size, 13);
419 }
420
421 #[test]
422 fn decode_tcp_response_with_max_drops() {
423 let buf = &[0x42; 10];
424 assert!(decode(DecoderType::Response, buf).unwrap().is_none());
425
426 let buf = &mut [0x42; MAX_FRAME_LEN * 2];
427 buf[256] = 0x01; buf[257] = 0x03; buf[258] = 0x04; buf[259] = 0x89; buf[260] = 0x02; buf[261] = 0x42; buf[262] = 0xC7; assert!(decode(DecoderType::Response, buf).is_err());
435 }
436 }
437}