Skip to main content

kble_tfsync/
lib.rs

1use bytes::{Buf, Bytes, BytesMut};
2use tokio_util::codec::Decoder;
3use tracing::warn;
4
5const FRAME_SIZE: usize = 444;
6// Version Number: 2'b01
7// Rest          : 6'bXXXXXX
8const HEADER_MASK: u8 = 0b1100_0000;
9const HEADER_PATTERN: u8 = 0b0100_0000;
10// Control Word Type: 1'b1
11// CLCW Version     : 2'b00
12// Status Field     : 3'bXXX
13// COP in Effect    : 2'b01
14// VCID             : 6'b000000
15// Spare            : 2'b00
16const 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                // insufficient buffer
65                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}