1#[cfg(feature = "blocking")]
2use embedded_hal::delay::DelayNs;
3#[cfg(not(feature = "blocking"))]
4use embedded_hal_async::delay::DelayNs;
5
6use crate::registers::{
7 ACC_CONF, ACC_DATA_X, ALT_ACC_CONF, ALT_CONF, ALT_GYR_CONF, ALT_STATUS, BMI323_CHIP_ID,
8 CHIP_ID, CMD, ERR_REG, EXT_ALT_CONFIG_CHG, EXT_ANYMO_1, EXT_ANYMO_2, EXT_ANYMO_3, EXT_FLAT_1,
9 EXT_FLAT_2, EXT_GEN_SET_1, EXT_NOMO_1, EXT_NOMO_2, EXT_NOMO_3, EXT_ORIENT_1, EXT_ORIENT_2,
10 EXT_SC_1, EXT_SIGMO_1, EXT_SIGMO_2, EXT_SIGMO_3, EXT_ST_RESULT, EXT_ST_SELECT, EXT_TAP_1,
11 EXT_TAP_2, EXT_TAP_3, EXT_TILT_1, EXT_TILT_2, FEATURE_CTRL, FEATURE_CTRL_ENABLE,
12 FEATURE_DATA_ADDR, FEATURE_DATA_TX, FEATURE_ENGINE_CONFIG, FEATURE_ENGINE_STATUS_ACTIVATED,
13 FEATURE_ENGINE_STATUS_NO_ERROR, FEATURE_IO_STATUS, FEATURE_IO_STATUS_SYNC, FEATURE_IO0,
14 FEATURE_IO1, FEATURE_IO2, FEATURE_IO3, FIFO_CONF, FIFO_CTRL, FIFO_CTRL_FLUSH, FIFO_DATA,
15 FIFO_FILL_LEVEL, FIFO_WATERMARK, GYR_CONF, GYR_DATA_X, INT_CONF, INT_STATUS_IBI,
16 INT_STATUS_INT1, INT_STATUS_INT2, IO_INT_CTRL, SELF_TEST, SENSOR_TIME_0, SOFT_RESET, STATUS,
17 TEMP_DATA, TransportKind, interrupt_map_location, words_to_axis,
18};
19use crate::{
20 AccelConfig, Access, ActiveLevel, AltAccelConfig, AltConfigControl, AltGyroConfig, AltStatus,
21 AnyMotionConfig, AxisData, Bmi323, DeviceState, Error, ErrorWord, EventReportMode, FifoConfig,
22 FlatConfig, GyroConfig, INTERRUPT_HOLD_MAX, ImuData, InterruptChannel, InterruptPinConfig,
23 InterruptRoute, InterruptSource, InterruptStatus, NoMotionConfig, OrientationConfig,
24 OutputDataRate, OutputMode, ReferenceUpdate, SelfTestDetail, SelfTestResult, SelfTestSelection,
25 SignificantMotionConfig, StatusWord, StepCounterConfig, TapConfig, TiltConfig,
26};
27
28#[maybe_async::maybe_async]
29impl<T> Bmi323<T>
30where
31 Self: Access,
32{
33 pub async fn init<D: DelayNs>(
42 &mut self,
43 delay: &mut D,
44 ) -> Result<DeviceState, Error<<Self as Access>::BusError>> {
45 self.soft_reset(delay).await?;
48
49 if matches!(self.kind, TransportKind::Spi) {
50 self.read_word(CHIP_ID).await.map_err(Error::Bus)?;
51 delay.delay_us(250).await;
52 }
53
54 let chip_id = self.read_word(CHIP_ID).await.map_err(Error::Bus)? as u8;
55 if chip_id != BMI323_CHIP_ID {
56 return Err(Error::InvalidChipId(chip_id));
57 }
58
59 let error = self.error_word().await?;
60 if error.fatal() {
61 return Err(Error::FatalError);
62 }
63
64 Ok(DeviceState {
65 chip_id,
66 status: self.status_word().await?,
67 error,
68 })
69 }
70
71 pub async fn soft_reset<D: DelayNs>(
73 &mut self,
74 delay: &mut D,
75 ) -> Result<(), Error<<Self as Access>::BusError>> {
76 self.write_word(CMD, SOFT_RESET).await.map_err(Error::Bus)?;
77 delay.delay_ms(2).await;
79 self.accel_range = crate::AccelRange::G2;
82 self.gyro_range = crate::GyroRange::Dps125;
83 Ok(())
84 }
85
86 pub async fn run_self_test<D: DelayNs>(
102 &mut self,
103 delay: &mut D,
104 selection: SelfTestSelection,
105 ) -> Result<SelfTestResult, Error<<Self as Access>::BusError>> {
106 self.enable_feature_engine(delay).await?;
107
108 if selection.tests_gyroscope() {
109 self.write_word(
110 ACC_CONF,
111 AccelConfig {
112 mode: crate::AccelMode::HighPerformance,
113 odr: OutputDataRate::Hz200,
114 ..Default::default()
115 }
116 .to_word(),
117 )
118 .await
119 .map_err(Error::Bus)?;
120 }
121
122 self.write_word(ALT_ACC_CONF, 0).await.map_err(Error::Bus)?;
123 self.write_word(ALT_GYR_CONF, 0).await.map_err(Error::Bus)?;
124 self.write_feature_word(EXT_ST_SELECT, selection.to_word())
125 .await?;
126 self.write_word(CMD, SELF_TEST).await.map_err(Error::Bus)?;
127
128 for _ in 0..50 {
132 let feature_io1 = self.read_word(FEATURE_IO1).await.map_err(Error::Bus)?;
133 if feature_io1 & (1 << 4) != 0 {
134 let detail = SelfTestDetail(self.read_feature_word(EXT_ST_RESULT).await?);
135 return Ok(SelfTestResult {
136 selection,
137 passed: feature_io1 & (1 << 6) != 0,
138 sample_rate_error: feature_io1 & (1 << 7) != 0,
139 error_status: (feature_io1 & 0x000F) as u8,
140 detail,
141 });
142 }
143 delay.delay_ms(10).await;
144 }
145
146 Err(Error::SelfTestTimeout)
147 }
148
149 pub async fn status_word(&mut self) -> Result<StatusWord, Error<<Self as Access>::BusError>> {
151 self.read_word(STATUS)
152 .await
153 .map(StatusWord)
154 .map_err(Error::Bus)
155 }
156
157 pub async fn error_word(&mut self) -> Result<ErrorWord, Error<<Self as Access>::BusError>> {
159 self.read_word(ERR_REG)
160 .await
161 .map(ErrorWord)
162 .map_err(Error::Bus)
163 }
164
165 pub async fn set_accel_config(
174 &mut self,
175 config: AccelConfig,
176 ) -> Result<(), Error<<Self as Access>::BusError>> {
177 self.write_word(ACC_CONF, config.to_word())
178 .await
179 .map_err(Error::Bus)?;
180 self.accel_range = config.range;
181 Ok(())
182 }
183
184 pub async fn set_gyro_config(
193 &mut self,
194 config: GyroConfig,
195 ) -> Result<(), Error<<Self as Access>::BusError>> {
196 self.write_word(GYR_CONF, config.to_word())
197 .await
198 .map_err(Error::Bus)?;
199 self.gyro_range = config.range;
200 Ok(())
201 }
202
203 pub fn accel_range(&self) -> crate::AccelRange {
208 self.accel_range
209 }
210
211 pub fn gyro_range(&self) -> crate::GyroRange {
216 self.gyro_range
217 }
218
219 pub async fn read_accel(&mut self) -> Result<AxisData, Error<<Self as Access>::BusError>> {
224 let mut words = [0u16; 3];
225 self.read_words(ACC_DATA_X, &mut words)
226 .await
227 .map_err(Error::Bus)?;
228 Ok(words_to_axis(words))
229 }
230
231 pub async fn read_gyro(&mut self) -> Result<AxisData, Error<<Self as Access>::BusError>> {
236 let mut words = [0u16; 3];
237 self.read_words(GYR_DATA_X, &mut words)
238 .await
239 .map_err(Error::Bus)?;
240 Ok(words_to_axis(words))
241 }
242
243 pub async fn read_imu_data(&mut self) -> Result<ImuData, Error<<Self as Access>::BusError>> {
249 let mut words = [0u16; 6];
250 self.read_words(ACC_DATA_X, &mut words)
251 .await
252 .map_err(Error::Bus)?;
253 Ok(ImuData {
254 accel: words_to_axis([words[0], words[1], words[2]]),
255 gyro: words_to_axis([words[3], words[4], words[5]]),
256 })
257 }
258
259 pub async fn read_temperature_celsius(
261 &mut self,
262 ) -> Result<f32, Error<<Self as Access>::BusError>> {
263 let raw = self.read_word(TEMP_DATA).await.map_err(Error::Bus)? as i16;
264 crate::driver::temperature_raw_to_celsius(raw)
265 }
266
267 pub async fn read_sensor_time(&mut self) -> Result<u32, Error<<Self as Access>::BusError>> {
269 let mut words = [0u16; 2];
270 self.read_words(SENSOR_TIME_0, &mut words)
271 .await
272 .map_err(Error::Bus)?;
273 Ok(words[0] as u32 | ((words[1] as u32) << 16))
274 }
275
276 pub async fn configure_interrupt_pin(
281 &mut self,
282 channel: InterruptChannel,
283 config: InterruptPinConfig,
284 ) -> Result<(), Error<<Self as Access>::BusError>> {
285 let shift = match channel {
286 InterruptChannel::Int1 => 0,
287 InterruptChannel::Int2 => 8,
288 InterruptChannel::Ibi => return Ok(()),
289 };
290 let mut word = self.read_word(IO_INT_CTRL).await.map_err(Error::Bus)?;
291 word &= !(0b111 << shift);
292 word |= ((matches!(config.active_level, ActiveLevel::High) as u16) << shift)
293 | ((matches!(config.output_mode, OutputMode::OpenDrain) as u16) << (shift + 1))
294 | ((config.enabled as u16) << (shift + 2));
295 self.write_word(IO_INT_CTRL, word).await.map_err(Error::Bus)
296 }
297
298 pub async fn set_interrupt_latching(
300 &mut self,
301 latched: bool,
302 ) -> Result<(), Error<<Self as Access>::BusError>> {
303 self.write_word(INT_CONF, latched as u16)
304 .await
305 .map_err(Error::Bus)
306 }
307
308 pub async fn map_interrupt(
310 &mut self,
311 source: InterruptSource,
312 route: InterruptRoute,
313 ) -> Result<(), Error<<Self as Access>::BusError>> {
314 let (register, shift) = interrupt_map_location(source);
315 let mut word = self.read_word(register).await.map_err(Error::Bus)?;
316 word &= !(0b11 << shift);
317 word |= u16::from(route) << shift;
318 self.write_word(register, word).await.map_err(Error::Bus)
319 }
320
321 pub async fn read_interrupt_status(
323 &mut self,
324 channel: InterruptChannel,
325 ) -> Result<InterruptStatus, Error<<Self as Access>::BusError>> {
326 let reg = match channel {
327 InterruptChannel::Int1 => INT_STATUS_INT1,
328 InterruptChannel::Int2 => INT_STATUS_INT2,
329 InterruptChannel::Ibi => INT_STATUS_IBI,
330 };
331 self.read_word(reg)
332 .await
333 .map(InterruptStatus)
334 .map_err(Error::Bus)
335 }
336
337 pub async fn set_fifo_config(
343 &mut self,
344 config: FifoConfig,
345 watermark_words: u16,
346 ) -> Result<(), Error<<Self as Access>::BusError>> {
347 self.write_word(FIFO_WATERMARK, watermark_words & 0x03FF)
349 .await
350 .map_err(Error::Bus)?;
351 self.write_word(FIFO_CONF, config.to_word())
352 .await
353 .map_err(Error::Bus)
354 }
355
356 pub async fn fifo_fill_level(&mut self) -> Result<u16, Error<<Self as Access>::BusError>> {
358 Ok(self.read_word(FIFO_FILL_LEVEL).await.map_err(Error::Bus)? & 0x07FF)
360 }
361
362 pub async fn flush_fifo(&mut self) -> Result<(), Error<<Self as Access>::BusError>> {
364 self.write_word(FIFO_CTRL, FIFO_CTRL_FLUSH)
365 .await
366 .map_err(Error::Bus)
367 }
368
369 pub async fn read_fifo_words(
379 &mut self,
380 words: &mut [u16],
381 ) -> Result<(), Error<<Self as Access>::BusError>> {
382 assert!(
383 words.len() <= crate::MAX_WORDS_PER_READ,
384 "read_fifo_words: words.len() ({}) must not exceed MAX_WORDS_PER_READ ({})",
385 words.len(),
386 crate::MAX_WORDS_PER_READ,
387 );
388 self.read_words(FIFO_DATA, words).await.map_err(Error::Bus)
389 }
390
391 pub async fn enable_feature_engine<D: DelayNs>(
399 &mut self,
400 delay: &mut D,
401 ) -> Result<(), Error<<Self as Access>::BusError>> {
402 self.write_word(ACC_CONF, 0).await.map_err(Error::Bus)?;
403 self.write_word(GYR_CONF, 0).await.map_err(Error::Bus)?;
404 self.write_word(FEATURE_IO2, FEATURE_ENGINE_CONFIG)
405 .await
406 .map_err(Error::Bus)?;
407 self.write_word(FEATURE_IO_STATUS, FEATURE_IO_STATUS_SYNC)
408 .await
409 .map_err(Error::Bus)?;
410 self.write_word(FEATURE_CTRL, FEATURE_CTRL_ENABLE)
411 .await
412 .map_err(Error::Bus)?;
413
414 for _ in 0..32 {
415 delay.delay_us(200).await;
418 let io1 = self.read_word(FEATURE_IO1).await.map_err(Error::Bus)?;
419 let status = (io1 & 0x000F) as u8;
420 if status == FEATURE_ENGINE_STATUS_ACTIVATED || status == FEATURE_ENGINE_STATUS_NO_ERROR
421 {
422 return Ok(());
423 }
424 }
425 let io1 = self.read_word(FEATURE_IO1).await.map_err(Error::Bus)?;
426 Err(Error::FeatureEngineNotReady((io1 & 0x000F) as u8))
427 }
428
429 pub async fn configure_any_motion(
431 &mut self,
432 config: AnyMotionConfig,
433 ) -> Result<(), Error<<Self as Access>::BusError>> {
434 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
435 .await?;
436 self.write_feature_word(
437 EXT_ANYMO_1,
438 (config.threshold & 0x0FFF)
439 | (match config.reference_update {
440 ReferenceUpdate::OnDetection => 0,
441 ReferenceUpdate::EverySample => 1,
442 } << 12),
443 )
444 .await?;
445 self.write_feature_word(EXT_ANYMO_2, config.hysteresis & 0x03FF)
446 .await?;
447 self.write_feature_word(
448 EXT_ANYMO_3,
449 (config.duration & 0x1FFF) | (((config.wait_time as u16) & 0x07) << 13),
450 )
451 .await?;
452 self.modify_word(FEATURE_IO0, |mut word| {
453 word &= !(0b111 << 3);
454 word |= (config.axes.x as u16) << 3;
455 word |= (config.axes.y as u16) << 4;
456 word |= (config.axes.z as u16) << 5;
457 word
458 })
459 .await
460 }
461
462 pub async fn configure_no_motion(
464 &mut self,
465 config: NoMotionConfig,
466 ) -> Result<(), Error<<Self as Access>::BusError>> {
467 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
468 .await?;
469 self.write_feature_word(
470 EXT_NOMO_1,
471 (config.threshold & 0x0FFF)
472 | (match config.reference_update {
473 ReferenceUpdate::OnDetection => 0,
474 ReferenceUpdate::EverySample => 1,
475 } << 12),
476 )
477 .await?;
478 self.write_feature_word(EXT_NOMO_2, config.hysteresis & 0x03FF)
479 .await?;
480 self.write_feature_word(
481 EXT_NOMO_3,
482 (config.duration & 0x1FFF) | (((config.wait_time as u16) & 0x07) << 13),
483 )
484 .await?;
485 self.modify_word(FEATURE_IO0, |mut word| {
491 word &= !0b111;
492 word |= config.axes.x as u16;
493 word |= (config.axes.y as u16) << 1;
494 word |= (config.axes.z as u16) << 2;
495 word
496 })
497 .await
498 }
499
500 pub async fn configure_flat(
503 &mut self,
504 config: FlatConfig,
505 ) -> Result<(), Error<<Self as Access>::BusError>> {
506 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
507 .await?;
508 self.write_feature_word(
509 EXT_FLAT_1,
510 u16::from(config.theta & 0x3F)
511 | ((config.blocking as u16) << 6)
512 | (u16::from(config.hold_time) << 8),
513 )
514 .await?;
515 self.write_feature_word(
516 EXT_FLAT_2,
517 u16::from(config.slope_threshold) | (u16::from(config.hysteresis) << 8),
518 )
519 .await?;
520 self.set_flat_enabled(true).await
521 }
522
523 pub async fn set_flat_enabled(
525 &mut self,
526 enabled: bool,
527 ) -> Result<(), Error<<Self as Access>::BusError>> {
528 self.modify_word(FEATURE_IO0, |mut word| {
529 if enabled {
530 word |= 1 << 6;
531 } else {
532 word &= !(1 << 6);
533 }
534 word
535 })
536 .await
537 }
538
539 pub async fn configure_orientation(
542 &mut self,
543 config: OrientationConfig,
544 ) -> Result<(), Error<<Self as Access>::BusError>> {
545 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
546 .await?;
547 self.write_feature_word(
548 EXT_ORIENT_1,
549 (config.upside_down_enabled as u16)
550 | ((config.mode as u16) << 1)
551 | ((config.blocking as u16) << 3)
552 | ((u16::from(config.theta & 0x3F)) << 5)
553 | ((u16::from(config.hold_time & 0x1F)) << 11),
554 )
555 .await?;
556 self.write_feature_word(
557 EXT_ORIENT_2,
558 u16::from(config.slope_threshold) | (u16::from(config.hysteresis) << 8),
559 )
560 .await?;
561 self.set_orientation_enabled(true).await
562 }
563
564 pub async fn set_orientation_enabled(
566 &mut self,
567 enabled: bool,
568 ) -> Result<(), Error<<Self as Access>::BusError>> {
569 self.modify_word(FEATURE_IO0, |mut word| {
570 if enabled {
571 word |= 1 << 7;
572 } else {
573 word &= !(1 << 7);
574 }
575 word
576 })
577 .await
578 }
579
580 pub async fn configure_tap(
585 &mut self,
586 config: TapConfig,
587 ) -> Result<(), Error<<Self as Access>::BusError>> {
588 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
589 .await?;
590 self.write_feature_word(
591 EXT_TAP_1,
592 (config.axis as u16)
593 | ((config.reporting_mode as u16) << 2)
594 | ((u16::from(config.max_peaks_for_tap & 0x07)) << 3)
595 | ((config.mode as u16) << 6),
596 )
597 .await?;
598 self.write_feature_word(
599 EXT_TAP_2,
600 (config.tap_peak_threshold & 0x03FF)
601 | ((u16::from(config.max_gesture_duration & 0x3F)) << 10),
602 )
603 .await?;
604 self.write_feature_word(
605 EXT_TAP_3,
606 u16::from(config.max_duration_between_peaks & 0x0F)
607 | (u16::from(config.tap_shock_settling_duration & 0x0F) << 4)
608 | (u16::from(config.min_quiet_duration_between_taps & 0x0F) << 8)
609 | (u16::from(config.quiet_time_after_gesture & 0x0F) << 12),
610 )
611 .await?;
612 self.modify_word(FEATURE_IO0, |mut word| {
613 word &= !((1 << 12) | (1 << 13) | (1 << 14));
614 word |= (config.single_tap_enabled as u16) << 12;
615 word |= (config.double_tap_enabled as u16) << 13;
616 word |= (config.triple_tap_enabled as u16) << 14;
617 word
618 })
619 .await
620 }
621
622 pub async fn configure_significant_motion(
625 &mut self,
626 config: SignificantMotionConfig,
627 ) -> Result<(), Error<<Self as Access>::BusError>> {
628 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
629 .await?;
630 self.write_feature_word(EXT_SIGMO_1, config.block_size)
631 .await?;
632 self.write_feature_word(
633 EXT_SIGMO_2,
634 (config.peak_to_peak_min & 0x03FF)
635 | ((u16::from(config.mean_crossing_rate_min & 0x3F)) << 10),
636 )
637 .await?;
638 self.write_feature_word(
639 EXT_SIGMO_3,
640 (config.peak_to_peak_max & 0x03FF)
641 | ((u16::from(config.mean_crossing_rate_max & 0x3F)) << 10),
642 )
643 .await?;
644 self.set_significant_motion_enabled(true).await
645 }
646
647 pub async fn set_significant_motion_enabled(
649 &mut self,
650 enabled: bool,
651 ) -> Result<(), Error<<Self as Access>::BusError>> {
652 self.modify_word(FEATURE_IO0, |mut word| {
653 if enabled {
654 word |= 1 << 10;
655 } else {
656 word &= !(1 << 10);
657 }
658 word
659 })
660 .await
661 }
662
663 pub async fn configure_tilt(
666 &mut self,
667 config: TiltConfig,
668 ) -> Result<(), Error<<Self as Access>::BusError>> {
669 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)
670 .await?;
671 self.write_feature_word(
672 EXT_TILT_1,
673 u16::from(config.segment_size) | (u16::from(config.min_tilt_angle) << 8),
674 )
675 .await?;
676 self.write_feature_word(EXT_TILT_2, config.beta_acc_mean)
677 .await?;
678 self.set_tilt_enabled(true).await
679 }
680
681 pub async fn set_tilt_enabled(
683 &mut self,
684 enabled: bool,
685 ) -> Result<(), Error<<Self as Access>::BusError>> {
686 self.modify_word(FEATURE_IO0, |mut word| {
687 if enabled {
688 word |= 1 << 11;
689 } else {
690 word &= !(1 << 11);
691 }
692 word
693 })
694 .await
695 }
696
697 pub async fn set_step_detector_enabled(
703 &mut self,
704 enabled: bool,
705 ) -> Result<(), Error<<Self as Access>::BusError>> {
706 self.modify_word(FEATURE_IO0, |mut word| {
707 if enabled {
708 word |= 1 << 8;
709 } else {
710 word &= !(1 << 8);
711 }
712 word
713 })
714 .await
715 }
716
717 pub async fn set_step_counter_enabled(
723 &mut self,
724 enabled: bool,
725 ) -> Result<(), Error<<Self as Access>::BusError>> {
726 self.modify_word(FEATURE_IO0, |mut word| {
727 if enabled {
728 word |= 1 << 9;
729 } else {
730 word &= !(1 << 9);
731 }
732 word
733 })
734 .await
735 }
736
737 pub async fn configure_step_counter(
742 &mut self,
743 config: StepCounterConfig,
744 ) -> Result<(), Error<<Self as Access>::BusError>> {
745 self.write_feature_word(EXT_SC_1, config.to_word()).await
746 }
747
748 pub async fn reset_step_counter(&mut self) -> Result<(), Error<<Self as Access>::BusError>> {
750 self.configure_step_counter(StepCounterConfig {
751 reset_counter: true,
752 ..StepCounterConfig::disabled()
753 })
754 .await
755 }
756
757 pub async fn read_step_count(&mut self) -> Result<u32, Error<<Self as Access>::BusError>> {
759 let low = self.read_word(FEATURE_IO2).await.map_err(Error::Bus)? as u32;
760 let high = self.read_word(FEATURE_IO3).await.map_err(Error::Bus)? as u32;
761 Ok(low | (high << 16))
762 }
763
764 pub async fn set_alt_accel_config(
766 &mut self,
767 config: AltAccelConfig,
768 ) -> Result<(), Error<<Self as Access>::BusError>> {
769 self.write_word(ALT_ACC_CONF, config.to_word())
770 .await
771 .map_err(Error::Bus)
772 }
773
774 pub async fn set_alt_gyro_config(
776 &mut self,
777 config: AltGyroConfig,
778 ) -> Result<(), Error<<Self as Access>::BusError>> {
779 self.write_word(ALT_GYR_CONF, config.to_word())
780 .await
781 .map_err(Error::Bus)
782 }
783
784 pub async fn configure_alt_config_control(
787 &mut self,
788 config: AltConfigControl,
789 ) -> Result<(), Error<<Self as Access>::BusError>> {
790 self.write_word(
791 ALT_CONF,
792 (config.accel_enabled as u16)
793 | ((config.gyro_enabled as u16) << 4)
794 | ((config.reset_on_user_config_write as u16) << 8),
795 )
796 .await
797 .map_err(Error::Bus)?;
798 self.write_feature_word(
799 EXT_ALT_CONFIG_CHG,
800 (config.switch_to_alternate as u16 & 0x0F)
801 | ((config.switch_to_user as u16 & 0x0F) << 4),
802 )
803 .await
804 }
805
806 pub async fn alt_status(&mut self) -> Result<AltStatus, Error<<Self as Access>::BusError>> {
808 self.read_word(ALT_STATUS)
809 .await
810 .map(AltStatus)
811 .map_err(Error::Bus)
812 }
813
814 async fn modify_word<F>(
815 &mut self,
816 reg: u8,
817 f: F,
818 ) -> Result<(), Error<<Self as Access>::BusError>>
819 where
820 F: FnOnce(u16) -> u16,
821 {
822 let value = self.read_word(reg).await.map_err(Error::Bus)?;
823 self.write_word(reg, f(value)).await.map_err(Error::Bus)?;
824 if reg == FEATURE_IO0 {
825 self.write_word(FEATURE_IO_STATUS, 1)
826 .await
827 .map_err(Error::Bus)?;
828 }
829 Ok(())
830 }
831
832 async fn write_feature_word(
833 &mut self,
834 ext_addr: u16,
835 value: u16,
836 ) -> Result<(), Error<<Self as Access>::BusError>> {
837 self.write_word(FEATURE_DATA_ADDR, ext_addr)
838 .await
839 .map_err(Error::Bus)?;
840 self.write_word(FEATURE_DATA_TX, value)
841 .await
842 .map_err(Error::Bus)
843 }
844
845 async fn read_feature_word(
846 &mut self,
847 ext_addr: u16,
848 ) -> Result<u16, Error<<Self as Access>::BusError>> {
849 self.write_word(FEATURE_DATA_ADDR, ext_addr)
850 .await
851 .map_err(Error::Bus)?;
852 self.read_word(FEATURE_DATA_TX).await.map_err(Error::Bus)
853 }
854
855 async fn modify_feature_word<F>(
856 &mut self,
857 ext_addr: u16,
858 f: F,
859 ) -> Result<(), Error<<Self as Access>::BusError>>
860 where
861 F: FnOnce(u16) -> u16,
862 {
863 let word = self.read_feature_word(ext_addr).await?;
864 self.write_feature_word(ext_addr, f(word)).await
865 }
866
867 async fn apply_common_feature_settings(
876 &mut self,
877 report_mode: EventReportMode,
878 interrupt_hold: u8,
879 ) -> Result<(), Error<<Self as Access>::BusError>> {
880 self.modify_feature_word(EXT_GEN_SET_1, |word| {
883 let mut updated = word & !0x003F;
884 updated |= match report_mode {
885 EventReportMode::AllEvents => 0,
886 EventReportMode::FirstEventOnly => 1,
887 };
888 updated |= ((interrupt_hold.min(INTERRUPT_HOLD_MAX) as u16) & 0x0F) << 1;
889 updated
890 })
891 .await
892 }
893}
894
895#[cfg(not(feature = "blocking"))]
897impl<T> Bmi323<T>
898where
899 Self: Access,
900{
901 pub async fn wait_for_interrupt<P: embedded_hal_async::digital::Wait>(
907 &mut self,
908 pin: &mut P,
909 channel: InterruptChannel,
910 ) -> Result<InterruptStatus, Error<<Self as Access>::BusError>> {
911 pin.wait_for_high().await.map_err(|_| Error::GpioError)?;
912 self.read_interrupt_status(channel).await
913 }
914}