1use super::*;
4use byteorder::{BigEndian, ByteOrder};
5
6pub mod server;
7pub use crate::frame::tcp::*;
8
9const MAX_FRAME_LEN: usize = 256;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct DecodedFrame<'a> {
16 pub transaction_id: TransactionId,
17 pub unit_id: UnitId,
18 pub pdu: &'a [u8],
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub struct FrameLocation {
24 pub start: usize,
26 pub size: usize,
28}
29
30pub fn decode(
32 decoder_type: DecoderType,
33 buf: &[u8],
34) -> Result<Option<(DecodedFrame, FrameLocation)>> {
35 use DecoderType::{Request, Response};
36 let mut drop_cnt = 0;
37
38 if buf.is_empty() {
39 return Err(Error::BufferSize);
40 }
41
42 loop {
43 let mut retry = false;
44 if drop_cnt + 1 >= buf.len() {
45 return Ok(None);
46 }
47 let raw_frame = &buf[drop_cnt..];
48 let res = match decoder_type {
49 Request => request_pdu_len(raw_frame),
50 Response => response_pdu_len(raw_frame),
51 }
52 .and_then(|pdu_len| {
53 retry = false;
54 if let Some(pdu_len) = pdu_len {
55 extract_frame(raw_frame, pdu_len).map(|x| {
56 x.map(|res| {
57 (
58 res,
59 FrameLocation {
60 start: drop_cnt,
61 size: pdu_len + 7,
62 },
63 )
64 })
65 })
66 } else {
67 Ok(None)
69 }
70 })
71 .or_else(|err| {
72 let pdu_type = match decoder_type {
73 Request => "request",
74 Response => "response",
75 };
76 if drop_cnt + 1 >= MAX_FRAME_LEN {
77 log::error!(
78 "Giving up to decode frame after dropping {drop_cnt} byte(s): {:X?}",
79 &buf[0..drop_cnt]
80 );
81 return Err(err);
82 }
83 log::warn!("Failed to decode {pdu_type} frame: {err}");
84 drop_cnt += 1;
85 retry = true;
86 Ok(None)
87 });
88
89 if !retry {
90 return res;
91 }
92 }
93}
94
95pub fn extract_frame(buf: &[u8], pdu_len: usize) -> Result<Option<DecodedFrame>> {
97 if buf.is_empty() {
98 return Err(Error::BufferSize);
99 }
100 let adu_len = 7 + pdu_len;
101 if buf.len() >= adu_len {
102 let (adu_buf, _next_frame) = buf.split_at(adu_len);
103 let (adu_buf, pdu_data) = adu_buf.split_at(7);
104 let (transaction_buf, adu_buf) = adu_buf.split_at(2);
105 let (protocol_buf, adu_buf) = adu_buf.split_at(2);
106 let (length_buf, adu_buf) = adu_buf.split_at(2);
107 let protocol_id = BigEndian::read_u16(protocol_buf);
108 if protocol_id != 0 {
109 return Err(Error::ProtocolNotModbus(protocol_id));
110 }
111 let transaction = BigEndian::read_u16(transaction_buf);
112 let m_length = BigEndian::read_u16(length_buf) as usize;
113 let unit = adu_buf[0];
114 if m_length != pdu_len + 1 {
115 return Err(Error::LengthMismatch(m_length, pdu_len + 1));
116 }
117 return Ok(Some(DecodedFrame {
118 transaction_id: transaction,
119 unit_id: unit,
120 pdu: pdu_data,
121 }));
122 }
123 Ok(None)
125}
126
127pub const fn request_pdu_len(adu_buf: &[u8]) -> Result<Option<usize>> {
129 if adu_buf.len() < 8 {
130 return Ok(None);
131 }
132 let fn_code = adu_buf[7];
133 let len = match fn_code {
134 0x01..=0x06 => Some(5),
135 0x07 | 0x0B | 0x0C | 0x11 => Some(1),
136 0x0F | 0x10 => {
137 if adu_buf.len() > 10 {
138 Some(6 + adu_buf[12] as usize)
139 } else {
140 None
142 }
143 }
144 0x16 => Some(7),
145 0x18 => Some(3),
146 0x17 => {
147 if adu_buf.len() > 16 {
148 Some(10 + adu_buf[16] as usize)
149 } else {
150 None
152 }
153 }
154 _ => {
155 return Err(Error::FnCode(fn_code));
156 }
157 };
158 Ok(len)
159}
160
161pub fn response_pdu_len(adu_buf: &[u8]) -> Result<Option<usize>> {
163 if adu_buf.len() < 8 {
164 return Ok(None);
165 }
166 let fn_code = adu_buf[7];
167 let len = match fn_code {
168 0x01..=0x04 | 0x0C | 0x17 => {
169 if adu_buf.len() > 8 {
170 Some(2 + adu_buf[8] as usize)
171 } else {
172 None
174 }
175 }
176 0x05 | 0x06 | 0x0B | 0x0F | 0x10 => Some(5),
177 0x07 | 0x81..=0xAB => Some(2),
178 0x16 => Some(7),
179 0x18 => {
180 if adu_buf.len() > 9 {
181 Some(3 + BigEndian::read_u16(&adu_buf[8..=9]) as usize)
182 } else {
183 None
185 }
186 }
187 _ => return Err(Error::FnCode(fn_code)),
188 };
189 Ok(len)
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195
196 #[test]
197 fn test_request_pdu_len() {
198 let buf = &mut [0x66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
199 assert!(request_pdu_len(buf).is_err());
200
201 buf[7] = 0x01;
202 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
203
204 buf[7] = 0x02;
205 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
206
207 buf[7] = 0x03;
208 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
209
210 buf[7] = 0x04;
211 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
212
213 buf[7] = 0x05;
214 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
215
216 buf[7] = 0x06;
217 assert_eq!(request_pdu_len(buf).unwrap(), Some(5));
218
219 buf[7] = 0x07;
220 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
221
222 buf[7] = 0x0B;
225 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
226
227 buf[7] = 0x0C;
228 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
229
230 buf[7] = 0x0F;
231 buf[12] = 99;
232 assert_eq!(request_pdu_len(buf).unwrap(), Some(105));
233
234 buf[7] = 0x10;
235 buf[12] = 99;
236 assert_eq!(request_pdu_len(buf).unwrap(), Some(105));
237
238 buf[7] = 0x11;
239 assert_eq!(request_pdu_len(buf).unwrap(), Some(1));
240
241 buf[7] = 0x16;
246 assert_eq!(request_pdu_len(buf).unwrap(), Some(7));
247
248 buf[7] = 0x17;
249 buf[16] = 99; assert_eq!(request_pdu_len(buf).unwrap(), Some(109));
251
252 buf[7] = 0x18;
253 assert_eq!(request_pdu_len(buf).unwrap(), Some(3));
254
255 }
257
258 #[test]
259 fn test_get_response_pdu_len() {
260 let buf = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x01, 99];
261 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
262
263 let buf = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 99, 0x00];
264 assert_eq!(response_pdu_len(buf).err().unwrap(), Error::FnCode(0));
265
266 let buf = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xee, 99, 0x00];
267 assert_eq!(response_pdu_len(buf).err().unwrap(), Error::FnCode(0xee));
268
269 buf[7] = 0x01;
270 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
271
272 buf[7] = 0x02;
273 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
274
275 buf[7] = 0x03;
276 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
277
278 buf[7] = 0x04;
279 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
280
281 buf[7] = 0x05;
282 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
283
284 buf[7] = 0x06;
285 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
286
287 buf[7] = 0x07;
288 assert_eq!(response_pdu_len(buf).unwrap(), Some(2));
289
290 buf[7] = 0x0B;
293 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
294
295 buf[7] = 0x0C;
296 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
297
298 buf[7] = 0x0F;
299 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
300
301 buf[7] = 0x10;
302 assert_eq!(response_pdu_len(buf).unwrap(), Some(5));
303
304 buf[7] = 0x16;
311 assert_eq!(response_pdu_len(buf).unwrap(), Some(7));
312
313 buf[7] = 0x17;
314 assert_eq!(response_pdu_len(buf).unwrap(), Some(101));
315
316 buf[7] = 0x18;
317 buf[8] = 0x01; buf[9] = 0x00; assert_eq!(response_pdu_len(buf).unwrap(), Some(259));
320
321 for i in 0x81..0xAB {
324 buf[7] = i;
325 assert_eq!(response_pdu_len(buf).unwrap(), Some(2));
326 }
327 }
328
329 mod frame_decoder {
330
331 use super::*;
332
333 #[test]
334 fn extract_partly_received_tcp_frame() {
335 let buf = &[
336 0x01, 0x02, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x03, 0x00, 0x00, ];
349 let pdu_len = request_pdu_len(buf).unwrap().unwrap();
350 let res = extract_frame(buf, pdu_len).unwrap();
351 assert!(res.is_none());
352 }
353
354 #[test]
355 fn extract_usual_tcp_response_frame() {
356 let buf = &[
357 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x01, 0x03, 0x04, 0x89, 0x02, 0x42, 0xC7, 0x03, ];
372 let pdu_len = response_pdu_len(buf).unwrap().unwrap();
373 let DecodedFrame {
374 transaction_id,
375 unit_id,
376 pdu,
377 } = extract_frame(buf, pdu_len).unwrap().unwrap();
378 assert_eq!(transaction_id, 258);
379 assert_eq!(unit_id, 0x01);
380 assert_eq!(pdu.len(), 6);
381 }
382
383 #[test]
384 fn decode_tcp_response_drop_invalid_bytes() {
385 let buf = &[
386 0x42, 0x43, 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x01, 0x03, 0x04, 0x89, 0x02, 0x42, 0xC7, 0x00, ];
403 let (frame, location) = decode(DecoderType::Response, buf).unwrap().unwrap();
404 assert_eq!(frame.transaction_id, 258);
405 assert_eq!(frame.unit_id, 0x01);
406 assert_eq!(frame.pdu.len(), 6);
407 assert_eq!(location.start, 2);
408 assert_eq!(location.size, 13);
409 }
410
411 #[test]
412 fn decode_tcp_response_with_max_drops() {
413 let buf = &[0x42; 10];
414 assert!(decode(DecoderType::Response, buf).unwrap().is_none());
415
416 let buf = &mut [0x42; MAX_FRAME_LEN * 2];
417 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());
425 }
426 }
427}