Skip to main content

ph_qmi8658/config/
mode.rs

1//! Operating mode state machine for the QMI8658.
2
3/// Operating modes from Table 34 / Figure 11 of the datasheet.
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub enum OperatingMode {
6    /// Software reset asserted.
7    SoftwareReset,
8    /// No power (VDDIO/VDD low).
9    NoPower,
10    /// Power-on default (all sensors off, normal clock).
11    PowerOnDefault,
12    /// Power-down (all sensors off, clock off).
13    PowerDown,
14    /// Magnetometer only.
15    MagOnly,
16    /// Accelerometer + magnetometer.
17    AccelMag,
18    /// Accelerometer + gyroscope + magnetometer (9DOF).
19    AccelGyroMag,
20    /// OIS mode (Accel + Gyro, aODR=0, gODR=0).
21    Ois,
22    /// Accelerometer + gyroscope only.
23    AccelGyroOnly,
24    /// Gyroscope only.
25    GyroOnly,
26    /// Accelerometer only.
27    AccelOnly,
28    /// Low power accelerometer only.
29    LowPowerAccel,
30    /// Low power, all sensors off (slow clock).
31    LowPowerAllOff,
32    /// Wake on Motion (WoM).
33    WakeOnMotion,
34}
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub(crate) enum TransitionDelay {
38    Immediate,
39    T0,
40    T1PlusT5,
41    T2PlusT5,
42    T3PlusT5,
43    T4PlusT5,
44    T6,
45    T7,
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49pub(crate) struct ModeTransition {
50    pub from: OperatingMode,
51    pub to: OperatingMode,
52    pub delay: TransitionDelay,
53}
54
55const MODE_TRANSITIONS: &[ModeTransition] = &[
56    ModeTransition {
57        from: OperatingMode::SoftwareReset,
58        to: OperatingMode::PowerOnDefault,
59        delay: TransitionDelay::T0,
60    },
61    ModeTransition {
62        from: OperatingMode::NoPower,
63        to: OperatingMode::PowerOnDefault,
64        delay: TransitionDelay::T0,
65    },
66    ModeTransition {
67        from: OperatingMode::PowerOnDefault,
68        to: OperatingMode::PowerDown,
69        delay: TransitionDelay::T6,
70    },
71    ModeTransition {
72        from: OperatingMode::PowerDown,
73        to: OperatingMode::PowerOnDefault,
74        delay: TransitionDelay::T7,
75    },
76    ModeTransition {
77        from: OperatingMode::PowerOnDefault,
78        to: OperatingMode::MagOnly,
79        delay: TransitionDelay::T6,
80    },
81    ModeTransition {
82        from: OperatingMode::MagOnly,
83        to: OperatingMode::PowerOnDefault,
84        delay: TransitionDelay::T3PlusT5,
85    },
86    ModeTransition {
87        from: OperatingMode::PowerOnDefault,
88        to: OperatingMode::AccelMag,
89        delay: TransitionDelay::T6,
90    },
91    ModeTransition {
92        from: OperatingMode::AccelMag,
93        to: OperatingMode::PowerOnDefault,
94        delay: TransitionDelay::T1PlusT5,
95    },
96    ModeTransition {
97        from: OperatingMode::PowerOnDefault,
98        to: OperatingMode::AccelGyroMag,
99        delay: TransitionDelay::T6,
100    },
101    ModeTransition {
102        from: OperatingMode::AccelGyroMag,
103        to: OperatingMode::PowerOnDefault,
104        delay: TransitionDelay::T1PlusT5,
105    },
106    ModeTransition {
107        from: OperatingMode::PowerOnDefault,
108        to: OperatingMode::Ois,
109        delay: TransitionDelay::T6,
110    },
111    ModeTransition {
112        from: OperatingMode::Ois,
113        to: OperatingMode::PowerOnDefault,
114        delay: TransitionDelay::T1PlusT5,
115    },
116    ModeTransition {
117        from: OperatingMode::PowerOnDefault,
118        to: OperatingMode::AccelGyroOnly,
119        delay: TransitionDelay::T6,
120    },
121    ModeTransition {
122        from: OperatingMode::AccelGyroOnly,
123        to: OperatingMode::PowerOnDefault,
124        delay: TransitionDelay::T1PlusT5,
125    },
126    ModeTransition {
127        from: OperatingMode::PowerOnDefault,
128        to: OperatingMode::GyroOnly,
129        delay: TransitionDelay::T6,
130    },
131    ModeTransition {
132        from: OperatingMode::GyroOnly,
133        to: OperatingMode::PowerOnDefault,
134        delay: TransitionDelay::T4PlusT5,
135    },
136    ModeTransition {
137        from: OperatingMode::PowerOnDefault,
138        to: OperatingMode::AccelOnly,
139        delay: TransitionDelay::T6,
140    },
141    ModeTransition {
142        from: OperatingMode::AccelOnly,
143        to: OperatingMode::PowerOnDefault,
144        delay: TransitionDelay::T1PlusT5,
145    },
146    ModeTransition {
147        from: OperatingMode::PowerOnDefault,
148        to: OperatingMode::LowPowerAccel,
149        delay: TransitionDelay::T6,
150    },
151    ModeTransition {
152        from: OperatingMode::LowPowerAccel,
153        to: OperatingMode::PowerOnDefault,
154        delay: TransitionDelay::T2PlusT5,
155    },
156    ModeTransition {
157        from: OperatingMode::PowerOnDefault,
158        to: OperatingMode::LowPowerAllOff,
159        delay: TransitionDelay::T7,
160    },
161    ModeTransition {
162        from: OperatingMode::LowPowerAllOff,
163        to: OperatingMode::PowerOnDefault,
164        delay: TransitionDelay::T6,
165    },
166    ModeTransition {
167        from: OperatingMode::LowPowerAllOff,
168        to: OperatingMode::WakeOnMotion,
169        delay: TransitionDelay::T2PlusT5,
170    },
171    ModeTransition {
172        from: OperatingMode::WakeOnMotion,
173        to: OperatingMode::LowPowerAllOff,
174        delay: TransitionDelay::T2PlusT5,
175    },
176    ModeTransition {
177        from: OperatingMode::LowPowerAccel,
178        to: OperatingMode::LowPowerAllOff,
179        delay: TransitionDelay::T2PlusT5,
180    },
181];
182
183#[derive(Clone, Copy, Debug, PartialEq, Eq)]
184pub(crate) struct OperatingModeStateMachine {
185    mode: OperatingMode,
186}
187
188impl OperatingModeStateMachine {
189    pub const fn new(mode: OperatingMode) -> Self {
190        Self { mode }
191    }
192
193    pub const fn mode(self) -> OperatingMode {
194        self.mode
195    }
196
197    pub fn set_mode(&mut self, mode: OperatingMode) {
198        self.mode = mode;
199    }
200
201    #[allow(dead_code)]
202    pub fn transition_to(&mut self, target: OperatingMode) -> Result<TransitionDelay, ()> {
203        if self.mode == target {
204            return Ok(TransitionDelay::Immediate);
205        }
206
207        let delay = transition_delay(self.mode, target).ok_or(())?;
208        self.mode = target;
209        Ok(delay)
210    }
211}
212
213pub(crate) fn transition_delay(from: OperatingMode, to: OperatingMode) -> Option<TransitionDelay> {
214    if from == to {
215        return Some(TransitionDelay::Immediate);
216    }
217
218    if matches!(to, OperatingMode::SoftwareReset | OperatingMode::NoPower) {
219        return Some(TransitionDelay::Immediate);
220    }
221
222    MODE_TRANSITIONS
223        .iter()
224        .find(|entry| entry.from == from && entry.to == to)
225        .map(|entry| entry.delay)
226}