1use crate::types::RadarFrame;
2
3const DATA_HEADER: [u8; 4] = [0xAA, 0xFF, 0x03, 0x00];
5const DATA_FOOTER: [u8; 2] = [0x55, 0xCC];
7
8const PAYLOAD_LEN: usize = 24;
10#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum ParseEvent {
13 Frame(RadarFrame),
15}
16
17#[derive(Debug, Clone, Copy)]
19enum State {
20 SearchHeader { matched: u8 },
22 ReadPayload { pos: u8 },
24 ReadFooter { matched: u8 },
26}
27
28#[derive(Debug)]
35pub struct FrameParser {
36 state: State,
37 buf: [u8; PAYLOAD_LEN],
38}
39
40impl FrameParser {
41 pub fn new() -> Self {
42 Self {
43 state: State::SearchHeader { matched: 0 },
44 buf: [0u8; PAYLOAD_LEN],
45 }
46 }
47
48 #[inline]
51 pub fn feed(&mut self, byte: u8) -> Option<ParseEvent> {
52 match self.state {
53 State::SearchHeader { matched } => {
54 if byte == DATA_HEADER[matched as usize] {
55 let next = matched + 1;
56 if next as usize == DATA_HEADER.len() {
57 self.state = State::ReadPayload { pos: 0 };
58 } else {
59 self.state = State::SearchHeader { matched: next };
60 }
61 } else if byte == DATA_HEADER[0] {
62 self.state = State::SearchHeader { matched: 1 };
64 } else {
65 self.state = State::SearchHeader { matched: 0 };
66 }
67 None
68 }
69 State::ReadPayload { pos } => {
70 self.buf[pos as usize] = byte;
71 let next = pos + 1;
72 if next as usize == PAYLOAD_LEN {
73 self.state = State::ReadFooter { matched: 0 };
74 } else {
75 self.state = State::ReadPayload { pos: next };
76 }
77 None
78 }
79 State::ReadFooter { matched } => {
80 if byte == DATA_FOOTER[matched as usize] {
81 let next = matched + 1;
82 if next as usize == DATA_FOOTER.len() {
83 self.state = State::SearchHeader { matched: 0 };
85 let frame = RadarFrame::from_bytes(&self.buf);
86 return Some(ParseEvent::Frame(frame));
87 } else {
88 self.state = State::ReadFooter { matched: next };
89 }
90 } else {
91 self.state = State::SearchHeader { matched: 0 };
93 }
94 None
95 }
96 }
97 }
98
99 #[cfg(feature = "std")]
103 pub fn feed_slice(&mut self, data: &[u8]) -> Vec<ParseEvent> {
104 let mut events = Vec::new();
105 for &b in data {
106 if let Some(ev) = self.feed(b) {
107 events.push(ev);
108 }
109 }
110 events
111 }
112}
113
114impl Default for FrameParser {
115 fn default() -> Self {
116 Self::new()
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 fn make_frame(payload: &[u8; 24]) -> Vec<u8> {
125 let mut frame = Vec::with_capacity(30);
126 frame.extend_from_slice(&DATA_HEADER);
127 frame.extend_from_slice(payload);
128 frame.extend_from_slice(&DATA_FOOTER);
129 frame
130 }
131
132 #[test]
133 fn parse_datasheet_example() {
134 let raw: [u8; 30] = [
136 0xAA, 0xFF, 0x03, 0x00, 0x0E, 0x03, 0xB1, 0x86, 0x10, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xCC, ];
142
143 let mut parser = FrameParser::new();
144 let events = parser.feed_slice(&raw);
145 assert_eq!(events.len(), 1);
146
147 let ParseEvent::Frame(frame) = &events[0];
148 assert_eq!(frame.targets[0].x, -782);
149 assert_eq!(frame.targets[0].y, 1713);
150 assert_eq!(frame.targets[0].speed, -16);
151 assert_eq!(frame.targets[0].distance_resolution, 320);
152 assert!(frame.targets[1].is_empty());
153 assert!(frame.targets[2].is_empty());
154 assert_eq!(frame.active_count(), 1);
155 }
156
157 #[test]
158 fn parse_with_garbage_prefix() {
159 let mut data = vec![0xFF, 0x00, 0x42, 0x13]; let mut payload = [0u8; 24];
161 payload[..8].copy_from_slice(&[0x0E, 0x03, 0xB1, 0x86, 0x10, 0x00, 0x40, 0x01]);
162 data.extend_from_slice(&make_frame(&payload));
163
164 let mut parser = FrameParser::new();
165 let events = parser.feed_slice(&data);
166 assert_eq!(events.len(), 1);
167 }
168
169 #[test]
170 fn parse_multiple_frames() {
171 let mut payload = [0u8; 24];
172 payload[..8].copy_from_slice(&[0x0E, 0x03, 0xB1, 0x86, 0x10, 0x00, 0x40, 0x01]);
173 let frame = make_frame(&payload);
174
175 let mut data = Vec::new();
176 data.extend_from_slice(&frame);
177 data.extend_from_slice(&frame);
178 data.extend_from_slice(&frame);
179
180 let mut parser = FrameParser::new();
181 let events = parser.feed_slice(&data);
182 assert_eq!(events.len(), 3);
183 }
184
185 #[test]
186 fn bad_footer_resyncs() {
187 let mut data = Vec::new();
188 data.extend_from_slice(&DATA_HEADER);
190 data.extend_from_slice(&[0u8; 24]);
191 data.extend_from_slice(&[0x55, 0xDD]); let mut payload = [0u8; 24];
195 payload[..8].copy_from_slice(&[0x0E, 0x03, 0xB1, 0x86, 0x10, 0x00, 0x40, 0x01]);
196 data.extend_from_slice(&make_frame(&payload));
197
198 let mut parser = FrameParser::new();
199 let events = parser.feed_slice(&data);
200 assert_eq!(events.len(), 1); }
202
203 #[test]
204 fn byte_by_byte_feeding() {
205 let mut payload = [0u8; 24];
206 payload[..8].copy_from_slice(&[0x0E, 0x03, 0xB1, 0x86, 0x10, 0x00, 0x40, 0x01]);
207 let data = make_frame(&payload);
208
209 let mut parser = FrameParser::new();
210 let mut events = Vec::new();
211 for &b in &data {
212 if let Some(ev) = parser.feed(b) {
213 events.push(ev);
214 }
215 }
216 assert_eq!(events.len(), 1);
217 }
218}