embedded_camsense_x1/
types.rs1use crate::constants::{
2 NUMBER_OF_POINTS_PER_MEASUREMENT, NUMBER_OF_POINTS_PER_SCAN, PAYLOAD_SIZE_IN_BYTES,
3};
4
5#[derive(Clone, Copy, Debug)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub enum Error<E> {
9 UART(E),
11 ChecksumMismatch(u32, u32),
13 Other,
15}
16
17#[derive(Clone, Copy, Debug)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub struct RawDistance {
21 value: u16,
23 quality: u8,
25 flag: bool,
27}
28
29#[derive(Clone, Copy, Debug)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub struct RawMeasurement {
33 pub speed: u16,
34 pub start_angle: u16,
36 pub end_angle: u16,
38 pub distances: [RawDistance; NUMBER_OF_POINTS_PER_MEASUREMENT],
40 pub checksum: u16,
42}
43
44#[inline]
50pub fn check_lidar_checksum(data: &[u8; PAYLOAD_SIZE_IN_BYTES]) -> Result<(), Error<()>> {
51 let mut accumulator: u32 = 0;
52
53 let num_data_words = data.len() / 2 - 1;
55 for i in 0..num_data_words {
56 let word = u16::from_le_bytes([data[2 * i], data[2 * i + 1]]);
57 accumulator = (accumulator << 1) + word as u32;
58 }
59
60 let computed_checksum = ((accumulator & 0x7FFF) + (accumulator >> 15)) & 0x7FFF;
62
63 let expected_checksum = u16::from_le_bytes([data[data.len() - 2], data[data.len() - 1]]) as u32;
65
66 if computed_checksum == expected_checksum {
67 Ok(())
68 } else {
69 Err(Error::ChecksumMismatch(
70 expected_checksum,
71 computed_checksum,
72 ))
73 }
74}
75
76impl TryFrom<[u8; 36]> for RawMeasurement {
77 type Error = Error<()>; fn try_from(data: [u8; PAYLOAD_SIZE_IN_BYTES]) -> Result<Self, Self::Error> {
79 check_lidar_checksum(&data)?;
81
82 let speed = u16::from_le_bytes([data[4], data[5]]);
83 let start_angle = u16::from_le_bytes([data[6], data[7]]);
84 let end_angle = u16::from_le_bytes([data[32], data[33]]);
85 let checksum = u16::from_le_bytes([data[34], data[35]]);
86
87 let mut distances = [RawDistance {
88 value: 0,
89 quality: 0,
90 flag: false,
91 }; 8];
92 for i in 0..8 {
93 let distance_bytes = [data[8 + i * 3], data[9 + i * 3], data[10 + i * 3]];
94 let value_bytes = [distance_bytes[0], distance_bytes[1] & 0x3F];
96 let value = u16::from_le_bytes(value_bytes);
97 let quality = distance_bytes[2];
98 let flag = (distance_bytes[1] >> 7) & 0x01 != 0;
100
101 let distance = RawDistance {
102 value,
103 quality,
104 flag,
105 };
106 distances[i] = distance;
107 }
108
109 Ok(Self {
110 speed,
111 start_angle,
112 end_angle,
113 distances,
114 checksum,
115 })
116 }
117}
118
119#[derive(Clone, Copy, Default, Debug)]
121#[cfg_attr(feature = "defmt", derive(defmt::Format))]
122pub struct Point {
123 pub distance: u16,
124 pub angle: f32,
125}
126
127#[derive(Clone, Copy, Debug)]
132#[cfg_attr(feature = "defmt", derive(defmt::Format))]
133pub struct PartialScan {
134 pub frequency: f32,
136 pub start_angle: f32,
138 pub end_angle: f32,
140 pub points: [Option<Point>; NUMBER_OF_POINTS_PER_MEASUREMENT],
142}
143
144impl From<(RawMeasurement, f32)> for PartialScan {
145 fn from((raw, angle_offset): (RawMeasurement, f32)) -> Self {
146 let frequency = raw.speed as f32 / 3840.0;
147 let start_angle = raw.start_angle as f32 / 64.0 - 640.0;
148 let end_angle = raw.end_angle as f32 / 64.0 - 640.0;
149 let step = if end_angle > start_angle {
150 (end_angle - start_angle) / 7.0
151 } else {
152 (end_angle - (start_angle - 360.0)) / 7.0
153 };
154
155 let mut points = [None; NUMBER_OF_POINTS_PER_MEASUREMENT];
156 for (i, raw_distance) in raw.distances.iter().enumerate() {
157 if raw_distance.flag || raw_distance.quality == 0 || raw_distance.value == 0 {
158 continue;
159 }
160
161 let angle = (start_angle + step * i as f32 + angle_offset) % 360.0;
162 points[i] = Some(Point {
163 distance: raw_distance.value,
164 angle,
165 });
166 }
167 Self {
168 frequency,
169 start_angle,
170 end_angle,
171 points,
172 }
173 }
174}
175
176#[derive(Clone, Copy, Debug)]
180#[cfg_attr(feature = "defmt", derive(defmt::Format))]
181pub struct Scan {
182 pub points: [Option<Point>; NUMBER_OF_POINTS_PER_SCAN],
184}