1use crate::error::Error;
4use crate::interrupt::InterruptWaitError;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub struct SelfTestAxis {
10 pub x: i16,
12 pub y: i16,
14 pub z: i16,
16}
17
18impl SelfTestAxis {
19 pub(crate) fn from_bytes(bytes: [u8; 6], big_endian: bool) -> Self {
20 let (x, y, z) = if big_endian {
21 (
22 i16::from_be_bytes([bytes[0], bytes[1]]),
23 i16::from_be_bytes([bytes[2], bytes[3]]),
24 i16::from_be_bytes([bytes[4], bytes[5]]),
25 )
26 } else {
27 (
28 i16::from_le_bytes([bytes[0], bytes[1]]),
29 i16::from_le_bytes([bytes[2], bytes[3]]),
30 i16::from_le_bytes([bytes[4], bytes[5]]),
31 )
32 };
33 Self { x, y, z }
34 }
35
36 fn abs_exceeds(self, threshold_lsb: i16) -> bool {
37 abs_i16(self.x) >= threshold_lsb
38 && abs_i16(self.y) >= threshold_lsb
39 && abs_i16(self.z) >= threshold_lsb
40 }
41}
42
43#[derive(Clone, Copy, Debug, PartialEq, Eq)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46pub struct SelfTestReport {
47 pub raw: SelfTestAxis,
49 pub threshold_lsb: i16,
51 pub passed: bool,
53}
54
55impl SelfTestReport {
56 pub(crate) fn accel(raw: SelfTestAxis) -> Self {
57 let threshold = accel_threshold_lsb();
58 Self {
59 raw,
60 threshold_lsb: threshold,
61 passed: raw.abs_exceeds(threshold),
62 }
63 }
64
65 pub(crate) fn gyro(raw: SelfTestAxis) -> Self {
66 let threshold = gyro_threshold_lsb();
67 Self {
68 raw,
69 threshold_lsb: threshold,
70 passed: raw.abs_exceeds(threshold),
71 }
72 }
73}
74
75#[derive(Debug)]
77#[cfg_attr(feature = "defmt", derive(defmt::Format))]
78pub enum SelfTestError<E> {
79 Driver(Error),
81 Interrupt(InterruptWaitError<E>),
83}
84
85impl<E> From<Error> for SelfTestError<E> {
86 fn from(err: Error) -> Self {
87 Self::Driver(err)
88 }
89}
90
91impl<E> From<InterruptWaitError<E>> for SelfTestError<E> {
92 fn from(err: InterruptWaitError<E>) -> Self {
93 Self::Interrupt(err)
94 }
95}
96
97const fn accel_threshold_lsb() -> i16 {
98 ((200i32 * 2048 + 999) / 1000) as i16
101}
102
103const fn gyro_threshold_lsb() -> i16 {
104 (300i32 * 16) as i16
106}
107
108const fn abs_i16(value: i16) -> i16 {
109 if value < 0 {
110 (-(value as i32)) as i16
111 } else {
112 value
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn accel_threshold_is_expected() {
122 assert_eq!(accel_threshold_lsb(), 410);
123 }
124
125 #[test]
126 fn gyro_threshold_is_expected() {
127 assert_eq!(gyro_threshold_lsb(), 4800);
128 }
129
130 #[test]
131 fn report_passes_when_above_threshold() {
132 let raw = SelfTestAxis {
133 x: 500,
134 y: -500,
135 z: 600,
136 };
137 let report = SelfTestReport::accel(raw);
138 assert!(report.passed);
139 }
140}