1use bytes::{Buf, Bytes, BytesMut};
2use tokio_util::codec::Decoder;
3use tracing::warn;
4
5const FRAME_SIZE: usize = 444;
6const HEADER_MASK: u8 = 0b1100_0000;
9const HEADER_PATTERN: u8 = 0b0100_0000;
10const TRAILER_SIZE: usize = 4;
17const TRAILER_MASK: [u8; 2] = [0b1110_0011, 0b1111_1111];
18const TRAILER_PATTERN: [u8; 2] = [0b00000001, 0b00000000];
19
20#[derive(Debug, Default)]
21pub struct AosTransferFrameCodec {
22 buf: BytesMut,
23}
24
25impl AosTransferFrameCodec {
26 pub fn new() -> Self {
27 Self::default()
28 }
29}
30
31impl AosTransferFrameCodec {
32 fn find_primary_header(&self) -> Option<usize> {
33 self.buf
34 .iter()
35 .position(|b| *b & HEADER_MASK == HEADER_PATTERN)
36 }
37
38 fn is_trailer_matched(&self) -> bool {
39 let trailer_pos = FRAME_SIZE - TRAILER_SIZE;
40 let trailer_bytes = [self.buf[trailer_pos], self.buf[trailer_pos + 1]];
41 trailer_bytes
42 .iter()
43 .zip(TRAILER_MASK.iter().zip(TRAILER_PATTERN))
44 .all(|(b, (mask, pattern))| b & mask == pattern)
45 }
46}
47
48impl Decoder for AosTransferFrameCodec {
49 type Item = Bytes;
50 type Error = anyhow::Error;
51
52 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
53 self.buf.extend_from_slice(src);
54 src.clear();
55 if self.buf.is_empty() {
56 return Ok(None);
57 }
58 while let Some(ph_pos) = self.find_primary_header() {
59 if ph_pos > 0 {
60 warn!("Leading junk data: {:02x?}", &self.buf[..ph_pos]);
61 self.buf.advance(ph_pos);
62 }
63 if self.buf.len() < FRAME_SIZE {
64 return Ok(None);
66 }
67 if self.is_trailer_matched() {
68 let frame = self.buf.split_to(FRAME_SIZE);
69 return Ok(Some(frame.into()));
70 } else {
71 warn!("Trailer mismatched: {:02x?}", &self.buf[..FRAME_SIZE]);
72 self.buf.advance(1);
73 }
74 }
75 warn!("No primary header found in {} bytes", self.buf.len());
76 self.buf.clear();
77 Ok(None)
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use bytes::BytesMut;
84
85 use super::*;
86 const TRANSFER_FRAME: [u8; 444] = [
87 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x10, 0xc0, 0x00, 0x01, 0xa9, 0x00,
88 0x00, 0x00, 0x00, 0x0b, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x3f, 0xf1, 0xb2, 0x2d, 0x0e, 0x56, 0x04,
90 0x19, 0x01, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
94 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
101 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x73, 0x64, 0x64, 0x64, 0x64,
103 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
117 ];
118
119 #[test]
120 fn test_complete_frame() {
121 let mut codec = AosTransferFrameCodec::new();
122 let mut complete_bytes = BytesMut::from(&TRANSFER_FRAME[..]);
123 let actual = codec.decode(&mut complete_bytes).unwrap().unwrap();
124 assert_eq!(actual, TRANSFER_FRAME.as_slice());
125 let actual = codec.decode(&mut BytesMut::new()).unwrap();
126 assert_eq!(actual, None);
127 }
128
129 #[test]
130 fn test_incomplete_frame() {
131 let mut codec = AosTransferFrameCodec::new();
132 let mut tail = BytesMut::from(&TRANSFER_FRAME[..]);
133 let mut head = tail.split_to(220);
134 assert_eq!(codec.decode(&mut head).unwrap(), None);
135 assert_eq!(
136 codec.decode(&mut tail).unwrap().unwrap(),
137 TRANSFER_FRAME.as_slice()
138 );
139 assert_eq!(codec.decode(&mut BytesMut::new()).unwrap(), None);
140 }
141
142 #[test]
143 fn test_contiguous_frame() {
144 let mut codec = AosTransferFrameCodec::new();
145 let mut double_frames = BytesMut::from(&TRANSFER_FRAME[..]);
146 double_frames.extend_from_slice(&TRANSFER_FRAME[..]);
147 let actual = codec.decode(&mut double_frames).unwrap().unwrap();
148 assert_eq!(actual, TRANSFER_FRAME.as_slice());
149 let actual = codec.decode(&mut BytesMut::new()).unwrap().unwrap();
150 assert_eq!(actual, TRANSFER_FRAME.as_slice());
151 let actual = codec.decode(&mut BytesMut::new()).unwrap();
152 assert_eq!(actual, None);
153 }
154
155 #[test]
156 fn test_leading_junk_data() {
157 let mut codec = AosTransferFrameCodec::new();
158 let mut input = BytesMut::from(&b"JUNKDATA"[..]);
159 input.extend_from_slice(&TRANSFER_FRAME[..]);
160 assert_eq!(
161 codec.decode(&mut input).unwrap().unwrap(),
162 TRANSFER_FRAME.as_slice()
163 );
164 assert_eq!(codec.decode(&mut BytesMut::new()).unwrap(), None);
165 }
166}