livox2/
lib.rs

1//! # Overview
2//! livox2 is a pure Rust library for interfacing with Livox LiDAR devices.
3//! This crate see lidar data streams as a [`streams::LidarStream`], just like the socket data
4//! flows they are in low-level network communication.
5//!
6//! # Usage
7//! To initialize the lidar data streams, use [`LivoxLidarBuilder`] to help you
8//! create the device instances by forwarding the configuration.
9//!
10//! Or you can create the device instances by yourself, see also [`streams`] module.
11//!
12//! Once you have the device instances, you can call [`streams::LidarStream::next_packet`] to
13//! receive the corresponding data packets.
14//!
15//! # Note
16//! This crate doens't provide stream methods, because the [`futures_core::Stream`] trait doesn't
17//! guarantee the unique mutable access to the socket buffer between each yield
18//! [`futures_core::Stream::Item`], and can't even return a reference.
19//!
20//! Instead, to get iterate the lidar data streams, you must match the enum
21//! [`streams::LidarStream::Packet`] first, take the inner array slice, then
22//! iterate this array slice to read the data.
23//!
24//! # Example
25//! See tests in crate lib.rs
26
27mod crc;
28pub mod error;
29mod seq;
30pub mod streams;
31pub mod types;
32
33pub mod dst;
34
35use std::{io, net::Ipv4Addr};
36
37pub use error::Error;
38use streams::{LidarConfig, LidarStream};
39use tuple_list::TupleList;
40
41/// A builder for creating [`LidarStream`] instances.
42pub struct LivoxLidarBuilder<D> {
43    config: LidarConfig,
44    device: D,
45}
46
47impl<Ds> LivoxLidarBuilder<Ds>
48where
49    Ds: TupleList,
50{
51    pub fn new(
52        local_ip: impl Into<Ipv4Addr>,
53        lidar_ip: impl Into<Ipv4Addr>,
54    ) -> LivoxLidarBuilder<()> {
55        Self::new_const(local_ip.into(), lidar_ip.into())
56    }
57    pub const fn new_const(local_ip: Ipv4Addr, lidar_ip: Ipv4Addr) -> LivoxLidarBuilder<()> {
58        Self::from_config(LidarConfig::new(local_ip, lidar_ip))
59    }
60    pub const fn from_config(config: LidarConfig) -> LivoxLidarBuilder<()> {
61        LivoxLidarBuilder { config, device: () }
62    }
63    pub async fn add_stream<D>(self) -> Result<LivoxLidarBuilder<(D, Ds)>, io::Error>
64    where
65        D: LidarStream,
66    {
67        Ok(LivoxLidarBuilder {
68            device: (D::from_config(&self.config).await?, self.device),
69            config: self.config,
70        })
71    }
72    pub fn build(self) -> Ds::Tuple {
73        self.device.into_tuple()
74    }
75}
76
77#[cfg(test)]
78mod tests {
79
80    use super::*;
81    use zerocopy::*;
82
83    const TEST_CONFIG: LivoxLidarBuilder<()> = LivoxLidarBuilder::new_const(
84        Ipv4Addr::new(192, 168, 1, 50),
85        Ipv4Addr::new(192, 168, 1, 3),
86    );
87
88    #[test]
89    fn test_builder() {
90        smol::block_on(async {
91            let (detect, imu) = TEST_CONFIG
92                .add_stream::<streams::PointDataStream>()
93                .await
94                .unwrap()
95                .add_stream::<streams::ImuStream>()
96                .await
97                .unwrap()
98                .build();
99        });
100    }
101
102    #[test]
103    fn test_detect_lidar() {
104        smol::block_on(async {
105            let mut detection = TEST_CONFIG
106                .add_stream::<streams::DetectionStream>()
107                .await
108                .unwrap()
109                .build()
110                .0;
111            let result = detection.next_packet().await.unwrap();
112            dbg!(result);
113        });
114    }
115
116    #[test]
117    fn test_recv_packet() {
118        smol::block_on(async {
119            let mut lidar = TEST_CONFIG
120                .add_stream::<streams::PointDataStream>()
121                .await
122                .unwrap()
123                .build()
124                .0;
125            let packet = lidar.next_packet().await.unwrap();
126            dbg!(packet.header);
127            dbg!(&packet.data[..5]);
128        });
129    }
130}