1pub(crate) mod fifo;
4pub(crate) mod scale;
5#[cfg(feature = "fixed")]
6pub(crate) mod fixed;
7
8pub(crate) use fifo::fifo_read_len;
9pub use fifo::{
10 FifoConfig, FifoFrame, FifoFrameFormat, FifoFrameIterator, FifoMode, FifoReadout, FifoSize,
11 FifoStatus,
12};
13pub use scale::{
14 ScaleFactor,
15 accel_lsb_per_g,
16 accel_mg_per_lsb,
17 gyro_lsb_per_dps,
18 gyro_mdps_per_lsb,
19 temperature_lsb_per_celsius,
20 temperature_mdegc_per_lsb,
21};
22
23use crate::register::Register;
24
25pub(crate) const RAW_BLOCK_START: Register = Register::TimestampLow;
26pub(crate) const RAW_BLOCK_LEN: usize = 17;
27pub(crate) const RAW_BLOCK_TIMESTAMP_OFFSET: usize = 0;
28pub(crate) const RAW_BLOCK_TEMPERATURE_OFFSET: usize = 3;
29pub(crate) const RAW_BLOCK_ACCEL_OFFSET: usize = 5;
30pub(crate) const RAW_BLOCK_GYRO_OFFSET: usize = 11;
31
32pub(crate) const FIFO_AXIS_BYTES: usize = 6;
33
34#[derive(Clone, Copy, Debug, PartialEq, Eq)]
35pub(crate) struct FifoFrameLayout {
36 pub accel: bool,
37 pub gyro: bool,
38 pub mag: bool,
39 pub bytes_per_frame: usize,
40}
41
42pub(crate) const FIFO_FRAME_LAYOUTS: [FifoFrameLayout; 8] = [
43 FifoFrameLayout {
44 accel: false,
45 gyro: false,
46 mag: false,
47 bytes_per_frame: 0,
48 },
49 FifoFrameLayout {
50 accel: true,
51 gyro: false,
52 mag: false,
53 bytes_per_frame: FIFO_AXIS_BYTES,
54 },
55 FifoFrameLayout {
56 accel: false,
57 gyro: true,
58 mag: false,
59 bytes_per_frame: FIFO_AXIS_BYTES,
60 },
61 FifoFrameLayout {
62 accel: true,
63 gyro: true,
64 mag: false,
65 bytes_per_frame: FIFO_AXIS_BYTES * 2,
66 },
67 FifoFrameLayout {
68 accel: false,
69 gyro: false,
70 mag: true,
71 bytes_per_frame: FIFO_AXIS_BYTES,
72 },
73 FifoFrameLayout {
74 accel: true,
75 gyro: false,
76 mag: true,
77 bytes_per_frame: FIFO_AXIS_BYTES * 2,
78 },
79 FifoFrameLayout {
80 accel: false,
81 gyro: true,
82 mag: true,
83 bytes_per_frame: FIFO_AXIS_BYTES * 2,
84 },
85 FifoFrameLayout {
86 accel: true,
87 gyro: true,
88 mag: true,
89 bytes_per_frame: FIFO_AXIS_BYTES * 3,
90 },
91];
92
93pub(crate) const fn fifo_frame_bytes(accel: bool, gyro: bool, mag: bool) -> usize {
94 let idx = (accel as usize) | ((gyro as usize) << 1) | ((mag as usize) << 2);
95 FIFO_FRAME_LAYOUTS[idx].bytes_per_frame
96}
97
98#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
100#[cfg_attr(feature = "defmt", derive(defmt::Format))]
101pub struct Timestamp {
102 pub ticks: u32,
104}
105
106impl Timestamp {
107 pub(crate) const fn from_bytes(bytes: [u8; 3]) -> Self {
108 let ticks = ((bytes[2] as u32) << 16) | ((bytes[1] as u32) << 8) | (bytes[0] as u32);
109 Self { ticks }
110 }
111}
112
113#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
115#[cfg_attr(feature = "defmt", derive(defmt::Format))]
116pub struct Sample<T> {
117 pub timestamp: Timestamp,
119 pub data: T,
121}
122
123#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
126pub struct RawBlock {
127 pub timestamp: Timestamp,
129 pub temperature: TemperatureRaw,
131 pub accel: Option<AccelRaw>,
133 pub gyro: Option<GyroRaw>,
135}
136
137pub(crate) fn decode_raw_block(
139 buffer: &[u8; RAW_BLOCK_LEN],
140 big_endian: bool,
141 accel_enabled: bool,
142 gyro_enabled: bool,
143) -> RawBlock {
144 let timestamp = Timestamp::from_bytes([
145 buffer[RAW_BLOCK_TIMESTAMP_OFFSET],
146 buffer[RAW_BLOCK_TIMESTAMP_OFFSET + 1],
147 buffer[RAW_BLOCK_TIMESTAMP_OFFSET + 2],
148 ]);
149 let temperature = TemperatureRaw::from_bytes(
150 [
151 buffer[RAW_BLOCK_TEMPERATURE_OFFSET],
152 buffer[RAW_BLOCK_TEMPERATURE_OFFSET + 1],
153 ],
154 big_endian,
155 );
156
157 let accel = if accel_enabled {
158 Some(AccelRaw::from_bytes(
159 [
160 buffer[RAW_BLOCK_ACCEL_OFFSET],
161 buffer[RAW_BLOCK_ACCEL_OFFSET + 1],
162 buffer[RAW_BLOCK_ACCEL_OFFSET + 2],
163 buffer[RAW_BLOCK_ACCEL_OFFSET + 3],
164 buffer[RAW_BLOCK_ACCEL_OFFSET + 4],
165 buffer[RAW_BLOCK_ACCEL_OFFSET + 5],
166 ],
167 big_endian,
168 ))
169 } else {
170 None
171 };
172
173 let gyro = if gyro_enabled {
174 Some(GyroRaw::from_bytes(
175 [
176 buffer[RAW_BLOCK_GYRO_OFFSET],
177 buffer[RAW_BLOCK_GYRO_OFFSET + 1],
178 buffer[RAW_BLOCK_GYRO_OFFSET + 2],
179 buffer[RAW_BLOCK_GYRO_OFFSET + 3],
180 buffer[RAW_BLOCK_GYRO_OFFSET + 4],
181 buffer[RAW_BLOCK_GYRO_OFFSET + 5],
182 ],
183 big_endian,
184 ))
185 } else {
186 None
187 };
188
189 RawBlock {
190 timestamp,
191 temperature,
192 accel,
193 gyro,
194 }
195}
196
197#[repr(C)]
199#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
200#[cfg_attr(feature = "defmt", derive(defmt::Format))]
201#[allow(dead_code)]
202pub struct AccelSampleRaw {
203 pub timestamp_ticks: u32,
205 pub accel_x: i16,
207 pub accel_y: i16,
209 pub accel_z: i16,
211}
212
213#[repr(C)]
215#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
216#[cfg_attr(feature = "defmt", derive(defmt::Format))]
217#[allow(dead_code)]
218pub struct AccelGyroSampleRaw {
219 pub timestamp_ticks: u32,
221 pub accel_x: i16,
223 pub accel_y: i16,
225 pub accel_z: i16,
227 pub gyro_x: i16,
229 pub gyro_y: i16,
231 pub gyro_z: i16,
233}
234
235#[repr(C)]
237#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
238#[cfg_attr(feature = "defmt", derive(defmt::Format))]
239#[allow(dead_code)]
240pub struct AccelGyroMagSampleRaw {
241 pub timestamp_ticks: u32,
243 pub accel_x: i16,
245 pub accel_y: i16,
247 pub accel_z: i16,
249 pub gyro_x: i16,
251 pub gyro_y: i16,
253 pub gyro_z: i16,
255 pub mag_x: i16,
257 pub mag_y: i16,
259 pub mag_z: i16,
261}
262
263#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
265#[cfg_attr(feature = "defmt", derive(defmt::Format))]
266pub struct AccelRaw {
267 pub x: i16,
269 pub y: i16,
271 pub z: i16,
273}
274
275impl AccelRaw {
276 pub(crate) fn from_bytes(bytes: [u8; 6], big_endian: bool) -> Self {
277 let (x, y, z) = if big_endian {
278 (
279 i16::from_be_bytes([bytes[0], bytes[1]]),
280 i16::from_be_bytes([bytes[2], bytes[3]]),
281 i16::from_be_bytes([bytes[4], bytes[5]]),
282 )
283 } else {
284 (
285 i16::from_le_bytes([bytes[0], bytes[1]]),
286 i16::from_le_bytes([bytes[2], bytes[3]]),
287 i16::from_le_bytes([bytes[4], bytes[5]]),
288 )
289 };
290 Self { x, y, z }
291 }
292
293 #[allow(dead_code)]
294 pub(crate) fn from_le_bytes(bytes: [u8; 6]) -> Self {
295 Self::from_bytes(bytes, false)
296 }
297}
298
299#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
301#[cfg_attr(feature = "defmt", derive(defmt::Format))]
302pub struct GyroRaw {
303 pub x: i16,
305 pub y: i16,
307 pub z: i16,
309}
310
311impl GyroRaw {
312 pub(crate) fn from_bytes(bytes: [u8; 6], big_endian: bool) -> Self {
313 let (x, y, z) = if big_endian {
314 (
315 i16::from_be_bytes([bytes[0], bytes[1]]),
316 i16::from_be_bytes([bytes[2], bytes[3]]),
317 i16::from_be_bytes([bytes[4], bytes[5]]),
318 )
319 } else {
320 (
321 i16::from_le_bytes([bytes[0], bytes[1]]),
322 i16::from_le_bytes([bytes[2], bytes[3]]),
323 i16::from_le_bytes([bytes[4], bytes[5]]),
324 )
325 };
326 Self { x, y, z }
327 }
328
329 #[allow(dead_code)]
330 pub(crate) fn from_le_bytes(bytes: [u8; 6]) -> Self {
331 Self::from_bytes(bytes, false)
332 }
333}
334
335#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
337#[cfg_attr(feature = "defmt", derive(defmt::Format))]
338pub struct TemperatureRaw {
339 pub value: i16,
341}
342
343impl TemperatureRaw {
344 pub(crate) fn from_bytes(bytes: [u8; 2], big_endian: bool) -> Self {
345 let value = if big_endian {
346 i16::from_be_bytes(bytes)
347 } else {
348 i16::from_le_bytes(bytes)
349 };
350 Self { value }
351 }
352
353 #[allow(dead_code)]
354 pub(crate) fn from_le_bytes(bytes: [u8; 2]) -> Self {
355 Self::from_bytes(bytes, false)
356 }
357}
358
359#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
361#[cfg_attr(feature = "defmt", derive(defmt::Format))]
362#[allow(dead_code)]
363pub struct MagRaw {
364 pub x: i16,
366 pub y: i16,
368 pub z: i16,
370}
371
372#[allow(dead_code)]
373impl MagRaw {
374 pub(crate) fn from_bytes(bytes: [u8; 6], big_endian: bool) -> Self {
375 let (x, y, z) = if big_endian {
376 (
377 i16::from_be_bytes([bytes[0], bytes[1]]),
378 i16::from_be_bytes([bytes[2], bytes[3]]),
379 i16::from_be_bytes([bytes[4], bytes[5]]),
380 )
381 } else {
382 (
383 i16::from_le_bytes([bytes[0], bytes[1]]),
384 i16::from_le_bytes([bytes[2], bytes[3]]),
385 i16::from_le_bytes([bytes[4], bytes[5]]),
386 )
387 };
388 Self { x, y, z }
389 }
390
391 pub(crate) fn from_le_bytes(bytes: [u8; 6]) -> Self {
392 Self::from_bytes(bytes, false)
393 }
394}
395
396#[cfg(test)]
397mod tests {
398 use super::*;
399
400 #[test]
401 fn decode_raw_block_little_endian() {
402 let mut buffer = [0u8; RAW_BLOCK_LEN];
403 buffer[RAW_BLOCK_TIMESTAMP_OFFSET] = 0x01;
404 buffer[RAW_BLOCK_TIMESTAMP_OFFSET + 1] = 0x02;
405 buffer[RAW_BLOCK_TIMESTAMP_OFFSET + 2] = 0x03;
406 buffer[RAW_BLOCK_TEMPERATURE_OFFSET] = 0x10;
407 buffer[RAW_BLOCK_TEMPERATURE_OFFSET + 1] = 0x00;
408
409 buffer[RAW_BLOCK_ACCEL_OFFSET] = 0x01;
410 buffer[RAW_BLOCK_ACCEL_OFFSET + 2] = 0x02;
411 buffer[RAW_BLOCK_ACCEL_OFFSET + 4] = 0x03;
412
413 buffer[RAW_BLOCK_GYRO_OFFSET] = 0x04;
414 buffer[RAW_BLOCK_GYRO_OFFSET + 2] = 0x05;
415 buffer[RAW_BLOCK_GYRO_OFFSET + 4] = 0x06;
416
417 let block = decode_raw_block(&buffer, false, true, true);
418 assert_eq!(block.timestamp.ticks, 0x030201);
419 assert_eq!(block.temperature.value, 0x0010);
420
421 let accel = block.accel.expect("accel");
422 let gyro = block.gyro.expect("gyro");
423 assert_eq!(accel.x, 1);
424 assert_eq!(accel.y, 2);
425 assert_eq!(accel.z, 3);
426 assert_eq!(gyro.x, 4);
427 assert_eq!(gyro.y, 5);
428 assert_eq!(gyro.z, 6);
429 }
430
431 #[test]
432 fn decode_raw_block_big_endian_no_sensors() {
433 let mut buffer = [0u8; RAW_BLOCK_LEN];
434 buffer[RAW_BLOCK_TIMESTAMP_OFFSET] = 0xAA;
435 buffer[RAW_BLOCK_TIMESTAMP_OFFSET + 1] = 0xBB;
436 buffer[RAW_BLOCK_TIMESTAMP_OFFSET + 2] = 0xCC;
437 buffer[RAW_BLOCK_TEMPERATURE_OFFSET] = 0x00;
438 buffer[RAW_BLOCK_TEMPERATURE_OFFSET + 1] = 0x10;
439
440 let block = decode_raw_block(&buffer, true, false, false);
441 assert_eq!(block.timestamp.ticks, 0xCCBBAA);
442 assert_eq!(block.temperature.value, 0x0010);
443 assert!(block.accel.is_none());
444 assert!(block.gyro.is_none());
445 }
446}