1use embedded_hal_async::delay::DelayNs as AsyncDelayNs;
2use embedded_hal_async::digital::Wait;
3
4use crate::registers::{
5 ACC_CONF, ACC_DATA_X, ALT_ACC_CONF, ALT_CONF, ALT_GYR_CONF, ALT_STATUS, BMI323_CHIP_ID,
6 CHIP_ID, CMD, ERR_REG, EXT_ALT_CONFIG_CHG, EXT_ANYMO_1, EXT_ANYMO_2, EXT_ANYMO_3, EXT_FLAT_1,
7 EXT_FLAT_2, EXT_GEN_SET_1, EXT_NOMO_1, EXT_NOMO_2, EXT_NOMO_3, EXT_ORIENT_1, EXT_ORIENT_2,
8 EXT_SC_1, EXT_SIGMO_1, EXT_SIGMO_2, EXT_SIGMO_3, EXT_ST_RESULT, EXT_ST_SELECT, EXT_TAP_1,
9 EXT_TAP_2, EXT_TAP_3, EXT_TILT_1, EXT_TILT_2, FEATURE_CTRL, FEATURE_DATA_ADDR, FEATURE_DATA_TX,
10 FEATURE_IO_STATUS, FEATURE_IO0, FEATURE_IO1, FEATURE_IO2, FEATURE_IO3, FIFO_CONF, FIFO_CTRL,
11 FIFO_DATA, FIFO_FILL_LEVEL, FIFO_WATERMARK, GYR_CONF, GYR_DATA_X, INT_CONF, IO_INT_CTRL,
12 SELF_TEST, SENSOR_TIME_0, SOFT_RESET, STATUS, TEMP_DATA, TransportKind, interrupt_map_location,
13 words_to_axis,
14};
15use crate::{
16 AccelConfig, ActiveLevel, AltAccelConfig, AltConfigControl, AltGyroConfig, AltStatus,
17 AnyMotionConfig, AsyncAccess, AxisData, Bmi323Async, DeviceState, Error, ErrorWord,
18 EventReportMode, FifoConfig, FlatConfig, GyroConfig, ImuData, InterruptChannel,
19 InterruptPinConfig, InterruptRoute, InterruptSource, InterruptStatus, NoMotionConfig,
20 OrientationConfig, OutputDataRate, OutputMode, ReferenceUpdate, SelfTestDetail, SelfTestResult,
21 SelfTestSelection, SignificantMotionConfig, StatusWord, StepCounterConfig, TapConfig,
22 TiltConfig,
23};
24
25impl<T> Bmi323Async<T>
26where
27 Self: AsyncAccess,
28{
29 pub async fn init<D: AsyncDelayNs>(
38 &mut self,
39 delay: &mut D,
40 ) -> Result<DeviceState, Error<<Self as AsyncAccess>::BusError>> {
41 self.soft_reset(delay).await?;
44
45 if matches!(self.kind, TransportKind::Spi) {
46 self.read_word(CHIP_ID).await.map_err(Error::Bus)?;
47 delay.delay_us(250).await;
48 }
49
50 let chip_id = self.read_word(CHIP_ID).await.map_err(Error::Bus)? as u8;
51 if chip_id != BMI323_CHIP_ID {
52 return Err(Error::InvalidChipId(chip_id));
53 }
54
55 let error = self.error_word().await?;
56 if error.fatal() {
57 return Err(Error::FatalError);
58 }
59
60 Ok(DeviceState {
61 chip_id,
62 status: self.status_word().await?,
63 error,
64 })
65 }
66
67 pub async fn soft_reset<D: AsyncDelayNs>(
69 &mut self,
70 delay: &mut D,
71 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
72 self.write_word(CMD, SOFT_RESET).await.map_err(Error::Bus)?;
73 delay.delay_ms(2).await;
74 Ok(())
75 }
76
77 pub async fn run_self_test<D: AsyncDelayNs>(
89 &mut self,
90 delay: &mut D,
91 selection: SelfTestSelection,
92 ) -> Result<SelfTestResult, Error<<Self as AsyncAccess>::BusError>> {
93 let saved_acc_conf = self.read_word(ACC_CONF).await.map_err(Error::Bus)?;
94 let saved_gyr_conf = self.read_word(GYR_CONF).await.map_err(Error::Bus)?;
95 let saved_alt_acc_conf = self.read_word(ALT_ACC_CONF).await.map_err(Error::Bus)?;
96 let saved_alt_gyr_conf = self.read_word(ALT_GYR_CONF).await.map_err(Error::Bus)?;
97 let saved_st_select = self.read_feature_word(EXT_ST_SELECT).await?;
98 let saved_accel_range = self.accel_range;
99 let saved_gyro_range = self.gyro_range;
100
101 let result = self.run_self_test_inner(delay, selection).await;
102 let restore = self
103 .restore_self_test_configuration(
104 saved_acc_conf,
105 saved_gyr_conf,
106 saved_alt_acc_conf,
107 saved_alt_gyr_conf,
108 saved_st_select,
109 )
110 .await;
111
112 self.accel_range = saved_accel_range;
113 self.gyro_range = saved_gyro_range;
114
115 match (result, restore) {
116 (Err(err), _) => Err(err),
117 (Ok(_), Err(err)) => Err(err),
118 (Ok(report), Ok(())) => Ok(report),
119 }
120 }
121
122 pub async fn status_word(
124 &mut self,
125 ) -> Result<StatusWord, Error<<Self as AsyncAccess>::BusError>> {
126 self.read_word(STATUS)
127 .await
128 .map(StatusWord)
129 .map_err(Error::Bus)
130 }
131
132 pub async fn error_word(
134 &mut self,
135 ) -> Result<ErrorWord, Error<<Self as AsyncAccess>::BusError>> {
136 self.read_word(ERR_REG)
137 .await
138 .map(ErrorWord)
139 .map_err(Error::Bus)
140 }
141
142 pub async fn set_accel_config(
147 &mut self,
148 config: AccelConfig,
149 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
150 self.write_word(ACC_CONF, config.to_word())
151 .await
152 .map_err(Error::Bus)?;
153 self.accel_range = config.range;
154 Ok(())
155 }
156
157 pub async fn set_gyro_config(
162 &mut self,
163 config: GyroConfig,
164 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
165 self.write_word(GYR_CONF, config.to_word())
166 .await
167 .map_err(Error::Bus)?;
168 self.gyro_range = config.range;
169 Ok(())
170 }
171
172 pub fn accel_range(&self) -> crate::AccelRange {
177 self.accel_range
178 }
179
180 pub fn gyro_range(&self) -> crate::GyroRange {
185 self.gyro_range
186 }
187
188 pub async fn read_accel(&mut self) -> Result<AxisData, Error<<Self as AsyncAccess>::BusError>> {
193 let mut words = [0u16; 3];
194 self.read_words(ACC_DATA_X, &mut words)
195 .await
196 .map_err(Error::Bus)?;
197 Ok(words_to_axis(words))
198 }
199
200 pub async fn read_gyro(&mut self) -> Result<AxisData, Error<<Self as AsyncAccess>::BusError>> {
205 let mut words = [0u16; 3];
206 self.read_words(GYR_DATA_X, &mut words)
207 .await
208 .map_err(Error::Bus)?;
209 Ok(words_to_axis(words))
210 }
211
212 pub async fn read_imu_data(
218 &mut self,
219 ) -> Result<ImuData, Error<<Self as AsyncAccess>::BusError>> {
220 let mut words = [0u16; 6];
221 self.read_words(ACC_DATA_X, &mut words)
222 .await
223 .map_err(Error::Bus)?;
224 Ok(ImuData {
225 accel: words_to_axis([words[0], words[1], words[2]]),
226 gyro: words_to_axis([words[3], words[4], words[5]]),
227 })
228 }
229
230 pub async fn read_temperature_celsius(
232 &mut self,
233 ) -> Result<f32, Error<<Self as AsyncAccess>::BusError>> {
234 let raw = self.read_word(TEMP_DATA).await.map_err(Error::Bus)? as i16;
235 Ok(raw as f32 / 512.0 + 23.0)
236 }
237
238 pub async fn read_sensor_time(
240 &mut self,
241 ) -> Result<u32, Error<<Self as AsyncAccess>::BusError>> {
242 let mut words = [0u16; 2];
243 self.read_words(SENSOR_TIME_0, &mut words)
244 .await
245 .map_err(Error::Bus)?;
246 Ok(words[0] as u32 | ((words[1] as u32) << 16))
247 }
248
249 pub async fn configure_interrupt_pin(
254 &mut self,
255 channel: InterruptChannel,
256 config: InterruptPinConfig,
257 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
258 let mut word = self.read_word(IO_INT_CTRL).await.map_err(Error::Bus)?;
259 let shift = match channel {
260 InterruptChannel::Int1 => 0,
261 InterruptChannel::Int2 => 8,
262 InterruptChannel::Ibi => return Ok(()),
263 };
264 word &= !(0b111 << shift);
265 word |= ((matches!(config.active_level, ActiveLevel::High) as u16) << shift)
266 | ((matches!(config.output_mode, OutputMode::OpenDrain) as u16) << (shift + 1))
267 | ((config.enabled as u16) << (shift + 2));
268 self.write_word(IO_INT_CTRL, word).await.map_err(Error::Bus)
269 }
270
271 pub async fn set_interrupt_latching(
273 &mut self,
274 latched: bool,
275 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
276 self.write_word(INT_CONF, latched as u16)
277 .await
278 .map_err(Error::Bus)
279 }
280
281 pub async fn map_interrupt(
283 &mut self,
284 source: InterruptSource,
285 route: InterruptRoute,
286 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
287 let (register, shift) = interrupt_map_location(source);
288 let mut word = self.read_word(register).await.map_err(Error::Bus)?;
289 word &= !(0b11 << shift);
290 word |= u16::from(route) << shift;
291 self.write_word(register, word).await.map_err(Error::Bus)
292 }
293
294 pub async fn read_interrupt_status(
296 &mut self,
297 channel: InterruptChannel,
298 ) -> Result<InterruptStatus, Error<<Self as AsyncAccess>::BusError>> {
299 let reg = match channel {
300 InterruptChannel::Int1 => 0x0D,
301 InterruptChannel::Int2 => 0x0E,
302 InterruptChannel::Ibi => 0x0F,
303 };
304 self.read_word(reg)
305 .await
306 .map(InterruptStatus)
307 .map_err(Error::Bus)
308 }
309
310 pub async fn wait_for_interrupt<P: Wait>(
318 &mut self,
319 pin: &mut P,
320 channel: InterruptChannel,
321 ) -> Result<InterruptStatus, Error<<Self as AsyncAccess>::BusError>> {
322 pin.wait_for_high().await.ok();
323 self.read_interrupt_status(channel).await
324 }
325
326 pub async fn set_fifo_config(
328 &mut self,
329 config: FifoConfig,
330 watermark_words: u16,
331 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
332 self.write_word(FIFO_WATERMARK, watermark_words & 0x03FF)
333 .await
334 .map_err(Error::Bus)?;
335 self.write_word(FIFO_CONF, config.to_word())
336 .await
337 .map_err(Error::Bus)
338 }
339
340 pub async fn fifo_fill_level(&mut self) -> Result<u16, Error<<Self as AsyncAccess>::BusError>> {
342 Ok(self.read_word(FIFO_FILL_LEVEL).await.map_err(Error::Bus)? & 0x07FF)
343 }
344
345 pub async fn flush_fifo(&mut self) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
347 self.write_word(FIFO_CTRL, 0x0001).await.map_err(Error::Bus)
348 }
349
350 pub async fn read_fifo_words(
360 &mut self,
361 words: &mut [u16],
362 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
363 assert!(
364 words.len() <= 64,
365 "read_fifo_words: words.len() must not exceed 64"
366 );
367 self.read_words(FIFO_DATA, words).await.map_err(Error::Bus)
368 }
369
370 pub async fn enable_feature_engine(
378 &mut self,
379 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
380 self.write_word(ACC_CONF, 0).await.map_err(Error::Bus)?;
381 self.write_word(GYR_CONF, 0).await.map_err(Error::Bus)?;
382 self.write_word(FEATURE_IO2, 0x012C)
383 .await
384 .map_err(Error::Bus)?;
385 self.write_word(FEATURE_IO_STATUS, 0x0001)
386 .await
387 .map_err(Error::Bus)?;
388 self.write_word(FEATURE_CTRL, 0x0001)
389 .await
390 .map_err(Error::Bus)?;
391
392 for _ in 0..32 {
393 let io1 = self.read_word(FEATURE_IO1).await.map_err(Error::Bus)?;
394 let status = (io1 & 0x000F) as u8;
395 if status == 0x1 || status == 0x5 {
396 return Ok(());
397 }
398 }
399 let io1 = self.read_word(FEATURE_IO1).await.map_err(Error::Bus)?;
400 Err(Error::FeatureEngineNotReady((io1 & 0x000F) as u8))
401 }
402
403 pub async fn configure_any_motion(
405 &mut self,
406 config: AnyMotionConfig,
407 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
408 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
409 .await?;
410 self.write_feature_word(
411 EXT_ANYMO_1,
412 (config.threshold & 0x0FFF)
413 | (match config.reference_update {
414 ReferenceUpdate::OnDetection => 0,
415 ReferenceUpdate::EverySample => 1,
416 } << 12),
417 )
418 .await?;
419 self.write_feature_word(EXT_ANYMO_2, config.hysteresis & 0x03FF)
420 .await?;
421 self.write_feature_word(
422 EXT_ANYMO_3,
423 (config.duration & 0x1FFF) | (((config.wait_time as u16) & 0x07) << 13),
424 )
425 .await?;
426 self.modify_word(FEATURE_IO0, |mut word| {
427 word &= !(0b111 << 3);
428 word |= (config.axes.x as u16) << 3;
429 word |= (config.axes.y as u16) << 4;
430 word |= (config.axes.z as u16) << 5;
431 word
432 })
433 .await
434 }
435
436 pub async fn configure_no_motion(
438 &mut self,
439 config: NoMotionConfig,
440 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
441 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
442 .await?;
443 self.write_feature_word(
444 EXT_NOMO_1,
445 (config.threshold & 0x0FFF)
446 | (match config.reference_update {
447 ReferenceUpdate::OnDetection => 0,
448 ReferenceUpdate::EverySample => 1,
449 } << 12),
450 )
451 .await?;
452 self.write_feature_word(EXT_NOMO_2, config.hysteresis & 0x03FF)
453 .await?;
454 self.write_feature_word(
455 EXT_NOMO_3,
456 (config.duration & 0x1FFF) | (((config.wait_time as u16) & 0x07) << 13),
457 )
458 .await?;
459 self.modify_word(FEATURE_IO0, |mut word| {
460 word &= !0b111;
461 word |= config.axes.x as u16;
462 word |= (config.axes.y as u16) << 1;
463 word |= (config.axes.z as u16) << 2;
464 word
465 })
466 .await
467 }
468
469 pub async fn configure_flat(
472 &mut self,
473 config: FlatConfig,
474 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
475 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
476 .await?;
477 self.write_feature_word(
478 EXT_FLAT_1,
479 u16::from(config.theta & 0x3F)
480 | ((config.blocking as u16) << 6)
481 | (u16::from(config.hold_time) << 8),
482 )
483 .await?;
484 self.write_feature_word(
485 EXT_FLAT_2,
486 u16::from(config.slope_threshold) | (u16::from(config.hysteresis) << 8),
487 )
488 .await?;
489 self.set_flat_enabled(true).await
490 }
491
492 pub async fn set_flat_enabled(
494 &mut self,
495 enabled: bool,
496 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
497 self.modify_word(FEATURE_IO0, |mut word| {
498 if enabled {
499 word |= 1 << 6;
500 } else {
501 word &= !(1 << 6);
502 }
503 word
504 })
505 .await
506 }
507
508 pub async fn configure_orientation(
511 &mut self,
512 config: OrientationConfig,
513 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
514 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
515 .await?;
516 self.write_feature_word(
517 EXT_ORIENT_1,
518 (config.upside_down_enabled as u16)
519 | ((config.mode as u16) << 1)
520 | ((config.blocking as u16) << 3)
521 | ((u16::from(config.theta & 0x3F)) << 5)
522 | ((u16::from(config.hold_time & 0x1F)) << 11),
523 )
524 .await?;
525 self.write_feature_word(
526 EXT_ORIENT_2,
527 u16::from(config.slope_threshold) | (u16::from(config.hysteresis) << 8),
528 )
529 .await?;
530 self.set_orientation_enabled(true).await
531 }
532
533 pub async fn set_orientation_enabled(
535 &mut self,
536 enabled: bool,
537 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
538 self.modify_word(FEATURE_IO0, |mut word| {
539 if enabled {
540 word |= 1 << 7;
541 } else {
542 word &= !(1 << 7);
543 }
544 word
545 })
546 .await
547 }
548
549 pub async fn configure_tap(
554 &mut self,
555 config: TapConfig,
556 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
557 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
558 .await?;
559 self.write_feature_word(
560 EXT_TAP_1,
561 (config.axis as u16)
562 | ((config.reporting_mode as u16) << 2)
563 | ((u16::from(config.max_peaks_for_tap & 0x07)) << 3)
564 | ((config.mode as u16) << 6),
565 )
566 .await?;
567 self.write_feature_word(
568 EXT_TAP_2,
569 (config.tap_peak_threshold & 0x03FF)
570 | ((u16::from(config.max_gesture_duration & 0x3F)) << 10),
571 )
572 .await?;
573 self.write_feature_word(
574 EXT_TAP_3,
575 u16::from(config.max_duration_between_peaks & 0x0F)
576 | (u16::from(config.tap_shock_settling_duration & 0x0F) << 4)
577 | (u16::from(config.min_quiet_duration_between_taps & 0x0F) << 8)
578 | (u16::from(config.quiet_time_after_gesture & 0x0F) << 12),
579 )
580 .await?;
581 self.modify_word(FEATURE_IO0, |mut word| {
582 word &= !((1 << 12) | (1 << 13) | (1 << 14));
583 word |= (config.single_tap_enabled as u16) << 12;
584 word |= (config.double_tap_enabled as u16) << 13;
585 word |= (config.triple_tap_enabled as u16) << 14;
586 word
587 })
588 .await
589 }
590
591 pub async fn configure_significant_motion(
594 &mut self,
595 config: SignificantMotionConfig,
596 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
597 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
598 .await?;
599 self.write_feature_word(EXT_SIGMO_1, config.block_size)
600 .await?;
601 self.write_feature_word(
602 EXT_SIGMO_2,
603 (config.peak_to_peak_min & 0x03FF)
604 | ((u16::from(config.mean_crossing_rate_min & 0x3F)) << 10),
605 )
606 .await?;
607 self.write_feature_word(
608 EXT_SIGMO_3,
609 (config.peak_to_peak_max & 0x03FF)
610 | ((u16::from(config.mean_crossing_rate_max & 0x3F)) << 10),
611 )
612 .await?;
613 self.set_significant_motion_enabled(true).await
614 }
615
616 pub async fn set_significant_motion_enabled(
618 &mut self,
619 enabled: bool,
620 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
621 self.modify_word(FEATURE_IO0, |mut word| {
622 if enabled {
623 word |= 1 << 10;
624 } else {
625 word &= !(1 << 10);
626 }
627 word
628 })
629 .await
630 }
631
632 pub async fn configure_tilt(
635 &mut self,
636 config: TiltConfig,
637 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
638 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
639 .await?;
640 self.write_feature_word(
641 EXT_TILT_1,
642 u16::from(config.segment_size) | (u16::from(config.min_tilt_angle) << 8),
643 )
644 .await?;
645 self.write_feature_word(EXT_TILT_2, config.beta_acc_mean)
646 .await?;
647 self.set_tilt_enabled(true).await
648 }
649
650 pub async fn set_tilt_enabled(
652 &mut self,
653 enabled: bool,
654 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
655 self.modify_word(FEATURE_IO0, |mut word| {
656 if enabled {
657 word |= 1 << 11;
658 } else {
659 word &= !(1 << 11);
660 }
661 word
662 })
663 .await
664 }
665
666 pub async fn set_step_detector_enabled(
672 &mut self,
673 enabled: bool,
674 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
675 self.modify_word(FEATURE_IO0, |mut word| {
676 if enabled {
677 word |= 1 << 8;
678 } else {
679 word &= !(1 << 8);
680 }
681 word
682 })
683 .await
684 }
685
686 pub async fn set_step_counter_enabled(
692 &mut self,
693 enabled: bool,
694 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
695 self.modify_word(FEATURE_IO0, |mut word| {
696 if enabled {
697 word |= 1 << 9;
698 } else {
699 word &= !(1 << 9);
700 }
701 word
702 })
703 .await
704 }
705
706 pub async fn configure_step_counter(
711 &mut self,
712 config: StepCounterConfig,
713 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
714 self.write_feature_word(EXT_SC_1, config.to_word()).await
715 }
716
717 pub async fn reset_step_counter(
719 &mut self,
720 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
721 self.configure_step_counter(StepCounterConfig {
722 reset_counter: true,
723 ..StepCounterConfig::disabled()
724 })
725 .await
726 }
727
728 pub async fn read_step_count(&mut self) -> Result<u32, Error<<Self as AsyncAccess>::BusError>> {
730 let low = self.read_word(FEATURE_IO2).await.map_err(Error::Bus)? as u32;
731 let high = self.read_word(FEATURE_IO3).await.map_err(Error::Bus)? as u32;
732 Ok(low | (high << 16))
733 }
734
735 pub async fn set_alt_accel_config(
737 &mut self,
738 config: AltAccelConfig,
739 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
740 self.write_word(ALT_ACC_CONF, config.to_word())
741 .await
742 .map_err(Error::Bus)
743 }
744
745 pub async fn set_alt_gyro_config(
747 &mut self,
748 config: AltGyroConfig,
749 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
750 self.write_word(ALT_GYR_CONF, config.to_word())
751 .await
752 .map_err(Error::Bus)
753 }
754
755 pub async fn configure_alt_config_control(
758 &mut self,
759 config: AltConfigControl,
760 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
761 self.write_word(
762 ALT_CONF,
763 (config.accel_enabled as u16)
764 | ((config.gyro_enabled as u16) << 4)
765 | ((config.reset_on_user_config_write as u16) << 8),
766 )
767 .await
768 .map_err(Error::Bus)?;
769 self.write_feature_word(
770 EXT_ALT_CONFIG_CHG,
771 (config.switch_to_alternate as u16) | ((config.switch_to_user as u16) << 4),
772 )
773 .await
774 }
775
776 pub async fn alt_status(
778 &mut self,
779 ) -> Result<AltStatus, Error<<Self as AsyncAccess>::BusError>> {
780 self.read_word(ALT_STATUS)
781 .await
782 .map(AltStatus)
783 .map_err(Error::Bus)
784 }
785
786 async fn modify_word<F>(
787 &mut self,
788 reg: u8,
789 f: F,
790 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>>
791 where
792 F: FnOnce(u16) -> u16,
793 {
794 let value = self.read_word(reg).await.map_err(Error::Bus)?;
795 self.write_word(reg, f(value)).await.map_err(Error::Bus)?;
796 if reg == FEATURE_IO0 {
797 self.write_word(FEATURE_IO_STATUS, 1)
798 .await
799 .map_err(Error::Bus)?;
800 }
801 Ok(())
802 }
803
804 async fn run_self_test_inner<D: AsyncDelayNs>(
805 &mut self,
806 delay: &mut D,
807 selection: SelfTestSelection,
808 ) -> Result<SelfTestResult, Error<<Self as AsyncAccess>::BusError>> {
809 self.enable_feature_engine().await?;
810
811 if selection.tests_gyroscope() {
812 self.write_word(
813 ACC_CONF,
814 AccelConfig {
815 mode: crate::AccelMode::HighPerformance,
816 odr: OutputDataRate::Hz200,
817 ..Default::default()
818 }
819 .to_word(),
820 )
821 .await
822 .map_err(Error::Bus)?;
823 }
824
825 self.write_word(ALT_ACC_CONF, 0).await.map_err(Error::Bus)?;
826 self.write_word(ALT_GYR_CONF, 0).await.map_err(Error::Bus)?;
827 self.write_feature_word(EXT_ST_SELECT, selection.to_word())
828 .await?;
829 self.write_word(CMD, SELF_TEST).await.map_err(Error::Bus)?;
830
831 for _ in 0..50 {
832 delay.delay_ms(10).await;
833 let feature_io1 = self.read_word(FEATURE_IO1).await.map_err(Error::Bus)?;
834 if feature_io1 & (1 << 4) != 0 {
835 let detail = SelfTestDetail(self.read_feature_word(EXT_ST_RESULT).await?);
836 return Ok(SelfTestResult {
837 selection,
838 passed: feature_io1 & (1 << 6) != 0,
839 sample_rate_error: feature_io1 & (1 << 7) != 0,
840 error_status: (feature_io1 & 0x000F) as u8,
841 detail,
842 });
843 }
844 }
845
846 Err(Error::SelfTestTimeout)
847 }
848
849 async fn restore_self_test_configuration(
850 &mut self,
851 acc_conf: u16,
852 gyr_conf: u16,
853 alt_acc_conf: u16,
854 alt_gyr_conf: u16,
855 st_select: u16,
856 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
857 self.write_word(ACC_CONF, acc_conf)
858 .await
859 .map_err(Error::Bus)?;
860 self.write_word(GYR_CONF, gyr_conf)
861 .await
862 .map_err(Error::Bus)?;
863 self.write_word(ALT_ACC_CONF, alt_acc_conf)
864 .await
865 .map_err(Error::Bus)?;
866 self.write_word(ALT_GYR_CONF, alt_gyr_conf)
867 .await
868 .map_err(Error::Bus)?;
869 self.write_feature_word(EXT_ST_SELECT, st_select).await
870 }
871
872 async fn write_feature_word(
873 &mut self,
874 ext_addr: u16,
875 value: u16,
876 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
877 self.write_word(FEATURE_DATA_ADDR, ext_addr)
878 .await
879 .map_err(Error::Bus)?;
880 self.write_word(FEATURE_DATA_TX, value)
881 .await
882 .map_err(Error::Bus)
883 }
884
885 async fn read_feature_word(
886 &mut self,
887 ext_addr: u16,
888 ) -> Result<u16, Error<<Self as AsyncAccess>::BusError>> {
889 self.write_word(FEATURE_DATA_ADDR, ext_addr)
890 .await
891 .map_err(Error::Bus)?;
892 self.read_word(FEATURE_DATA_TX).await.map_err(Error::Bus)
893 }
894
895 async fn modify_feature_word<F>(
896 &mut self,
897 ext_addr: u16,
898 f: F,
899 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>>
900 where
901 F: FnOnce(u16) -> u16,
902 {
903 let word = self.read_feature_word(ext_addr).await?;
904 self.write_feature_word(ext_addr, f(word)).await
905 }
906
907 async fn apply_common_feature_settings(
916 &mut self,
917 report_mode: EventReportMode,
918 interrupt_hold: u8,
919 ) -> Result<(), Error<<Self as AsyncAccess>::BusError>> {
920 self.modify_feature_word(EXT_GEN_SET_1, |word| {
921 let mut updated = word & !0x003F;
922 updated |= match report_mode {
923 EventReportMode::AllEvents => 0,
924 EventReportMode::FirstEventOnly => 1,
925 };
926 updated |= ((interrupt_hold.min(13) as u16) & 0x0F) << 1;
927 updated
928 })
929 .await
930 }
931}