use crate::cmd::TMiniPlusCmd;
pub trait LidarCommands {
type Header;
fn start_scan_cmd() -> &'static [u8; 2];
fn stop_scan_cmd() -> &'static [u8; 2];
fn get_info_cmd() -> &'static [u8; 2];
}
#[derive(Debug, Clone, Copy)]
pub struct TMiniPlus;
impl LidarCommands for TMiniPlus {
type Header = TMiniHeader;
fn start_scan_cmd() -> &'static [u8; 2] {
TMiniPlusCmd::START_SCAN.as_cmd()
}
fn stop_scan_cmd() -> &'static [u8; 2] {
TMiniPlusCmd::STOP_SCAN.as_cmd()
}
fn get_info_cmd() -> &'static [u8; 2] {
TMiniPlusCmd::GET_INFO.as_cmd()
}
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct TMiniHeader {
pub header: u16,
pub ct: u8,
pub lsn: u8,
pub fsa: u16,
pub lsa: u16,
pub cs: u16,
}
impl TMiniHeader {
pub fn from_bytes(data: &[u8]) -> Option<Self> {
if data.len() < 10 {
return None;
}
Some(TMiniHeader {
header: u16::from_le_bytes([data[0], data[1]]),
ct: data[2],
lsn: data[3],
fsa: u16::from_le_bytes([data[4], data[5]]),
lsa: u16::from_le_bytes([data[6], data[7]]),
cs: u16::from_le_bytes([data[8], data[9]]),
})
}
pub fn is_valid(&self) -> bool {
self.header == 0x55AA }
pub fn scan_frequency(&self) -> f32 {
match self.ct & 0x03 {
0 => 5.0,
1 => 8.0,
2 => 10.0,
_ => 0.0,
}
}
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct SampleNode {
pub intensity: u8,
pub distance_low: u8,
pub distance_high_and_flag: u8,
}
impl SampleNode {
pub fn distance(&self) -> u16 {
((self.distance_high_and_flag as u16) << 6) | ((self.distance_low as u16) >> 2)
}
pub fn is_invalid(&self) -> bool {
(self.distance_high_and_flag & 0x80) != 0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tmini_header_parsing() {
let data = [0x55, 0xAA, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let header = TMiniHeader::from_bytes(&data).unwrap();
assert!(header.is_valid());
assert_eq!(header.lsn, 1);
}
#[test]
fn test_sample_node_distance() {
let sample = SampleNode {
intensity: 100,
distance_low: 0x34,
distance_high_and_flag: 0x12,
};
assert_eq!(sample.distance(), 0x1234);
assert!(!sample.is_invalid());
}
}