use crate::types::RadarFrame;
const DATA_HEADER: [u8; 4] = [0xAA, 0xFF, 0x03, 0x00];
const DATA_FOOTER: [u8; 2] = [0x55, 0xCC];
const PAYLOAD_LEN: usize = 24;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseEvent {
Frame(RadarFrame),
}
#[derive(Debug, Clone, Copy)]
enum State {
SearchHeader { matched: u8 },
ReadPayload { pos: u8 },
ReadFooter { matched: u8 },
}
#[derive(Debug)]
pub struct FrameParser {
state: State,
buf: [u8; PAYLOAD_LEN],
}
impl FrameParser {
pub fn new() -> Self {
Self {
state: State::SearchHeader { matched: 0 },
buf: [0u8; PAYLOAD_LEN],
}
}
#[inline]
pub fn feed(&mut self, byte: u8) -> Option<ParseEvent> {
match self.state {
State::SearchHeader { matched } => {
if byte == DATA_HEADER[matched as usize] {
let next = matched + 1;
if next as usize == DATA_HEADER.len() {
self.state = State::ReadPayload { pos: 0 };
} else {
self.state = State::SearchHeader { matched: next };
}
} else if byte == DATA_HEADER[0] {
self.state = State::SearchHeader { matched: 1 };
} else {
self.state = State::SearchHeader { matched: 0 };
}
None
}
State::ReadPayload { pos } => {
self.buf[pos as usize] = byte;
let next = pos + 1;
if next as usize == PAYLOAD_LEN {
self.state = State::ReadFooter { matched: 0 };
} else {
self.state = State::ReadPayload { pos: next };
}
None
}
State::ReadFooter { matched } => {
if byte == DATA_FOOTER[matched as usize] {
let next = matched + 1;
if next as usize == DATA_FOOTER.len() {
self.state = State::SearchHeader { matched: 0 };
let frame = RadarFrame::from_bytes(&self.buf);
return Some(ParseEvent::Frame(frame));
} else {
self.state = State::ReadFooter { matched: next };
}
} else {
self.state = State::SearchHeader { matched: 0 };
}
None
}
}
}
#[cfg(feature = "std")]
pub fn feed_slice(&mut self, data: &[u8]) -> Vec<ParseEvent> {
let mut events = Vec::new();
for &b in data {
if let Some(ev) = self.feed(b) {
events.push(ev);
}
}
events
}
}
impl Default for FrameParser {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_frame(payload: &[u8; 24]) -> Vec<u8> {
let mut frame = Vec::with_capacity(30);
frame.extend_from_slice(&DATA_HEADER);
frame.extend_from_slice(payload);
frame.extend_from_slice(&DATA_FOOTER);
frame
}
#[test]
fn parse_datasheet_example() {
let raw: [u8; 30] = [
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, ];
let mut parser = FrameParser::new();
let events = parser.feed_slice(&raw);
assert_eq!(events.len(), 1);
let ParseEvent::Frame(frame) = &events[0];
assert_eq!(frame.targets[0].x, -782);
assert_eq!(frame.targets[0].y, 1713);
assert_eq!(frame.targets[0].speed, -16);
assert_eq!(frame.targets[0].distance_resolution, 320);
assert!(frame.targets[1].is_empty());
assert!(frame.targets[2].is_empty());
assert_eq!(frame.active_count(), 1);
}
#[test]
fn parse_with_garbage_prefix() {
let mut data = vec![0xFF, 0x00, 0x42, 0x13]; let mut payload = [0u8; 24];
payload[..8].copy_from_slice(&[0x0E, 0x03, 0xB1, 0x86, 0x10, 0x00, 0x40, 0x01]);
data.extend_from_slice(&make_frame(&payload));
let mut parser = FrameParser::new();
let events = parser.feed_slice(&data);
assert_eq!(events.len(), 1);
}
#[test]
fn parse_multiple_frames() {
let mut payload = [0u8; 24];
payload[..8].copy_from_slice(&[0x0E, 0x03, 0xB1, 0x86, 0x10, 0x00, 0x40, 0x01]);
let frame = make_frame(&payload);
let mut data = Vec::new();
data.extend_from_slice(&frame);
data.extend_from_slice(&frame);
data.extend_from_slice(&frame);
let mut parser = FrameParser::new();
let events = parser.feed_slice(&data);
assert_eq!(events.len(), 3);
}
#[test]
fn bad_footer_resyncs() {
let mut data = Vec::new();
data.extend_from_slice(&DATA_HEADER);
data.extend_from_slice(&[0u8; 24]);
data.extend_from_slice(&[0x55, 0xDD]);
let mut payload = [0u8; 24];
payload[..8].copy_from_slice(&[0x0E, 0x03, 0xB1, 0x86, 0x10, 0x00, 0x40, 0x01]);
data.extend_from_slice(&make_frame(&payload));
let mut parser = FrameParser::new();
let events = parser.feed_slice(&data);
assert_eq!(events.len(), 1); }
#[test]
fn byte_by_byte_feeding() {
let mut payload = [0u8; 24];
payload[..8].copy_from_slice(&[0x0E, 0x03, 0xB1, 0x86, 0x10, 0x00, 0x40, 0x01]);
let data = make_frame(&payload);
let mut parser = FrameParser::new();
let mut events = Vec::new();
for &b in &data {
if let Some(ev) = parser.feed(b) {
events.push(ev);
}
}
assert_eq!(events.len(), 1);
}
}