1pub(crate) mod common;
4pub(crate) mod mode;
5
6pub use common::{AccelConfig, AccelOutputDataRate, AccelRange, LowPassFilterMode};
7pub use common::{GyroConfig, GyroOutputDataRate, GyroRange};
8pub use mode::OperatingMode;
9pub(crate) use mode::{OperatingModeStateMachine, TransitionDelay, transition_delay};
10
11use crate::error::Error;
12use crate::register::{ctrl5, ctrl7};
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct Config {
18 pub accel: Option<AccelConfig>,
20 pub gyro: Option<GyroConfig>,
22}
23
24impl Default for Config {
25 fn default() -> Self {
26 Self::new()
27 }
28}
29
30impl Config {
31 pub const fn new() -> Self {
33 Self {
34 accel: Some(AccelConfig::DEFAULT),
35 gyro: Some(GyroConfig::DEFAULT),
36 }
37 }
38
39 #[must_use]
41 pub const fn with_accel_config(mut self, accel: AccelConfig) -> Self {
42 self.accel = Some(accel);
43 self
44 }
45
46 #[must_use]
48 pub const fn without_accel(mut self) -> Self {
49 self.accel = None;
50 self
51 }
52
53 #[must_use]
55 pub const fn with_gyro_config(mut self, gyro: GyroConfig) -> Self {
56 self.gyro = Some(gyro);
57 self
58 }
59
60 #[must_use]
62 pub const fn without_gyro(mut self) -> Self {
63 self.gyro = None;
64 self
65 }
66
67 pub(crate) const fn accel_enabled(self) -> bool {
68 self.accel.is_some()
69 }
70
71 pub(crate) const fn gyro_enabled(self) -> bool {
72 self.gyro.is_some()
73 }
74
75 pub(crate) const fn ctrl2_value(self) -> u8 {
76 match self.accel {
77 Some(accel) => accel.ctrl2_value(),
78 None => 0,
79 }
80 }
81
82 pub(crate) const fn ctrl3_value(self) -> u8 {
83 match self.gyro {
84 Some(gyro) => gyro.ctrl3_value(),
85 None => 0,
86 }
87 }
88
89 pub(crate) const fn ctrl5_value(self) -> u8 {
90 let mut value = 0;
91 if let Some(gyro) = self.gyro
92 && let Some(mode) = gyro.lpf
93 {
94 value |= ctrl5::G_LPF_EN;
95 value |= (mode.bits() << ctrl5::G_LPF_MODE_SHIFT) & ctrl5::G_LPF_MODE_MASK;
96 }
97 if let Some(accel) = self.accel
98 && let Some(mode) = accel.lpf
99 {
100 value |= ctrl5::A_LPF_EN;
101 value |= (mode.bits() << ctrl5::A_LPF_MODE_SHIFT) & ctrl5::A_LPF_MODE_MASK;
102 }
103 value
104 }
105
106 pub(crate) const fn ctrl7_value(self) -> u8 {
107 let mut value = 0;
108 if self.accel_enabled() {
109 value |= ctrl7::A_EN;
110 }
111 if self.gyro_enabled() {
112 value |= ctrl7::G_EN;
113 }
114 value
115 }
116
117 pub(crate) fn validate(self) -> Result<(), Error> {
118 if let (Some(accel), Some(_gyro)) = (self.accel, self.gyro)
119 && accel.odr.is_low_power()
120 {
121 return Err(Error::InvalidData);
122 }
123 Ok(())
124 }
125
126 pub(crate) const fn target_mode(self) -> OperatingMode {
127 match (self.accel, self.gyro) {
128 (None, None) => OperatingMode::PowerOnDefault,
129 (Some(accel), None) => {
130 if accel.odr.is_low_power() {
131 OperatingMode::LowPowerAccel
132 } else {
133 OperatingMode::AccelOnly
134 }
135 }
136 (None, Some(_)) => OperatingMode::GyroOnly,
137 (Some(_), Some(_)) => OperatingMode::AccelGyroOnly,
138 }
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::common::{AccelConfig, AccelOutputDataRate, AccelRange, GyroConfig};
145 use super::*;
146
147 #[test]
148 fn validate_rejects_low_power_accel_with_gyro() {
149 let accel = AccelConfig::new(AccelRange::G8, AccelOutputDataRate::LowPowerHz21);
150 let config = Config::new().with_accel_config(accel);
151 assert_eq!(config.validate(), Err(Error::InvalidData));
152 }
153
154 #[test]
155 fn validate_allows_low_power_accel_without_gyro() {
156 let accel = AccelConfig::new(AccelRange::G8, AccelOutputDataRate::LowPowerHz21);
157 let config = Config::new().with_accel_config(accel).without_gyro();
158 assert_eq!(config.validate(), Ok(()));
159 }
160
161 #[test]
162 fn target_mode_tracks_config() {
163 let accel = AccelConfig::new(AccelRange::G8, AccelOutputDataRate::LowPowerHz21);
164 let gyro = GyroConfig::DEFAULT;
165 let config = Config::new().with_accel_config(accel).without_gyro();
166 assert_eq!(config.target_mode(), OperatingMode::LowPowerAccel);
167
168 let config = Config::new().with_gyro_config(gyro).without_accel();
169 assert_eq!(config.target_mode(), OperatingMode::GyroOnly);
170
171 let config = Config::new().without_accel().without_gyro();
172 assert_eq!(config.target_mode(), OperatingMode::PowerOnDefault);
173 }
174}