bma400/config/
gen_int_config.rs

1pub(crate) use crate::{
2    BMA400, ConfigError, DataSource, GenIntCriterionMode, GenIntLogicMode, GenIntRefMode,
3    Hysteresis, OutputDataRate,
4    config::Config,
5    registers::{
6        Gen1IntConfig0, Gen1IntConfig1, Gen1IntConfig2, Gen1IntConfig3, Gen1IntConfig4,
7        Gen1IntConfig5, Gen1IntConfig6, Gen1IntConfig7, Gen1IntConfig8, Gen1IntConfig9,
8        Gen1IntConfig31, Gen2IntConfig0, Gen2IntConfig1, Gen2IntConfig2, Gen2IntConfig3,
9        Gen2IntConfig4, Gen2IntConfig5, Gen2IntConfig6, Gen2IntConfig7, Gen2IntConfig8,
10        Gen2IntConfig9, Gen2IntConfig31,
11    },
12};
13
14#[derive(Clone, Default)]
15pub struct Gen1IntConfig {
16    config0: Gen1IntConfig0,
17    config1: Gen1IntConfig1,
18    config2: Gen1IntConfig2,
19    config3: Gen1IntConfig3,
20    config31: Gen1IntConfig31,
21    config4: Gen1IntConfig4,
22    config5: Gen1IntConfig5,
23    config6: Gen1IntConfig6,
24    config7: Gen1IntConfig7,
25    config8: Gen1IntConfig8,
26    config9: Gen1IntConfig9,
27}
28
29impl Gen1IntConfig {
30    pub fn src(&self) -> DataSource {
31        self.config0.src()
32    }
33}
34
35#[derive(Clone, Default)]
36pub struct Gen2IntConfig {
37    config0: Gen2IntConfig0,
38    config1: Gen2IntConfig1,
39    config2: Gen2IntConfig2,
40    config3: Gen2IntConfig3,
41    config31: Gen2IntConfig31,
42    config4: Gen2IntConfig4,
43    config5: Gen2IntConfig5,
44    config6: Gen2IntConfig6,
45    config7: Gen2IntConfig7,
46    config8: Gen2IntConfig8,
47    config9: Gen2IntConfig9,
48}
49
50impl Gen2IntConfig {
51    pub fn src(&self) -> DataSource {
52        self.config0.src()
53    }
54}
55
56pub enum GenIntConfig {
57    Gen1Int(Gen1IntConfig),
58    Gen2Int(Gen2IntConfig),
59}
60
61impl GenIntConfig {
62    pub fn src(&self) -> DataSource {
63        match self {
64            GenIntConfig::Gen1Int(config) => config.src(),
65            GenIntConfig::Gen2Int(config) => config.src(),
66        }
67    }
68}
69
70/// Configure Generic Interrupt settings
71///
72/// - Enable / Disable axes evaluated for the interrupt trigger condition using [`with_axes()`](GenIntConfigBuilder::with_axes)
73/// - [DataSource] used for evaluating the trigger condition using [`with_src()`](GenIntConfigBuilder::with_src)
74/// - Set the [GenIntRefMode] (reference acceleration update mode) using [`with_ref_mode()`](GenIntConfigBuilder::with_ref_mode)
75/// - Set the [Hysteresis] adjustment amplitude using [`with_hysteresis()`](GenIntConfigBuilder::with_hysteresis)
76/// - Set the [GenIntCriterionMode] (trigger on activity / inactivity) using [`with_criterion_mode()`](GenIntConfigBuilder::with_criterion_mode)
77/// - Set the [GenIntLogicMode] (trigger on any / all axes) using [`with_logic_mode()`](GenIntConfigBuilder::with_logic_mode)
78/// - Set the interrupt trigger threshold using [`with_threshold()`](GenIntConfigBuilder::with_threshold)
79/// - Set the number of cycles that the interrupt condition must be true before the interrupt triggers using [`with_duration()`](GenIntConfigBuilder::with_duration)
80/// - Manually set the reference acceleration for the interrupt trigger condition using [`with_ref_accel()`](GenIntConfigBuilder::with_ref_accel)
81pub struct GenIntConfigBuilder<'a, Interface> {
82    config: GenIntConfig,
83    device: &'a mut BMA400<Interface>,
84}
85
86#[cfg(not(feature = "embedded-hal-async"))]
87impl<'a, Interface, E> GenIntConfigBuilder<'a, Interface>
88where
89    Interface: crate::blocking::WriteToRegister<Error = E>,
90    E: From<ConfigError>,
91{
92    /// Write this configuration to device registers
93    pub fn write(self) -> Result<(), E> {
94        let has_config0_changes = self.has_config0_changes_from(&self.device.config);
95        let has_config1_changes = self.has_config1_changes_from(&self.device.config);
96        let has_config2_changes = self.has_config2_changes_from(&self.device.config);
97        let has_config3_changes = self.has_config3_changes_from(&self.device.config);
98        let has_config31_changes = self.has_config31_changes_from(&self.device.config);
99        let has_config4_changes = self.has_config4_changes_from(&self.device.config);
100        let has_config5_changes = self.has_config5_changes_from(&self.device.config);
101        let has_config6_changes = self.has_config6_changes_from(&self.device.config);
102        let has_config7_changes = self.has_config7_changes_from(&self.device.config);
103        let has_config8_changes = self.has_config8_changes_from(&self.device.config);
104        let has_config9_changes = self.has_config9_changes_from(&self.device.config);
105
106        let has_changes = has_config0_changes
107            || has_config1_changes
108            || has_config2_changes
109            || has_config3_changes
110            || has_config31_changes
111            || has_config4_changes
112            || has_config5_changes
113            || has_config6_changes
114            || has_config7_changes
115            || has_config8_changes
116            || has_config9_changes;
117
118        // If there aren't any changes, return early
119        if !has_changes {
120            return Ok(());
121        }
122        // Clone the existing enabled interrupts
123        let mut int_config0 = self.device.config.int_config.get_config0();
124        let int_enabled = match &self.config {
125            GenIntConfig::Gen1Int(_) => int_config0.gen1_int(),
126            GenIntConfig::Gen2Int(_) => int_config0.gen2_int(),
127        };
128        // If the interrupt is enabled and we're changing the data source to AccFilt1 the ODR must
129        // be 100Hz
130        if int_enabled
131            && !matches!(self.device.config.acc_config.odr(), OutputDataRate::Hz100)
132            && matches!(self.config.src(), DataSource::AccFilt1)
133        {
134            return Err(ConfigError::Filt1InterruptInvalidODR.into());
135        }
136        // If there are changes and the interrupt is active, need to disable interrupt before
137        // writing changes
138        match &self.config {
139            GenIntConfig::Gen1Int(_) => {
140                if int_enabled {
141                    int_config0 = int_config0.with_gen1_int(false);
142                    self.device.interface.write_register(int_config0)?;
143                }
144            }
145            GenIntConfig::Gen2Int(_) => {
146                if int_enabled {
147                    int_config0 = int_config0.with_gen2_int(false);
148                    self.device.interface.write_register(int_config0)?;
149                }
150            }
151        }
152        if has_config0_changes {
153            match &self.config {
154                GenIntConfig::Gen1Int(config) => {
155                    self.device.interface.write_register(config.config0)?;
156                    self.device.config.gen1int_config.config0 = config.config0;
157                }
158                GenIntConfig::Gen2Int(config) => {
159                    self.device.interface.write_register(config.config0)?;
160                    self.device.config.gen2int_config.config0 = config.config0;
161                }
162            }
163        }
164        if has_config1_changes {
165            match &self.config {
166                GenIntConfig::Gen1Int(config) => {
167                    self.device.interface.write_register(config.config1)?;
168                    self.device.config.gen1int_config.config1 = config.config1;
169                }
170                GenIntConfig::Gen2Int(config) => {
171                    self.device.interface.write_register(config.config1)?;
172                    self.device.config.gen2int_config.config1 = config.config1;
173                }
174            }
175        }
176        if has_config2_changes {
177            match &self.config {
178                GenIntConfig::Gen1Int(config) => {
179                    self.device.interface.write_register(config.config2)?;
180                    self.device.config.gen1int_config.config2 = config.config2;
181                }
182                GenIntConfig::Gen2Int(config) => {
183                    self.device.interface.write_register(config.config2)?;
184                    self.device.config.gen2int_config.config2 = config.config2;
185                }
186            }
187        }
188        if has_config3_changes {
189            match &self.config {
190                GenIntConfig::Gen1Int(config) => {
191                    self.device.interface.write_register(config.config3)?;
192                    self.device.config.gen1int_config.config3 = config.config3;
193                }
194                GenIntConfig::Gen2Int(config) => {
195                    self.device.interface.write_register(config.config3)?;
196                    self.device.config.gen2int_config.config3 = config.config3;
197                }
198            }
199        }
200        if has_config31_changes {
201            match &self.config {
202                GenIntConfig::Gen1Int(config) => {
203                    self.device.interface.write_register(config.config31)?;
204                    self.device.config.gen1int_config.config31 = config.config31;
205                }
206                GenIntConfig::Gen2Int(config) => {
207                    self.device.interface.write_register(config.config31)?;
208                    self.device.config.gen2int_config.config31 = config.config31;
209                }
210            }
211        }
212        if has_config4_changes {
213            match &self.config {
214                GenIntConfig::Gen1Int(config) => {
215                    self.device.interface.write_register(config.config4)?;
216                    self.device.config.gen1int_config.config4 = config.config4;
217                }
218                GenIntConfig::Gen2Int(config) => {
219                    self.device.interface.write_register(config.config4)?;
220                    self.device.config.gen2int_config.config4 = config.config4;
221                }
222            }
223        }
224        if has_config5_changes {
225            match &self.config {
226                GenIntConfig::Gen1Int(config) => {
227                    self.device.interface.write_register(config.config5)?;
228                    self.device.config.gen1int_config.config5 = config.config5;
229                }
230                GenIntConfig::Gen2Int(config) => {
231                    self.device.interface.write_register(config.config5)?;
232                    self.device.config.gen2int_config.config5 = config.config5;
233                }
234            }
235        }
236        if has_config6_changes {
237            match &self.config {
238                GenIntConfig::Gen1Int(config) => {
239                    self.device.interface.write_register(config.config6)?;
240                    self.device.config.gen1int_config.config6 = config.config6;
241                }
242                GenIntConfig::Gen2Int(config) => {
243                    self.device.interface.write_register(config.config6)?;
244                    self.device.config.gen2int_config.config6 = config.config6;
245                }
246            }
247        }
248        if has_config7_changes {
249            match &self.config {
250                GenIntConfig::Gen1Int(config) => {
251                    self.device.interface.write_register(config.config7)?;
252                    self.device.config.gen1int_config.config7 = config.config7;
253                }
254                GenIntConfig::Gen2Int(config) => {
255                    self.device.interface.write_register(config.config7)?;
256                    self.device.config.gen2int_config.config7 = config.config7;
257                }
258            }
259        }
260        if has_config8_changes {
261            match &self.config {
262                GenIntConfig::Gen1Int(config) => {
263                    self.device.interface.write_register(config.config8)?;
264                    self.device.config.gen1int_config.config8 = config.config8;
265                }
266                GenIntConfig::Gen2Int(config) => {
267                    self.device.interface.write_register(config.config8)?;
268                    self.device.config.gen2int_config.config8 = config.config8;
269                }
270            }
271        }
272        if has_config9_changes {
273            match &self.config {
274                GenIntConfig::Gen1Int(config) => {
275                    self.device.interface.write_register(config.config9)?;
276                    self.device.config.gen1int_config.config9 = config.config9;
277                }
278                GenIntConfig::Gen2Int(config) => {
279                    self.device.interface.write_register(config.config9)?;
280                    self.device.config.gen2int_config.config9 = config.config9;
281                }
282            }
283        }
284        // Re-enable interrupt, if it was disabled
285        if int_config0.bits() != self.device.config.int_config.get_config0().bits() {
286            self.device
287                .interface
288                .write_register(self.device.config.int_config.get_config0())?;
289        }
290        Ok(())
291    }
292}
293
294#[cfg(feature = "embedded-hal-async")]
295impl<'a, Interface, E> GenIntConfigBuilder<'a, Interface>
296where
297    Interface: crate::asynch::WriteToRegister<Error = E>,
298    E: From<ConfigError>,
299{
300    /// Write this configuration to device registers
301    pub async fn write(self) -> Result<(), E> {
302        let has_config0_changes = self.has_config0_changes_from(&self.device.config);
303        let has_config1_changes = self.has_config1_changes_from(&self.device.config);
304        let has_config2_changes = self.has_config2_changes_from(&self.device.config);
305        let has_config3_changes = self.has_config3_changes_from(&self.device.config);
306        let has_config31_changes = self.has_config31_changes_from(&self.device.config);
307        let has_config4_changes = self.has_config4_changes_from(&self.device.config);
308        let has_config5_changes = self.has_config5_changes_from(&self.device.config);
309        let has_config6_changes = self.has_config6_changes_from(&self.device.config);
310        let has_config7_changes = self.has_config7_changes_from(&self.device.config);
311        let has_config8_changes = self.has_config8_changes_from(&self.device.config);
312        let has_config9_changes = self.has_config9_changes_from(&self.device.config);
313
314        let has_changes = has_config0_changes
315            || has_config1_changes
316            || has_config2_changes
317            || has_config3_changes
318            || has_config31_changes
319            || has_config4_changes
320            || has_config5_changes
321            || has_config6_changes
322            || has_config7_changes
323            || has_config8_changes
324            || has_config9_changes;
325
326        // If there aren't any changes, return early
327        if !has_changes {
328            return Ok(());
329        }
330        // Clone the existing enabled interrupts
331        let mut int_config0 = self.device.config.int_config.get_config0();
332        let int_enabled = match &self.config {
333            GenIntConfig::Gen1Int(_) => int_config0.gen1_int(),
334            GenIntConfig::Gen2Int(_) => int_config0.gen2_int(),
335        };
336        // If the interrupt is enabled and we're changing the data source to AccFilt1 the ODR must
337        // be 100Hz
338        if int_enabled
339            && !matches!(self.device.config.acc_config.odr(), OutputDataRate::Hz100)
340            && matches!(self.config.src(), DataSource::AccFilt1)
341        {
342            return Err(ConfigError::Filt1InterruptInvalidODR.into());
343        }
344        // If there are changes and the interrupt is active, need to disable interrupt before
345        // writing changes
346        match &self.config {
347            GenIntConfig::Gen1Int(_) => {
348                if int_enabled {
349                    int_config0 = int_config0.with_gen1_int(false);
350                    self.device.interface.write_register(int_config0).await?;
351                }
352            }
353            GenIntConfig::Gen2Int(_) => {
354                if int_enabled {
355                    int_config0 = int_config0.with_gen2_int(false);
356                    self.device.interface.write_register(int_config0).await?;
357                }
358            }
359        }
360        if has_config0_changes {
361            match &self.config {
362                GenIntConfig::Gen1Int(config) => {
363                    self.device.interface.write_register(config.config0).await?;
364                    self.device.config.gen1int_config.config0 = config.config0;
365                }
366                GenIntConfig::Gen2Int(config) => {
367                    self.device.interface.write_register(config.config0).await?;
368                    self.device.config.gen2int_config.config0 = config.config0;
369                }
370            }
371        }
372        if has_config1_changes {
373            match &self.config {
374                GenIntConfig::Gen1Int(config) => {
375                    self.device.interface.write_register(config.config1).await?;
376                    self.device.config.gen1int_config.config1 = config.config1;
377                }
378                GenIntConfig::Gen2Int(config) => {
379                    self.device.interface.write_register(config.config1).await?;
380                    self.device.config.gen2int_config.config1 = config.config1;
381                }
382            }
383        }
384        if has_config2_changes {
385            match &self.config {
386                GenIntConfig::Gen1Int(config) => {
387                    self.device.interface.write_register(config.config2).await?;
388                    self.device.config.gen1int_config.config2 = config.config2;
389                }
390                GenIntConfig::Gen2Int(config) => {
391                    self.device.interface.write_register(config.config2).await?;
392                    self.device.config.gen2int_config.config2 = config.config2;
393                }
394            }
395        }
396        if has_config3_changes {
397            match &self.config {
398                GenIntConfig::Gen1Int(config) => {
399                    self.device.interface.write_register(config.config3).await?;
400                    self.device.config.gen1int_config.config3 = config.config3;
401                }
402                GenIntConfig::Gen2Int(config) => {
403                    self.device.interface.write_register(config.config3).await?;
404                    self.device.config.gen2int_config.config3 = config.config3;
405                }
406            }
407        }
408        if has_config31_changes {
409            match &self.config {
410                GenIntConfig::Gen1Int(config) => {
411                    self.device
412                        .interface
413                        .write_register(config.config31)
414                        .await?;
415                    self.device.config.gen1int_config.config31 = config.config31;
416                }
417                GenIntConfig::Gen2Int(config) => {
418                    self.device
419                        .interface
420                        .write_register(config.config31)
421                        .await?;
422                    self.device.config.gen2int_config.config31 = config.config31;
423                }
424            }
425        }
426        if has_config4_changes {
427            match &self.config {
428                GenIntConfig::Gen1Int(config) => {
429                    self.device.interface.write_register(config.config4).await?;
430                    self.device.config.gen1int_config.config4 = config.config4;
431                }
432                GenIntConfig::Gen2Int(config) => {
433                    self.device.interface.write_register(config.config4).await?;
434                    self.device.config.gen2int_config.config4 = config.config4;
435                }
436            }
437        }
438        if has_config5_changes {
439            match &self.config {
440                GenIntConfig::Gen1Int(config) => {
441                    self.device.interface.write_register(config.config5).await?;
442                    self.device.config.gen1int_config.config5 = config.config5;
443                }
444                GenIntConfig::Gen2Int(config) => {
445                    self.device.interface.write_register(config.config5).await?;
446                    self.device.config.gen2int_config.config5 = config.config5;
447                }
448            }
449        }
450        if has_config6_changes {
451            match &self.config {
452                GenIntConfig::Gen1Int(config) => {
453                    self.device.interface.write_register(config.config6).await?;
454                    self.device.config.gen1int_config.config6 = config.config6;
455                }
456                GenIntConfig::Gen2Int(config) => {
457                    self.device.interface.write_register(config.config6).await?;
458                    self.device.config.gen2int_config.config6 = config.config6;
459                }
460            }
461        }
462        if has_config7_changes {
463            match &self.config {
464                GenIntConfig::Gen1Int(config) => {
465                    self.device.interface.write_register(config.config7).await?;
466                    self.device.config.gen1int_config.config7 = config.config7;
467                }
468                GenIntConfig::Gen2Int(config) => {
469                    self.device.interface.write_register(config.config7).await?;
470                    self.device.config.gen2int_config.config7 = config.config7;
471                }
472            }
473        }
474        if has_config8_changes {
475            match &self.config {
476                GenIntConfig::Gen1Int(config) => {
477                    self.device.interface.write_register(config.config8).await?;
478                    self.device.config.gen1int_config.config8 = config.config8;
479                }
480                GenIntConfig::Gen2Int(config) => {
481                    self.device.interface.write_register(config.config8).await?;
482                    self.device.config.gen2int_config.config8 = config.config8;
483                }
484            }
485        }
486        if has_config9_changes {
487            match &self.config {
488                GenIntConfig::Gen1Int(config) => {
489                    self.device.interface.write_register(config.config9).await?;
490                    self.device.config.gen1int_config.config9 = config.config9;
491                }
492                GenIntConfig::Gen2Int(config) => {
493                    self.device.interface.write_register(config.config9).await?;
494                    self.device.config.gen2int_config.config9 = config.config9;
495                }
496            }
497        }
498        // Re-enable interrupt, if it was disabled
499        if int_config0.bits() != self.device.config.int_config.get_config0().bits() {
500            self.device
501                .interface
502                .write_register(self.device.config.int_config.get_config0())
503                .await?;
504        }
505        Ok(())
506    }
507}
508
509impl<'a, Interface> GenIntConfigBuilder<'a, Interface> {
510    pub(crate) fn new_gen1(
511        device: &'a mut BMA400<Interface>,
512    ) -> GenIntConfigBuilder<'a, Interface> {
513        let config = GenIntConfig::Gen1Int(device.config.gen1int_config.clone());
514        GenIntConfigBuilder { config, device }
515    }
516    pub(crate) fn new_gen2(
517        device: &'a mut BMA400<Interface>,
518    ) -> GenIntConfigBuilder<'a, Interface> {
519        let config = GenIntConfig::Gen2Int(device.config.gen2int_config.clone());
520        GenIntConfigBuilder { config, device }
521    }
522    // Config0
523    /// Select the axes to be considered when evaluating the generic interrupt criterion
524    pub fn with_axes(mut self, x: bool, y: bool, z: bool) -> Self {
525        match &mut self.config {
526            GenIntConfig::Gen1Int(config) => {
527                config.config0 = config.config0.with_x_axis(x).with_y_axis(y).with_z_axis(z)
528            }
529            GenIntConfig::Gen2Int(config) => {
530                config.config0 = config.config0.with_x_axis(x).with_y_axis(y).with_z_axis(z)
531            }
532        }
533        self
534    }
535    /// Set the data source to use when evaluating the generic interrupt criterion
536    ///
537    /// Cannot use [DataSource::AccFilt2Lp]. If passed, this will default to [DataSource::AccFilt2]
538    pub fn with_src(mut self, src: DataSource) -> Self {
539        let src = match src {
540            DataSource::AccFilt2Lp => DataSource::AccFilt2,
541            _ => src,
542        };
543        match &mut self.config {
544            GenIntConfig::Gen1Int(config) => config.config0 = config.config0.with_src(src),
545            GenIntConfig::Gen2Int(config) => config.config0 = config.config0.with_src(src),
546        }
547        self
548    }
549    /// Set the reference acceleration update mode for the generic interrupt
550    pub fn with_ref_mode(mut self, mode: GenIntRefMode) -> Self {
551        match &mut self.config {
552            GenIntConfig::Gen1Int(config) => config.config0 = config.config0.with_refu_mode(mode),
553            GenIntConfig::Gen2Int(config) => config.config0 = config.config0.with_refu_mode(mode),
554        }
555        self
556    }
557    /// Set the amplitude of the hysteresis adjustment to the interrupt criteria
558    pub fn with_hysteresis(mut self, hysteresis: Hysteresis) -> Self {
559        match &mut self.config {
560            GenIntConfig::Gen1Int(config) => {
561                config.config0 = config.config0.with_act_hysteresis(hysteresis)
562            }
563            GenIntConfig::Gen2Int(config) => {
564                config.config0 = config.config0.with_act_hysteresis(hysteresis)
565            }
566        }
567        self
568    }
569    // Config1
570    /// Set the interrupt trigger condition (on Activity or Inactivity)
571    pub fn with_criterion_mode(mut self, mode: GenIntCriterionMode) -> Self {
572        match &mut self.config {
573            GenIntConfig::Gen1Int(config) => {
574                config.config1 = config.config1.with_criterion_sel(mode)
575            }
576            GenIntConfig::Gen2Int(config) => {
577                config.config1 = config.config1.with_criterion_sel(mode)
578            }
579        }
580        self
581    }
582    /// Set the interrupt trigger behavior when multiple axes are selected
583    pub fn with_logic_mode(mut self, mode: GenIntLogicMode) -> Self {
584        match &mut self.config {
585            GenIntConfig::Gen1Int(config) => config.config1 = config.config1.with_comb_sel(mode),
586            GenIntConfig::Gen2Int(config) => config.config1 = config.config1.with_comb_sel(mode),
587        }
588        self
589    }
590    // Config2
591    /// Set the threshold above or below reference acceleration at which the interrupt criterion
592    /// evaluates to true
593    ///
594    /// This is not adjusted by scale, and is compared against the 8 msb of the acceleration (8
595    /// milli-g resolution)
596    pub fn with_threshold(mut self, threshold: u8) -> Self {
597        match &mut self.config {
598            GenIntConfig::Gen1Int(config) => {
599                config.config2 = config.config2.with_threshold(threshold)
600            }
601            GenIntConfig::Gen2Int(config) => {
602                config.config2 = config.config2.with_threshold(threshold)
603            }
604        }
605        self
606    }
607    // Config3 and Config31
608    /// Set the number of cycles that the interrupt criterion must evaluate to true before the
609    /// interrupt triggers
610    ///
611    /// Note that the actual time duration depends on the ODR of the [DataSource] used
612    pub fn with_duration(mut self, duration: u16) -> Self {
613        match &mut self.config {
614            GenIntConfig::Gen1Int(config) => {
615                config.config3 = config.config3.with_duration_msb(duration.to_le_bytes()[1]);
616                config.config31 = config.config31.with_duration_lsb(duration.to_le_bytes()[0]);
617            }
618            GenIntConfig::Gen2Int(config) => {
619                config.config3 = config.config3.with_duration_msb(duration.to_le_bytes()[1]);
620                config.config31 = config.config31.with_duration_lsb(duration.to_le_bytes()[0]);
621            }
622        }
623        self
624    }
625    // Config4-9
626    /// Manually set the reference acceleration for the interrupt criterion. This is
627    /// automatically overwritten if [`GenIntRefMode::Manual`] is not set.
628    ///
629    /// 12-bit, clamped to \[-2048, 2047\] and scales with [crate::Scale]
630    pub fn with_ref_accel(mut self, ref_x: i16, ref_y: i16, ref_z: i16) -> Self {
631        let (ref_x, ref_y, ref_z) = (
632            ref_x.clamp(-2048, 2047),
633            ref_y.clamp(-2048, 2047),
634            ref_z.clamp(-2048, 2047),
635        );
636        match &mut self.config {
637            GenIntConfig::Gen1Int(config) => {
638                config.config4 = config.config4.with_ref_x_lsb(ref_x.to_le_bytes()[0]);
639                config.config5 = config.config5.with_ref_x_msb(ref_x.to_le_bytes()[1]);
640                config.config6 = config.config6.with_ref_y_lsb(ref_y.to_le_bytes()[0]);
641                config.config7 = config.config7.with_ref_y_msb(ref_y.to_le_bytes()[1]);
642                config.config8 = config.config8.with_ref_z_lsb(ref_z.to_le_bytes()[0]);
643                config.config9 = config.config9.with_ref_z_msb(ref_z.to_le_bytes()[1]);
644            }
645            GenIntConfig::Gen2Int(config) => {
646                config.config4 = config.config4.with_ref_x_lsb(ref_x.to_le_bytes()[0]);
647                config.config5 = config.config5.with_ref_x_msb(ref_x.to_le_bytes()[1]);
648                config.config6 = config.config6.with_ref_y_lsb(ref_y.to_le_bytes()[0]);
649                config.config7 = config.config7.with_ref_y_msb(ref_y.to_le_bytes()[1]);
650                config.config8 = config.config8.with_ref_z_lsb(ref_z.to_le_bytes()[0]);
651                config.config9 = config.config9.with_ref_z_msb(ref_z.to_le_bytes()[1]);
652            }
653        }
654        self
655    }
656
657    /// Write this configuration to device registers
658    // Detect changes to assess whether to skip writing registers
659    fn has_config0_changes_from(&self, device_config: &Config) -> bool {
660        match &self.config {
661            GenIntConfig::Gen1Int(config) => {
662                config.config0.bits() != device_config.gen1int_config.config0.bits()
663            }
664            GenIntConfig::Gen2Int(config) => {
665                config.config0.bits() != device_config.gen2int_config.config0.bits()
666            }
667        }
668    }
669    fn has_config1_changes_from(&self, device_config: &Config) -> bool {
670        match &self.config {
671            GenIntConfig::Gen1Int(config) => {
672                config.config1.bits() != device_config.gen1int_config.config1.bits()
673            }
674            GenIntConfig::Gen2Int(config) => {
675                config.config1.bits() != device_config.gen2int_config.config1.bits()
676            }
677        }
678    }
679    fn has_config2_changes_from(&self, device_config: &Config) -> bool {
680        match &self.config {
681            GenIntConfig::Gen1Int(config) => {
682                config.config2.bits() != device_config.gen1int_config.config2.bits()
683            }
684            GenIntConfig::Gen2Int(config) => {
685                config.config2.bits() != device_config.gen2int_config.config2.bits()
686            }
687        }
688    }
689    fn has_config3_changes_from(&self, device_config: &Config) -> bool {
690        match &self.config {
691            GenIntConfig::Gen1Int(config) => {
692                config.config3.bits() != device_config.gen1int_config.config3.bits()
693            }
694            GenIntConfig::Gen2Int(config) => {
695                config.config3.bits() != device_config.gen2int_config.config3.bits()
696            }
697        }
698    }
699    fn has_config31_changes_from(&self, device_config: &Config) -> bool {
700        match &self.config {
701            GenIntConfig::Gen1Int(config) => {
702                config.config31.bits() != device_config.gen1int_config.config31.bits()
703            }
704            GenIntConfig::Gen2Int(config) => {
705                config.config31.bits() != device_config.gen2int_config.config31.bits()
706            }
707        }
708    }
709    fn has_config4_changes_from(&self, device_config: &Config) -> bool {
710        match &self.config {
711            GenIntConfig::Gen1Int(config) => {
712                config.config4.bits() != device_config.gen1int_config.config4.bits()
713            }
714            GenIntConfig::Gen2Int(config) => {
715                config.config4.bits() != device_config.gen2int_config.config4.bits()
716            }
717        }
718    }
719    fn has_config5_changes_from(&self, device_config: &Config) -> bool {
720        match &self.config {
721            GenIntConfig::Gen1Int(config) => {
722                config.config5.bits() != device_config.gen1int_config.config5.bits()
723            }
724            GenIntConfig::Gen2Int(config) => {
725                config.config5.bits() != device_config.gen2int_config.config5.bits()
726            }
727        }
728    }
729    fn has_config6_changes_from(&self, device_config: &Config) -> bool {
730        match &self.config {
731            GenIntConfig::Gen1Int(config) => {
732                config.config6.bits() != device_config.gen1int_config.config6.bits()
733            }
734            GenIntConfig::Gen2Int(config) => {
735                config.config6.bits() != device_config.gen2int_config.config6.bits()
736            }
737        }
738    }
739    fn has_config7_changes_from(&self, device_config: &Config) -> bool {
740        match &self.config {
741            GenIntConfig::Gen1Int(config) => {
742                config.config7.bits() != device_config.gen1int_config.config7.bits()
743            }
744            GenIntConfig::Gen2Int(config) => {
745                config.config7.bits() != device_config.gen2int_config.config7.bits()
746            }
747        }
748    }
749    fn has_config8_changes_from(&self, device_config: &Config) -> bool {
750        match &self.config {
751            GenIntConfig::Gen1Int(config) => {
752                config.config8.bits() != device_config.gen1int_config.config8.bits()
753            }
754            GenIntConfig::Gen2Int(config) => {
755                config.config8.bits() != device_config.gen2int_config.config8.bits()
756            }
757        }
758    }
759    fn has_config9_changes_from(&self, device_config: &Config) -> bool {
760        match &self.config {
761            GenIntConfig::Gen1Int(config) => {
762                config.config9.bits() != device_config.gen1int_config.config9.bits()
763            }
764            GenIntConfig::Gen2Int(config) => {
765                config.config9.bits() != device_config.gen2int_config.config9.bits()
766            }
767        }
768    }
769}
770
771#[cfg(test)]
772mod tests {
773    use super::*;
774    use crate::{BMA400Error, tests::get_test_device};
775    #[test]
776    fn test_axes() {
777        let mut device = get_test_device();
778        let builder = device.config_gen1_int();
779        assert!(matches!(builder.config, GenIntConfig::Gen1Int(_)));
780        let builder = builder.with_axes(false, false, true);
781        if let GenIntConfig::Gen1Int(config) = &builder.config {
782            assert_eq!(config.config0.bits(), 0x80);
783        }
784        let builder = builder.with_axes(false, true, false);
785        if let GenIntConfig::Gen1Int(config) = &builder.config {
786            assert_eq!(config.config0.bits(), 0x40);
787        }
788        let builder = builder.with_axes(true, false, false);
789        if let GenIntConfig::Gen1Int(config) = &builder.config {
790            assert_eq!(config.config0.bits(), 0x20);
791        }
792
793        let builder = device.config_gen2_int();
794        assert!(matches!(builder.config, GenIntConfig::Gen2Int(_)));
795        let builder = builder.with_axes(false, false, true);
796        if let GenIntConfig::Gen2Int(config) = &builder.config {
797            assert_eq!(config.config0.bits(), 0x80);
798        }
799        let builder = builder.with_axes(false, true, false);
800        if let GenIntConfig::Gen2Int(config) = &builder.config {
801            assert_eq!(config.config0.bits(), 0x40);
802        }
803        let builder = builder.with_axes(true, false, false);
804        if let GenIntConfig::Gen2Int(config) = &builder.config {
805            assert_eq!(config.config0.bits(), 0x20);
806        }
807    }
808    #[test]
809    fn test_src() {
810        let mut device = get_test_device();
811        let builder = device.config_gen1_int();
812        assert!(matches!(builder.config, GenIntConfig::Gen1Int(_)));
813        let builder = builder.with_src(DataSource::AccFilt2Lp);
814        if let GenIntConfig::Gen1Int(config) = &builder.config {
815            assert_eq!(config.config0.bits(), 0x10);
816        }
817        let builder = builder.with_src(DataSource::AccFilt1);
818        if let GenIntConfig::Gen1Int(config) = &builder.config {
819            assert_eq!(config.config0.bits(), 0x00);
820        }
821        let builder = builder.with_src(DataSource::AccFilt2);
822        if let GenIntConfig::Gen1Int(config) = &builder.config {
823            assert_eq!(config.config0.bits(), 0x10);
824        }
825
826        let builder = device.config_gen2_int();
827        assert!(matches!(builder.config, GenIntConfig::Gen2Int(_)));
828        let builder = builder.with_src(DataSource::AccFilt2Lp);
829        if let GenIntConfig::Gen2Int(config) = &builder.config {
830            assert_eq!(config.config0.bits(), 0x10);
831        }
832        let builder = builder.with_src(DataSource::AccFilt1);
833        if let GenIntConfig::Gen2Int(config) = &builder.config {
834            assert_eq!(config.config0.bits(), 0x00);
835        }
836        let builder = builder.with_src(DataSource::AccFilt2);
837        if let GenIntConfig::Gen2Int(config) = &builder.config {
838            assert_eq!(config.config0.bits(), 0x10);
839        }
840    }
841    #[test]
842    fn test_reference_mode() {
843        let mut device = get_test_device();
844        let builder = device.config_gen1_int();
845        assert!(matches!(builder.config, GenIntConfig::Gen1Int(_)));
846        let builder = builder.with_ref_mode(GenIntRefMode::OneTime);
847        if let GenIntConfig::Gen1Int(config) = &builder.config {
848            assert_eq!(config.config0.bits(), 0x04);
849        }
850        let builder = builder.with_ref_mode(GenIntRefMode::EveryTimeFromSrc);
851        if let GenIntConfig::Gen1Int(config) = &builder.config {
852            assert_eq!(config.config0.bits(), 0x08);
853        }
854        let builder = builder.with_ref_mode(GenIntRefMode::EveryTimeFromLp);
855        if let GenIntConfig::Gen1Int(config) = &builder.config {
856            assert_eq!(config.config0.bits(), 0x0C);
857        }
858        let builder = builder.with_ref_mode(GenIntRefMode::Manual);
859        if let GenIntConfig::Gen1Int(config) = &builder.config {
860            assert_eq!(config.config0.bits(), 0x00);
861        }
862
863        let builder = device.config_gen2_int();
864        assert!(matches!(builder.config, GenIntConfig::Gen2Int(_)));
865        let builder = builder.with_ref_mode(GenIntRefMode::OneTime);
866        if let GenIntConfig::Gen2Int(config) = &builder.config {
867            assert_eq!(config.config0.bits(), 0x04);
868        }
869        let builder = builder.with_ref_mode(GenIntRefMode::EveryTimeFromSrc);
870        if let GenIntConfig::Gen2Int(config) = &builder.config {
871            assert_eq!(config.config0.bits(), 0x08);
872        }
873        let builder = builder.with_ref_mode(GenIntRefMode::EveryTimeFromLp);
874        if let GenIntConfig::Gen2Int(config) = &builder.config {
875            assert_eq!(config.config0.bits(), 0x0C);
876        }
877        let builder = builder.with_ref_mode(GenIntRefMode::Manual);
878        if let GenIntConfig::Gen2Int(config) = &builder.config {
879            assert_eq!(config.config0.bits(), 0x00);
880        }
881    }
882    #[test]
883    fn test_hysteresis() {
884        let mut device = get_test_device();
885        let builder = device.config_gen1_int();
886        assert!(matches!(builder.config, GenIntConfig::Gen1Int(_)));
887        let builder = builder.with_hysteresis(Hysteresis::Hyst96mg);
888        if let GenIntConfig::Gen1Int(config) = &builder.config {
889            assert_eq!(config.config0.bits(), 0x03);
890        }
891        let builder = builder.with_hysteresis(Hysteresis::Hyst48mg);
892        if let GenIntConfig::Gen1Int(config) = &builder.config {
893            assert_eq!(config.config0.bits(), 0x02);
894        }
895        let builder = builder.with_hysteresis(Hysteresis::Hyst24mg);
896        if let GenIntConfig::Gen1Int(config) = &builder.config {
897            assert_eq!(config.config0.bits(), 0x01);
898        }
899        let builder = builder.with_hysteresis(Hysteresis::None);
900        if let GenIntConfig::Gen1Int(config) = &builder.config {
901            assert_eq!(config.config0.bits(), 0x00);
902        }
903
904        let builder = device.config_gen2_int();
905        assert!(matches!(builder.config, GenIntConfig::Gen2Int(_)));
906        let builder = builder.with_hysteresis(Hysteresis::Hyst96mg);
907        if let GenIntConfig::Gen2Int(config) = &builder.config {
908            assert_eq!(config.config0.bits(), 0x03);
909        }
910        let builder = builder.with_hysteresis(Hysteresis::Hyst48mg);
911        if let GenIntConfig::Gen2Int(config) = &builder.config {
912            assert_eq!(config.config0.bits(), 0x02);
913        }
914        let builder = builder.with_hysteresis(Hysteresis::Hyst24mg);
915        if let GenIntConfig::Gen2Int(config) = &builder.config {
916            assert_eq!(config.config0.bits(), 0x01);
917        }
918        let builder = builder.with_hysteresis(Hysteresis::None);
919        if let GenIntConfig::Gen2Int(config) = &builder.config {
920            assert_eq!(config.config0.bits(), 0x00);
921        }
922    }
923    #[test]
924    fn test_criterion_mode() {
925        let mut device = get_test_device();
926        let builder = device.config_gen1_int();
927        assert!(matches!(builder.config, GenIntConfig::Gen1Int(_)));
928        let builder = builder.with_criterion_mode(GenIntCriterionMode::Activity);
929        if let GenIntConfig::Gen1Int(config) = &builder.config {
930            assert_eq!(config.config1.bits(), 0x02);
931        }
932        let builder = builder.with_criterion_mode(GenIntCriterionMode::Inactivity);
933        if let GenIntConfig::Gen1Int(config) = &builder.config {
934            assert_eq!(config.config1.bits(), 0x00);
935        }
936
937        let builder = device.config_gen2_int();
938        assert!(matches!(builder.config, GenIntConfig::Gen2Int(_)));
939        let builder = builder.with_criterion_mode(GenIntCriterionMode::Activity);
940        if let GenIntConfig::Gen2Int(config) = &builder.config {
941            assert_eq!(config.config1.bits(), 0x02);
942        }
943        let builder = builder.with_criterion_mode(GenIntCriterionMode::Inactivity);
944        if let GenIntConfig::Gen2Int(config) = &builder.config {
945            assert_eq!(config.config1.bits(), 0x00);
946        }
947    }
948    #[test]
949    fn test_logic_mode() {
950        let mut device = get_test_device();
951        let builder = device.config_gen1_int();
952        assert!(matches!(builder.config, GenIntConfig::Gen1Int(_)));
953        let builder = builder.with_logic_mode(GenIntLogicMode::And);
954        if let GenIntConfig::Gen1Int(config) = &builder.config {
955            assert_eq!(config.config1.bits(), 0x01);
956        }
957        let builder = builder.with_logic_mode(GenIntLogicMode::Or);
958        if let GenIntConfig::Gen1Int(config) = &builder.config {
959            assert_eq!(config.config1.bits(), 0x00);
960        }
961
962        let builder = device.config_gen2_int();
963        assert!(matches!(builder.config, GenIntConfig::Gen2Int(_)));
964        let builder = builder.with_logic_mode(GenIntLogicMode::And);
965        if let GenIntConfig::Gen2Int(config) = &builder.config {
966            assert_eq!(config.config1.bits(), 0x01);
967        }
968        let builder = builder.with_logic_mode(GenIntLogicMode::Or);
969        if let GenIntConfig::Gen2Int(config) = &builder.config {
970            assert_eq!(config.config1.bits(), 0x00);
971        }
972    }
973    #[test]
974    fn test_threshold() {
975        let mut device = get_test_device();
976        let builder = device.config_gen1_int();
977        assert!(matches!(builder.config, GenIntConfig::Gen1Int(_)));
978        let builder = builder.with_threshold(0xFF);
979        if let GenIntConfig::Gen1Int(config) = &builder.config {
980            assert_eq!(config.config2.bits(), 0xFF);
981        }
982        let builder = builder.with_threshold(0);
983        if let GenIntConfig::Gen1Int(config) = &builder.config {
984            assert_eq!(config.config2.bits(), 0);
985        }
986
987        let builder = device.config_gen2_int();
988        assert!(matches!(builder.config, GenIntConfig::Gen2Int(_)));
989        let builder = builder.with_threshold(0xFF);
990        if let GenIntConfig::Gen2Int(config) = &builder.config {
991            assert_eq!(config.config2.bits(), 0xFF);
992        }
993        let builder = builder.with_threshold(0);
994        if let GenIntConfig::Gen2Int(config) = &builder.config {
995            assert_eq!(config.config2.bits(), 0);
996        }
997    }
998    #[test]
999    fn test_duration() {
1000        let mut device = get_test_device();
1001        let builder = device.config_gen1_int();
1002        assert!(matches!(builder.config, GenIntConfig::Gen1Int(_)));
1003        let builder = builder.with_duration(0xFF00);
1004        if let GenIntConfig::Gen1Int(config) = &builder.config {
1005            assert_eq!(config.config3.bits(), 0xFF);
1006            assert_eq!(config.config31.bits(), 0x00);
1007        }
1008        let builder = builder.with_duration(0x00FF);
1009        if let GenIntConfig::Gen1Int(config) = &builder.config {
1010            assert_eq!(config.config3.bits(), 0x00);
1011            assert_eq!(config.config31.bits(), 0xFF);
1012        }
1013
1014        let builder = device.config_gen2_int();
1015        assert!(matches!(builder.config, GenIntConfig::Gen2Int(_)));
1016        let builder = builder.with_duration(0xFF00);
1017        if let GenIntConfig::Gen2Int(config) = &builder.config {
1018            assert_eq!(config.config3.bits(), 0xFF);
1019            assert_eq!(config.config31.bits(), 0x00);
1020        }
1021        let builder = builder.with_duration(0x00FF);
1022        if let GenIntConfig::Gen2Int(config) = &builder.config {
1023            assert_eq!(config.config3.bits(), 0x00);
1024            assert_eq!(config.config31.bits(), 0xFF);
1025        }
1026    }
1027    #[test]
1028    fn test_int1_config_err() {
1029        let mut device = get_test_device();
1030        // Change the data source to AccFilt2
1031        assert!(matches!(
1032            device
1033                .config_gen1_int()
1034                .with_src(DataSource::AccFilt2)
1035                .write(),
1036            Ok(())
1037        ));
1038        // Enable the interrupt
1039        assert!(matches!(
1040            device.config_interrupts().with_gen1_int(true).write(),
1041            Ok(())
1042        ));
1043        // Try to change the data source back to AccFilt1 while the interrupt is enabled
1044        assert!(matches!(
1045            device
1046                .config_gen1_int()
1047                .with_src(DataSource::AccFilt1)
1048                .write(),
1049            Err(BMA400Error::ConfigBuildError(
1050                ConfigError::Filt1InterruptInvalidODR
1051            ))
1052        ));
1053    }
1054    #[test]
1055    fn test_int2_config_err() {
1056        let mut device = get_test_device();
1057        // Change the data source to AccFilt2
1058        assert!(matches!(
1059            device
1060                .config_gen2_int()
1061                .with_src(DataSource::AccFilt2)
1062                .write(),
1063            Ok(())
1064        ));
1065        // Enable the interrupt
1066        assert!(matches!(
1067            device.config_interrupts().with_gen2_int(true).write(),
1068            Ok(())
1069        ));
1070        // Try to change the data source back to AccFilt1 while the interrupt is enabled
1071        assert!(matches!(
1072            device
1073                .config_gen2_int()
1074                .with_src(DataSource::AccFilt1)
1075                .write(),
1076            Err(BMA400Error::ConfigBuildError(
1077                ConfigError::Filt1InterruptInvalidODR
1078            ))
1079        ));
1080    }
1081}