1use core::convert::TryInto;
2use num_enum::TryFromPrimitive;
3
4#[derive(Copy, Clone, Debug, Eq, PartialEq)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7#[repr(u8)]
8pub enum SlaveAddr {
9 Default = 0x18,
11
12 Alternate = 0x19,
14}
15
16impl SlaveAddr {
17 pub fn addr(self) -> u8 {
18 self as u8
19 }
20}
21
22#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
24#[derive(Copy, Clone, Debug, Eq, PartialEq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26#[repr(u8)]
27pub enum Register {
28 STATUS_AUX = 0x07,
29 OUT_ADC1_L = 0x08,
30 OUT_ADC1_H = 0x09,
31 OUT_ADC2_L = 0x0A,
32 OUT_ADC2_H = 0x0B,
33 OUT_ADC3_L = 0x0C,
34 OUT_ADC3_H = 0x0D,
35 WHOAMI = 0x0F,
36 CTRL0 = 0x1E,
37 TEMP_CFG = 0x1F,
38 CTRL1 = 0x20,
39 CTRL2 = 0x21,
40 CTRL3 = 0x22,
41 CTRL4 = 0x23,
42 CTRL5 = 0x24,
43 CTRL6 = 0x25,
44 REFERENCE = 0x26,
45 STATUS = 0x27,
46 OUT_X_L = 0x28,
47 OUT_X_H = 0x29,
48 OUT_Y_L = 0x2A,
49 OUT_Y_H = 0x2B,
50 OUT_Z_L = 0x2C,
51 OUT_Z_H = 0x2D,
52 FIFO_CTRL = 0x2E,
53 FIFO_SRC = 0x2F,
54 INT1_CFG = 0x30,
55 INT1_SRC = 0x31,
56 INT1_THS = 0x32,
57 INT1_DURATION = 0x33,
58 INT2_CFG = 0x34,
59 INT2_SRC = 0x35,
60 INT2_THS = 0x36,
61 INT2_DURATION = 0x37,
62 CLICK_CFG = 0x38,
63 CLICK_SRC = 0x39,
64 CLICK_THS = 0x3A,
65 TIME_LIMIT = 0x3B,
66 TIME_LATENCY = 0x3C,
67 TIME_WINDOW = 0x3D,
68 ACT_THS = 0x3E,
69 ACT_DUR = 0x3F,
70}
71
72impl Register {
73 pub fn addr(self) -> u8 {
75 self as u8
76 }
77
78 pub fn read_only(self) -> bool {
80 matches!(
81 self,
82 Register::STATUS_AUX
83 | Register::OUT_ADC1_L
84 | Register::OUT_ADC1_H
85 | Register::OUT_ADC2_L
86 | Register::OUT_ADC2_H
87 | Register::OUT_ADC3_L
88 | Register::OUT_ADC3_H
89 | Register::WHOAMI
90 | Register::STATUS
91 | Register::OUT_X_L
92 | Register::OUT_X_H
93 | Register::OUT_Y_L
94 | Register::OUT_Y_H
95 | Register::OUT_Z_L
96 | Register::OUT_Z_H
97 | Register::FIFO_SRC
98 | Register::INT1_SRC
99 | Register::INT2_SRC
100 | Register::CLICK_SRC
101 )
102 }
103}
104
105#[allow(non_camel_case_types)]
107#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive)]
108#[cfg_attr(feature = "defmt", derive(defmt::Format))]
109#[repr(u8)]
110#[derive(Default)]
111pub enum Range {
112 G16 = 0b11,
114
115 G8 = 0b10,
117
118 G4 = 0b01,
120
121 #[default]
123 G2 = 0b00,
124}
125
126impl Range {
127 pub const fn bits(self) -> u8 {
128 self as u8
129 }
130
131 pub const fn as_mg(self) -> u8 {
133 match self {
134 Range::G16 => 186,
135 Range::G8 => 62,
136 Range::G4 => 32,
137 Range::G2 => 16,
138 }
139 }
140}
141
142#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
143#[cfg_attr(feature = "defmt", derive(defmt::Format))]
144pub struct Threshold(pub(crate) u8);
145
146impl Threshold {
147 #[inline(always)]
149 pub fn g(range: Range, gs: f32) -> Self {
150 Self::mg(range, gs * 1000.0)
151 }
152
153 #[inline(always)]
154 pub fn mg(range: Range, mgs: f32) -> Self {
155 let value = mgs / (range.as_mg() as f32);
156
157 let result = crude_ceil(value);
158
159 Threshold(result.try_into().unwrap())
160 }
161
162 pub const ZERO: Self = Threshold(0);
163}
164
165fn crude_ceil(value: f32) -> u64 {
167 let truncated = value as u64;
168
169 let round_up = value - (truncated as f32) > 0.0;
170
171 if round_up {
172 truncated + 1
173 } else {
174 truncated
175 }
176}
177
178#[allow(non_camel_case_types)]
180#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive)]
181#[cfg_attr(feature = "defmt", derive(defmt::Format))]
182#[repr(u8)]
183pub enum DataRate {
184 Hz_400 = 0b0111,
186
187 Hz_200 = 0b0110,
189
190 Hz_100 = 0b0101,
192
193 Hz_50 = 0b0100,
195
196 Hz_25 = 0b0011,
198
199 Hz_10 = 0b0010,
201
202 Hz_1 = 0b0001,
204
205 PowerDown = 0b0000,
207}
208
209impl DataRate {
210 pub const fn bits(self) -> u8 {
211 self as u8
212 }
213
214 pub const fn sample_rate(self) -> f32 {
215 match self {
216 DataRate::Hz_400 => 400.0,
217 DataRate::Hz_200 => 200.0,
218 DataRate::Hz_100 => 100.0,
219 DataRate::Hz_50 => 50.0,
220 DataRate::Hz_25 => 25.0,
221 DataRate::Hz_10 => 10.0,
222 DataRate::Hz_1 => 1.0,
223 DataRate::PowerDown => 0.0,
224 }
225 }
226}
227
228#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
229#[cfg_attr(feature = "defmt", derive(defmt::Format))]
230pub struct Duration(pub(crate) u8);
231
232impl Duration {
233 #[inline(always)]
236 pub fn seconds(output_data_rate: DataRate, seconds: f32) -> Self {
237 let duration = output_data_rate.sample_rate() * seconds;
238
239 Self(duration as u8)
240 }
241
242 #[inline(always)]
245 pub fn miliseconds(output_data_rate: DataRate, miliseconds: f32) -> Self {
246 Self::seconds(output_data_rate, miliseconds * 1000.0)
247 }
248
249 pub const ZERO: Self = Duration(0);
250}
251
252#[derive(Debug)]
270#[cfg_attr(feature = "defmt", derive(defmt::Format))]
271pub struct DataStatus {
272 pub zyxor: bool,
274
275 pub xyzor: (bool, bool, bool),
277
278 pub zyxda: bool,
280
281 pub xyzda: (bool, bool, bool),
283}
284
285#[derive(Copy, Clone, Debug, Eq, PartialEq)]
287#[cfg_attr(feature = "defmt", derive(defmt::Format))]
288pub struct FifoStatus {
289 pub watermark: bool,
291 pub overrun: bool,
296 pub empty: bool,
298 pub stack_size: u8,
303}
304
305impl FifoStatus {
306 pub const fn from_bits(status: u8) -> Self {
308 Self {
309 watermark: (status >> 7) & 1 == 1,
310 overrun: (status >> 6) & 1 == 1,
311 empty: (status >> 5) & 1 == 1,
312 stack_size: status & 0b0001_1111,
313 }
314 }
315}
316
317#[derive(Copy, Clone, Debug, Eq, PartialEq)]
320#[cfg_attr(feature = "defmt", derive(defmt::Format))]
321pub enum FifoMode {
322 ByPass,
324 Fifo,
328 Stream,
333 StreamToFifoInt1,
337 StreamToFifoInt2,
341}
342
343impl FifoMode {
344 pub const fn to_bits(self) -> u8 {
346 let mut trigger = false;
347
348 let mode = match self {
349 FifoMode::ByPass => 0b00,
350 FifoMode::Fifo => 0b01,
351 FifoMode::Stream => 0b10,
352 FifoMode::StreamToFifoInt1 => 0b11,
353 FifoMode::StreamToFifoInt2 => {
354 trigger = true;
355
356 0b11
357 }
358 };
359
360 mode << 6 | (trigger as u8) << 5
361 }
362}
363
364#[derive(Copy, Clone, Debug, Eq, PartialEq)]
366#[cfg_attr(feature = "defmt", derive(defmt::Format))]
367#[repr(u8)]
368pub enum Mode {
369 HighResolution,
371
372 Normal,
374
375 LowPower,
377}
378
379pub const DEVICE_ID: u8 = 0x33;
383
384pub const ADC_EN: u8 = 0b1000_0000;
387pub const TEMP_EN: u8 = 0b0100_0000;
388
389pub const ODR_MASK: u8 = 0b1111_0000;
392pub const LP_EN: u8 = 0b0000_1000;
393pub const Z_EN: u8 = 0b0000_0100;
394pub const Y_EN: u8 = 0b0000_0010;
395pub const X_EN: u8 = 0b0000_0001;
396
397pub const BDU: u8 = 0b1000_0000;
400pub const FS_MASK: u8 = 0b0011_0000;
401pub const HR: u8 = 0b0000_1000;
402
403pub const ZYXOR: u8 = 0b1000_0000;
406pub const ZOR: u8 = 0b0100_0000;
407pub const YOR: u8 = 0b0010_0000;
408pub const XOR: u8 = 0b0001_0000;
409pub const ZYXDA: u8 = 0b0000_1000;
410pub const ZDA: u8 = 0b0000_0100;
411pub const YDA: u8 = 0b0000_0010;
412pub const XDA: u8 = 0b0000_0001;
413
414#[cfg(test)]
415mod test {
416 use super::*;
417
418 #[test]
419 fn threshold_g_vs_mg() {
420 assert_eq!(
421 Threshold::g(Range::G2, 1.5),
422 Threshold::mg(Range::G2, 1500.0)
423 );
424 }
425
426 #[test]
427 fn duration_seconds_vs_miliseconds() {
428 assert_eq!(
429 Duration::seconds(DataRate::Hz_400, 1.5),
430 Duration::miliseconds(DataRate::Hz_400, 1500.0)
431 );
432 }
433}