1use crate::{
2 consts::{AZIMUTH_COUNT_PER_REV, BLOCKS_PER_PACKET, CHANNELS_PER_BLOCK, FIRING_PERIOD},
3 types::{
4 channel_array::ChannelArrayDRef,
5 firing_block::{FiringBlockD16, FiringBlockD32, FiringBlockS16, FiringBlockS32},
6 firing_xyz::{FiringXyzD16, FiringXyzD32, FiringXyzS16, FiringXyzS32},
7 format::{Format, FormatKind},
8 },
9 utils::AngleExt as _,
10 Config16, Config32,
11};
12use eyre::{ensure, Result};
13use itertools::{chain, izip, Itertools as _};
14use measurements::Angle;
15use std::{f64::consts::PI, iter, mem, time::Duration};
16
17#[repr(u16)]
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum BlockIdentifier {
21 Block0To31 = 0xeeff,
22 Block32To63 = 0xddff,
23}
24
25#[repr(u8)]
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum ReturnMode {
29 Strongest = 0x37,
30 Last = 0x38,
31 Dual = 0x39,
32}
33
34impl ReturnMode {
35 pub fn is_single(&self) -> bool {
36 [ReturnMode::Strongest, ReturnMode::Last].contains(self)
37 }
38
39 pub fn is_dual(&self) -> bool {
40 *self == Self::Dual
41 }
42}
43
44#[repr(u8)]
46#[derive(
47 Debug, Clone, Copy, PartialEq, Eq, Hash, strum::AsRefStr, strum::Display, strum::EnumString,
48)]
49pub enum ProductID {
50 HDL32E = 0x21,
51 VLP16 = 0x22,
52 PuckLite = 0x23,
53 PuckHiRes = 0x24,
54 VLP32C = 0x28,
55 Velarray = 0x31,
56 VLS128 = 0xa1,
57}
58
59impl ProductID {
60 pub fn num_lines(&self) -> usize {
61 match self {
62 Self::HDL32E => 16,
63 Self::VLP16 => 16,
64 Self::PuckLite => 16,
65 Self::PuckHiRes => 16,
66 Self::VLP32C => 32,
67 Self::Velarray => todo!(),
68 Self::VLS128 => 128,
69 }
70 }
71}
72
73#[repr(C, packed)]
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
76pub struct Channel {
77 pub distance: u16,
79 pub intensity: u8,
81}
82
83#[repr(C, packed)]
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
86pub struct Block {
87 pub block_identifier: BlockIdentifier,
89 pub azimuth_count: u16,
91 pub channels: [Channel; CHANNELS_PER_BLOCK],
93}
94
95impl Block {
96 pub fn azimuth_radians(&self) -> f64 {
97 2.0 * PI * self.azimuth_count as f64 / (AZIMUTH_COUNT_PER_REV - 1) as f64
98 }
99
100 pub fn azimuth_degrees(&self) -> f64 {
101 360.0 * self.azimuth_count as f64 / (AZIMUTH_COUNT_PER_REV - 1) as f64
102 }
103
104 pub fn azimuth(&self) -> Angle {
105 Angle::from_radians(self.azimuth_radians())
106 }
107}
108
109#[repr(C, packed)]
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
112pub struct DataPacket {
113 pub blocks: [Block; BLOCKS_PER_PACKET],
115 pub toh: u32,
117 pub return_mode: ReturnMode,
119 pub product_id: ProductID,
121}
122
123impl DataPacket {
124 pub fn from_bytes(buffer: [u8; mem::size_of::<Self>()]) -> Self {
126 unsafe { mem::transmute::<_, Self>(buffer) }
127 }
128
129 pub fn from_slice(buffer: &[u8]) -> Result<&Self> {
131 ensure!(
132 buffer.len() == mem::size_of::<Self>(),
133 "Requre the slice length to be {}, but get {}",
134 mem::size_of::<Self>(),
135 buffer.len(),
136 );
137 let packet = unsafe { &*(buffer.as_ptr() as *const Self) };
138 Ok(packet)
139 }
140
141 pub fn toh(&self) -> Duration {
142 Duration::from_micros(self.toh as u64)
143 }
144
145 pub fn try_format(&self) -> Option<Format> {
146 Format::try_from_model(self.product_id, self.return_mode)
147 }
148
149 pub fn format(&self) -> Format {
150 Format::from_model(self.product_id, self.return_mode)
151 }
152
153 pub fn firing_block_iter(
154 &self,
155 ) -> FormatKind<
156 impl Iterator<Item = FiringBlockS16<'_>> + Clone,
157 impl Iterator<Item = FiringBlockS32<'_>> + Clone,
158 impl Iterator<Item = FiringBlockD16<'_>> + Clone,
159 impl Iterator<Item = FiringBlockD32<'_>> + Clone,
160 > {
161 use Format::*;
162 use FormatKind as F;
163
164 match self.format() {
165 Single16 => F::from_s16(self.firing_block_iter_s16()),
166 Dual16 => F::from_d16(self.firing_block_iter_d16()),
167 Single32 => F::from_s32(self.firing_block_iter_s32()),
168 Dual32 => F::from_d32(self.firing_block_iter_d32()),
169 }
170 }
171
172 pub fn firing_block_iter_s16(
173 &self,
174 ) -> impl Iterator<Item = FiringBlockS16<'_>> + Clone + Sync + Send {
175 let block_period = FIRING_PERIOD.mul_f64(2.0);
176 let tohs = iter::successors(Some(self.toh()), move |prev| Some(*prev + block_period));
177 let firing_azimuths = {
178 let block_azimuths: Vec<_> = self.blocks.iter().map(|block| block.azimuth()).collect();
179 let block_azimuth_diffs: Vec<_> = block_azimuths
180 .iter()
181 .cloned()
182 .tuple_windows()
183 .map(|(curr, next)| (next - curr).wrap_to_2pi())
184 .collect();
185 let last_block_azimuth_diff = *block_azimuth_diffs.last().unwrap();
186
187 izip!(
188 block_azimuths,
189 chain!(block_azimuth_diffs, [last_block_azimuth_diff])
190 )
191 .map(|(block_azimuth, block_azimuth_diff)| {
192 let mid_azimuth = block_azimuth + block_azimuth_diff / 2.0;
193 let last_azimuth = block_azimuth + block_azimuth_diff;
194 [block_azimuth..mid_azimuth, mid_azimuth..last_azimuth]
195 })
196 };
197
198 izip!(tohs, firing_azimuths, &self.blocks).flat_map(
199 move |(block_toh, [former_azimuth, latter_azimuth], block)| {
200 let former_toh = block_toh;
201 let latter_toh = former_toh + FIRING_PERIOD;
202
203 let (former_channels, latter_channels) = block.channels.split_at(16);
204
205 let former = FiringBlockS16 {
206 toh: former_toh,
207 azimuth_range: former_azimuth,
208 block,
209 channels: former_channels
210 .try_into()
211 .unwrap_or_else(|_| unreachable!()),
212 };
213 let latter = FiringBlockS16 {
214 toh: latter_toh,
215 azimuth_range: latter_azimuth,
216 block,
217 channels: latter_channels
218 .try_into()
219 .unwrap_or_else(|_| unreachable!()),
220 };
221
222 [former, latter]
223 },
224 )
225 }
226
227 pub fn firing_block_iter_d16(
228 &self,
229 ) -> impl Iterator<Item = FiringBlockD16<'_>> + Clone + Sync + Send {
230 let block_period = FIRING_PERIOD.mul_f64(2.0);
231 let tohs = iter::successors(Some(self.toh()), move |prev| Some(*prev + block_period));
232 let firing_azimuths = {
233 let block_azimuths: Vec<_> = self
234 .blocks
235 .iter()
236 .step_by(2)
237 .map(|block| block.azimuth())
238 .collect();
239 let block_azimuth_diffs: Vec<_> = block_azimuths
240 .iter()
241 .cloned()
242 .tuple_windows()
243 .map(|(curr, next)| (next - curr).wrap_to_2pi())
244 .collect();
245 let last_block_azimuth_diff = *block_azimuth_diffs.last().unwrap();
246
247 izip!(
248 block_azimuths,
249 chain!(block_azimuth_diffs, [last_block_azimuth_diff])
250 )
251 .map(|(block_azimuth, block_azimuth_diff)| {
252 let mid_azimuth = block_azimuth + block_azimuth_diff / 2.0;
253 let last_azimuth = block_azimuth + block_azimuth_diff;
254 [block_azimuth..mid_azimuth, mid_azimuth..last_azimuth]
255 })
256 };
257
258 izip!(tohs, firing_azimuths, self.blocks.chunks(2)).flat_map(
259 |(block_toh, [former_azimuth, latter_azimuth], block_pair)| {
260 let [block_strongest, block_last] = match block_pair {
261 [first, second] => [first, second],
262 _ => unreachable!(),
263 };
264
265 let former_toh = block_toh;
266 let latter_toh = former_toh + FIRING_PERIOD;
267
268 let (former_strongest, latter_strongest) = block_strongest.channels.split_at(16);
269 let (former_last, latter_last) = block_last.channels.split_at(16);
270
271 [
272 FiringBlockD16 {
273 toh: former_toh,
274 azimuth_range: former_azimuth,
275 block_strongest,
276 block_last,
277 channels: ChannelArrayDRef {
278 strongest: former_strongest
279 .try_into()
280 .unwrap_or_else(|_| unreachable!()),
281 last: former_last.try_into().unwrap_or_else(|_| unreachable!()),
282 },
283 },
284 FiringBlockD16 {
285 toh: latter_toh,
286 azimuth_range: latter_azimuth,
287 block_strongest,
288 block_last,
289 channels: ChannelArrayDRef {
290 strongest: latter_strongest
291 .try_into()
292 .unwrap_or_else(|_| unreachable!()),
293 last: latter_last.try_into().unwrap_or_else(|_| unreachable!()),
294 },
295 },
296 ]
297 },
298 )
299 }
300
301 pub fn firing_block_iter_s32(
302 &self,
303 ) -> impl Iterator<Item = FiringBlockS32<'_>> + Clone + Sync + Send {
304 let tohs = iter::successors(Some(self.toh()), move |prev| Some(*prev + FIRING_PERIOD));
305 let azimuths = {
306 let block_azimuths: Vec<_> = self.blocks.iter().map(|block| block.azimuth()).collect();
307 let block_azimuth_diffs: Vec<_> = block_azimuths
308 .iter()
309 .cloned()
310 .tuple_windows()
311 .map(|(curr, next)| (next - curr).wrap_to_2pi())
312 .collect();
313 let last_block_azimuth_diff = *block_azimuth_diffs.last().unwrap();
314
315 izip!(
316 block_azimuths,
317 chain!(block_azimuth_diffs, [last_block_azimuth_diff])
318 )
319 .map(|(former_azimuth, azimuth_diff)| {
320 let latter_azimuth = former_azimuth + azimuth_diff;
321 former_azimuth..latter_azimuth
322 })
323 };
324
325 izip!(tohs, azimuths, &self.blocks).map(move |(block_toh, azimuth_range, block)| {
326 let former_toh = block_toh;
327 let latter_toh = former_toh + FIRING_PERIOD;
328
329 FiringBlockS32 {
330 toh: latter_toh,
331 azimuth_range,
332 block,
333 channels: &block.channels,
334 }
335 })
336 }
337
338 pub fn firing_block_iter_d32(
339 &self,
340 ) -> impl Iterator<Item = FiringBlockD32<'_>> + Clone + Sync + Send {
341 let tohs = iter::successors(Some(self.toh()), move |prev| Some(*prev + FIRING_PERIOD));
342 let azimuths = {
343 let azimuths: Vec<_> = self
344 .blocks
345 .iter()
346 .step_by(2)
347 .map(|block| block.azimuth())
348 .collect();
349 let azimuth_diffs: Vec<_> = azimuths
350 .iter()
351 .cloned()
352 .tuple_windows()
353 .map(|(curr, next)| (next - curr).wrap_to_2pi())
354 .collect();
355 let last_azimuth_diff = *azimuth_diffs.last().unwrap();
356
357 izip!(azimuths, chain!(azimuth_diffs, [last_azimuth_diff])).map(
358 |(former_azimuth, azimuth_diff)| {
359 let latter_azimuth = former_azimuth + azimuth_diff;
360 former_azimuth..latter_azimuth
361 },
362 )
363 };
364
365 izip!(tohs, azimuths, self.blocks.chunks(2)).map(
366 move |(block_toh, azimuth_range, chunk)| {
367 let [block_strongest, block_last] = match chunk {
368 [first, second] => [first, second],
369 _ => unreachable!(),
370 };
371
372 FiringBlockD32 {
373 toh: block_toh,
374 azimuth_range,
375 block_strongest,
376 block_last,
377 channels: ChannelArrayDRef {
378 strongest: &block_strongest.channels,
379 last: &block_last.channels,
380 },
381 }
382 },
383 )
384 }
385
386 pub fn firing_xyz_iter_s16<'a>(
387 &'a self,
388 beams: &'a Config16,
389 ) -> impl Iterator<Item = FiringXyzS16> + Clone + Sync + Send + 'a {
390 self.firing_block_iter_s16()
391 .map(|firing| firing.to_firing_xyz(beams))
392 }
393
394 pub fn firing_xyz_iter_s32<'a>(
395 &'a self,
396 beams: &'a Config32,
397 ) -> impl Iterator<Item = FiringXyzS32> + Clone + Sync + Send + 'a {
398 self.firing_block_iter_s32()
399 .map(|firing| firing.to_firing_xyz(beams))
400 }
401
402 pub fn firing_xyz_iter_d16<'a>(
403 &'a self,
404 beams: &'a Config16,
405 ) -> impl Iterator<Item = FiringXyzD16> + Clone + Sync + Send + 'a {
406 self.firing_block_iter_d16()
407 .map(|firing| firing.to_firing_xyz(beams))
408 }
409
410 pub fn firing_xyz_iter_d32<'a>(
411 &'a self,
412 beams: &'a Config32,
413 ) -> impl Iterator<Item = FiringXyzD32> + Clone + Sync + Send + 'a {
414 self.firing_block_iter_d32()
415 .map(|firing| firing.to_firing_xyz(beams))
416 }
417}