use std::io::BufRead;
use std::{io::BufReader, io::Read, time::Duration};
use crate::crc::crc8;
use crate::scan_types::{PartialScan, Scan, ScanBuilder};
use anyhow::Result;
use byteorder::ByteOrder;
use cancellation::CancellationTokenSource;
use ringbuf::{Consumer, Producer, RingBuffer};
use serialport::SerialPortType::UsbPort;
use serialport::{DataBits, FlowControl, Parity, SerialPort, StopBits};
pub type Serial = Box<dyn SerialPort>;
pub struct LD06<R: Read + Send> {
port: Option<BufReader<R>>,
cons: Consumer<Scan>,
prod: Option<Producer<Scan>>,
cts: CancellationTokenSource,
}
impl LD06<Serial> {
pub fn new_auto_port() -> Result<Self> {
let mut port_name = None;
for port in serialport::available_ports()? {
if let UsbPort(info) = port.port_type {
if info.pid == 0xea60 {
port_name.replace(port.port_name);
}
}
}
let port = serialport::new(
port_name.ok_or_else(|| std::io::Error::from(std::io::ErrorKind::NotFound))?,
230400,
);
let serial = port
.data_bits(DataBits::Eight)
.stop_bits(StopBits::One)
.parity(Parity::None)
.flow_control(FlowControl::None)
.timeout(Duration::new(2, 0))
.open()?;
let spsc = RingBuffer::new(8);
let (p, c) = spsc.split();
Ok(LD06 {
port: Some(BufReader::new(serial)),
prod: Some(p),
cons: c,
cts: CancellationTokenSource::new(),
})
}
pub fn new(path: &str) -> Result<Self> {
let port = serialport::new(path, 230400);
let serial = port
.data_bits(DataBits::Eight)
.stop_bits(StopBits::One)
.parity(Parity::None)
.flow_control(FlowControl::None)
.open()?;
let spsc = RingBuffer::new(8);
let (p, c) = spsc.split();
Ok(LD06 {
port: Some(BufReader::new(serial)),
prod: Some(p),
cons: c,
cts: CancellationTokenSource::new(),
})
}
}
impl<R: Read + Send + 'static> LD06<R> {
pub fn from_reader(data: R) -> Self {
let spsc = RingBuffer::new(8);
let (p, c) = spsc.split();
LD06 {
port: Some(BufReader::new(data)),
prod: Some(p),
cons: c,
cts: CancellationTokenSource::new(),
}
}
pub fn listen(&mut self) {
let ring = self.prod.take();
if ring.is_none() {
return;
}
let mut ring = ring.unwrap();
let ct = self.cts.token().clone();
let mut reader = self.port.take().unwrap();
std::thread::spawn(move || {
let mut buf: Vec<u8> = Vec::with_capacity(47); let mut builder = ScanBuilder::default();
while !ct.is_canceled() {
let mut packet = PartialScan::default();
reader.read_until(0x54, &mut buf).unwrap();
if buf.len() < 47 {
if buf.is_empty() {
continue;
}
buf.clear();
continue;
}
if crc8(&buf[0..=45]) != 0 {
log::error!("Checksum Failed!");
buf.clear();
continue;
}
packet.radar_speed = byteorder::LE::read_u16(&buf[1..=2]);
packet.start_angle = byteorder::LE::read_u16(&buf[3..=4]) as f32 / 100.0;
for (i, range) in buf[5..12 * 3 + 5 ].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[41..=42]) as f32 / 100.0;
packet.stamp = byteorder::LE::read_u16(&buf[43..=44]);
packet.crc = buf[45];
let full_scan = builder.add_partial_scan(packet);
if let Some(scan) = full_scan {
if !ct.is_canceled() && ring.push(scan).is_err() {
log::error!("Dropping packet due to full buffer");
}
}
buf.clear();
}
});
}
pub fn stop(self) {
self.cts.cancel();
}
pub unsafe fn stop_borrow(&self) {
self.cts.cancel()
}
pub fn flush_stop(self) -> Vec<Scan> {
self.cts.cancel();
let mut v = Vec::new();
self.cons.iter().for_each(|s| v.push(s.clone()));
v
}
pub fn next_scan(&mut self) -> Option<Scan> {
self.cons.pop()
}
pub fn has_scan(&self) -> bool {
!self.cons.is_empty()
}
}
impl<R: Read + Send> Drop for LD06<R> {
fn drop(&mut self) {
self.cts.cancel();
}
}
#[cfg(test)]
mod test {
use crate::ld06_driver::LD06;
use std::thread::sleep;
use std::time::Duration;
const TEST_BYTES: &[u8] = include_bytes!("../test_assets/example3.0.txt");
#[test]
fn test_read() {
let mut driver = LD06::from_reader(TEST_BYTES);
driver.listen();
sleep(Duration::new(1, 0));
while driver.has_scan() {
let scan = driver.next_scan().unwrap();
println!("{:?}", scan);
}
}
}