pub use crate::scan_types::*;
use byteorder::ByteOrder;
use crate::crc::crc8;
use crate::error::ParseError;
use embedded_hal::serial::Read;
use nb::{Error, Result};
use pid::Pid;
pub struct LD06<R: Read<u8>> {
reader: R,
wip_scan: [u8; 47],
packet_idx: u8,
}
impl<R: Read<u8>> LD06<R> {
pub fn new(reader: R) -> Self {
LD06 {
reader,
wip_scan: [0u8; 47],
packet_idx: 0,
}
}
pub fn read_next_byte(&mut self) -> Result<Option<PartialScan>, ParseError<R::Error>> {
let byte = self.reader.read();
if let Err(err) = byte {
return match err {
Error::Other(err) => Err(Error::Other(ParseError::SerialErr(err))),
Error::WouldBlock => Ok(None),
};
}
let byte = unsafe { byte.unwrap_unchecked() };
if byte == 0x54 && self.packet_idx != 0 {
self.packet_idx = 0;
}
self.wip_scan[self.packet_idx as usize] = byte;
self.packet_idx += 1;
if self.packet_idx == 47 {
self.packet_idx = 0;
if crc8(&self.wip_scan[0..=46]) != 0 {
return Err(nb::Error::Other(ParseError::CrcFail));
}
let mut packet = PartialScan::default();
let buf = &self.wip_scan;
packet.radar_speed = byteorder::LE::read_u16(&buf[2..=3]);
packet.start_angle = byteorder::LE::read_u16(&buf[4..=5]) as f32 / 100.0;
for (i, range) in buf[6..12 * 3 + 6 ].chunks(3).enumerate() {
packet.data[i].dist = byteorder::LE::read_u16(&range[0..=1]);
packet.data[i].confidence = range[2];
}
packet.end_angle = byteorder::LE::read_u16(&buf[42..=43]) as f32 / 100.0;
packet.stamp = byteorder::LE::read_u16(&buf[44..=45]);
packet.crc = buf[46];
Ok(Some(packet))
} else {
Ok(None)
}
}
pub fn into_pid(self) -> LD06Pid<R> {
let pid = Pid::new(10.0f32, 2.0, 2.0, 500.0, 500.0, 500.0, 14_400.0, 3600.0);
LD06Pid { inner: self, pid }
}
}
pub struct LD06Pid<R: Read<u8>> {
inner: LD06<R>,
pid: Pid<f32>,
}
impl<R: Read<u8>> LD06Pid<R> {
pub fn read_next_byte(&mut self) -> Result<Option<(PartialScan, u16)>, ParseError<R::Error>> {
let res = self.inner.read_next_byte()?;
if let Some(scan) = res {
let out = self.pid.next_control_output(scan.radar_speed as f32);
Ok(Some((scan, out.output as u16)))
} else {
Ok(None)
}
}
pub fn get_max_lidar_speed(&self) -> u16 {
14400 }
}
#[cfg(test)]
mod test {
extern crate std;
use crate::{Range, LD06};
use embedded_hal_mock::serial::{Mock, Transaction};
use std::prelude::rust_2021::*;
const REF_BYTES: &[u8] = &[
0x54, 0x2C, 0x68, 0x08, 0xAB, 0x7E, 0xE0, 0x00, 0xE4, 0xDC, 0x00, 0xE2, 0xD9, 0x00, 0xE5,
0xD5, 0x00, 0xE3, 0xD3, 0x00, 0xE4, 0xD0, 0x00, 0xE9, 0xCD, 0x00, 0xE4, 0xCA, 0x00, 0xE2,
0xC7, 0x00, 0xE9, 0xC5, 0x00, 0xE5, 0xC2, 0x00, 0xE5, 0xC0, 0x00, 0xE5, 0xBE, 0x82, 0x3A,
0x1A, 0x50,
];
#[test]
fn test_lidar_read() {
let expectations = &[Transaction::read_many(REF_BYTES)];
let mock = Mock::new(expectations);
let mut ld06 = LD06::new(mock);
let scan = loop {
if let Ok(Some(scan)) = ld06.read_next_byte() {
break scan;
}
};
assert_eq!(scan.radar_speed, 2152);
assert_eq!(scan.start_angle, 324.27);
assert_eq!(scan.end_angle, 334.7);
assert_eq!(scan.crc, 0x50);
assert_eq!(scan.stamp, 0x1a3a);
assert_eq!(
scan.data[0],
Range {
confidence: 228,
dist: 224
}
);
assert_eq!(
scan.data[1],
Range {
confidence: 226,
dist: 220
}
);
}
}