1#![cfg_attr(not(feature = "std"), no_std)]
129#![deny(missing_docs)]
130#![deny(warnings)]
131#![allow(clippy::missing_errors_doc)]
132
133use core::cmp;
134use core::fmt::Debug;
135
136use accelerometer::vector::{F32x3, I16x3};
137use accelerometer::{Error, ErrorKind, RawAccelerometer};
138#[cfg(feature = "async")]
139use device_driver::{AsyncBufferInterface, AsyncRegisterInterface};
140use device_driver::{BufferInterface, BufferInterfaceError, RegisterInterface};
141use embedded_hal as hal;
142#[cfg(feature = "async")]
143use embedded_hal_async as hal_async;
144use hal::i2c::I2c;
145#[cfg(feature = "async")]
146use hal_async::i2c::I2c as AsyncI2c;
147#[cfg(feature = "async")]
148use hal_async::spi::SpiDevice as AsyncSpiDevice;
149
150#[allow(unsafe_code)]
151#[allow(missing_docs)]
152#[allow(clippy::doc_markdown, clippy::missing_errors_doc, clippy::identity_op)]
153mod generated {
154 device_driver::create_device!(
155 device_name: Lis2de12Device,
156 manifest: "src/lis2de12.yaml"
157 );
158}
159
160pub use generated::{Fm, Fs, Lis2de12Device, Odr, St, TempEn, field_sets};
161
162pub const FIFO_FRAME_BYTES: usize = 6;
164pub const FIFO_CAPACITY: u8 = 32;
166pub type FifoFrame = [u8; FIFO_FRAME_BYTES];
168pub const FIFO_WATERMARK_MAX: u8 = 31;
170
171#[derive(Copy, Clone, Debug, Eq, PartialEq)]
173pub enum FifoMode {
174 Bypass,
176 Fifo,
178 Stream,
180 StreamToFifo,
182}
183
184impl From<FifoMode> for Fm {
185 fn from(mode: FifoMode) -> Self {
186 match mode {
187 FifoMode::Bypass => Fm::Bypass,
188 FifoMode::Fifo => Fm::Fifo,
189 FifoMode::Stream => Fm::Stream,
190 FifoMode::StreamToFifo => Fm::StreamToFifo,
191 }
192 }
193}
194
195impl From<Fm> for FifoMode {
196 fn from(mode: Fm) -> Self {
197 match mode {
198 Fm::Bypass => FifoMode::Bypass,
199 Fm::Fifo => FifoMode::Fifo,
200 Fm::Stream => FifoMode::Stream,
201 Fm::StreamToFifo => FifoMode::StreamToFifo,
202 }
203 }
204}
205
206#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
212pub enum InterruptPolarity {
213 #[default]
215 ActiveHigh,
216 ActiveLow,
218}
219
220#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
222pub enum LatchMode {
223 #[default]
227 NonLatched,
228 Latched,
231}
232
233fn mode_bits(mode: MotionDetectionMode) -> (bool, bool, bool) {
235 match mode {
236 MotionDetectionMode::OrCombination => (false, false, false),
237 MotionDetectionMode::AndCombination => (true, false, false),
238 MotionDetectionMode::SixDirection => (false, true, false),
239 MotionDetectionMode::SixDirectionPosition => (true, true, false),
240 MotionDetectionMode::FourDirection => (false, true, true),
241 MotionDetectionMode::FourDirectionPosition => (true, true, true),
242 }
243}
244
245#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
247pub enum MotionDetectionMode {
248 #[default]
250 OrCombination,
251 AndCombination,
253 SixDirection,
255 SixDirectionPosition,
257 FourDirection,
260 FourDirectionPosition,
263}
264
265#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
267#[allow(clippy::struct_excessive_bools)]
268pub struct MotionAxesConfig {
269 pub x_high: bool,
271 pub x_low: bool,
273 pub y_high: bool,
275 pub y_low: bool,
277 pub z_high: bool,
279 pub z_low: bool,
281}
282
283impl MotionAxesConfig {
284 #[must_use]
286 pub const fn none() -> Self {
287 Self {
288 x_high: false,
289 x_low: false,
290 y_high: false,
291 y_low: false,
292 z_high: false,
293 z_low: false,
294 }
295 }
296
297 #[must_use]
299 pub const fn all_high() -> Self {
300 Self {
301 x_high: true,
302 x_low: false,
303 y_high: true,
304 y_low: false,
305 z_high: true,
306 z_low: false,
307 }
308 }
309
310 #[must_use]
312 pub const fn all_low() -> Self {
313 Self {
314 x_high: false,
315 x_low: true,
316 y_high: false,
317 y_low: true,
318 z_high: false,
319 z_low: true,
320 }
321 }
322
323 #[must_use]
325 pub const fn all() -> Self {
326 Self {
327 x_high: true,
328 x_low: true,
329 y_high: true,
330 y_low: true,
331 z_high: true,
332 z_low: true,
333 }
334 }
335
336 #[must_use]
338 pub const fn any(&self) -> bool {
339 self.x_high || self.x_low || self.y_high || self.y_low || self.z_high || self.z_low
340 }
341}
342
343#[derive(Copy, Clone, Debug, Eq, PartialEq)]
345pub struct MotionConfig {
346 pub enable: bool,
348 pub mode: MotionDetectionMode,
350 pub axes: MotionAxesConfig,
352 pub threshold: u8,
355 pub duration: u8,
357 pub latch: LatchMode,
359 pub high_pass_filter: bool,
361}
362
363impl Default for MotionConfig {
364 fn default() -> Self {
365 Self {
366 enable: false,
367 mode: MotionDetectionMode::OrCombination,
368 axes: MotionAxesConfig::none(),
369 threshold: 0,
370 duration: 0,
371 latch: LatchMode::NonLatched,
372 high_pass_filter: false,
373 }
374 }
375}
376
377impl MotionConfig {
378 #[must_use]
380 pub const fn disabled() -> Self {
381 Self {
382 enable: false,
383 mode: MotionDetectionMode::OrCombination,
384 axes: MotionAxesConfig::none(),
385 threshold: 0,
386 duration: 0,
387 latch: LatchMode::NonLatched,
388 high_pass_filter: false,
389 }
390 }
391
392 #[must_use]
394 pub const fn with_enable(mut self, enable: bool) -> Self {
395 self.enable = enable;
396 self
397 }
398
399 #[must_use]
401 pub const fn with_mode(mut self, mode: MotionDetectionMode) -> Self {
402 self.mode = mode;
403 self
404 }
405
406 #[must_use]
408 pub const fn with_axes(mut self, axes: MotionAxesConfig) -> Self {
409 self.axes = axes;
410 self
411 }
412
413 #[must_use]
415 pub const fn with_threshold(mut self, threshold: u8) -> Self {
416 self.threshold = if threshold > 127 { 127 } else { threshold };
417 self
418 }
419
420 #[must_use]
422 pub const fn with_duration(mut self, duration: u8) -> Self {
423 self.duration = if duration > 127 { 127 } else { duration };
424 self
425 }
426
427 #[must_use]
429 pub const fn with_latch(mut self, latch: LatchMode) -> Self {
430 self.latch = latch;
431 self
432 }
433
434 #[must_use]
436 pub const fn with_high_pass_filter(mut self, enable: bool) -> Self {
437 self.high_pass_filter = enable;
438 self
439 }
440}
441
442#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
444#[allow(clippy::struct_excessive_bools)]
445pub struct ClickAxesConfig {
446 pub x_single: bool,
448 pub x_double: bool,
450 pub y_single: bool,
452 pub y_double: bool,
454 pub z_single: bool,
456 pub z_double: bool,
458}
459
460impl ClickAxesConfig {
461 #[must_use]
463 pub const fn none() -> Self {
464 Self {
465 x_single: false,
466 x_double: false,
467 y_single: false,
468 y_double: false,
469 z_single: false,
470 z_double: false,
471 }
472 }
473
474 #[must_use]
476 pub const fn all_single() -> Self {
477 Self {
478 x_single: true,
479 x_double: false,
480 y_single: true,
481 y_double: false,
482 z_single: true,
483 z_double: false,
484 }
485 }
486
487 #[must_use]
489 pub const fn all_double() -> Self {
490 Self {
491 x_single: false,
492 x_double: true,
493 y_single: false,
494 y_double: true,
495 z_single: false,
496 z_double: true,
497 }
498 }
499
500 #[must_use]
502 pub const fn all() -> Self {
503 Self {
504 x_single: true,
505 x_double: true,
506 y_single: true,
507 y_double: true,
508 z_single: true,
509 z_double: true,
510 }
511 }
512
513 #[must_use]
515 pub const fn any(&self) -> bool {
516 self.x_single
517 || self.x_double
518 || self.y_single
519 || self.y_double
520 || self.z_single
521 || self.z_double
522 }
523}
524
525#[derive(Copy, Clone, Debug, Eq, PartialEq)]
527pub struct ClickConfig {
528 pub enable: bool,
530 pub axes: ClickAxesConfig,
532 pub threshold: u8,
535 pub time_limit: u8,
537 pub time_latency: u8,
539 pub time_window: u8,
541 pub latch: LatchMode,
543 pub high_pass_filter: bool,
545}
546
547impl Default for ClickConfig {
548 fn default() -> Self {
549 Self {
550 enable: false,
551 axes: ClickAxesConfig::none(),
552 threshold: 0,
553 time_limit: 0,
554 time_latency: 0,
555 time_window: 0,
556 latch: LatchMode::NonLatched,
557 high_pass_filter: false,
558 }
559 }
560}
561
562impl ClickConfig {
563 #[must_use]
565 pub const fn disabled() -> Self {
566 Self {
567 enable: false,
568 axes: ClickAxesConfig::none(),
569 threshold: 0,
570 time_limit: 0,
571 time_latency: 0,
572 time_window: 0,
573 latch: LatchMode::NonLatched,
574 high_pass_filter: false,
575 }
576 }
577
578 #[must_use]
580 pub const fn with_enable(mut self, enable: bool) -> Self {
581 self.enable = enable;
582 self
583 }
584
585 #[must_use]
587 pub const fn with_axes(mut self, axes: ClickAxesConfig) -> Self {
588 self.axes = axes;
589 self
590 }
591
592 #[must_use]
594 pub const fn with_threshold(mut self, threshold: u8) -> Self {
595 self.threshold = if threshold > 127 { 127 } else { threshold };
596 self
597 }
598
599 #[must_use]
601 pub const fn with_time_limit(mut self, time_limit: u8) -> Self {
602 self.time_limit = if time_limit > 127 { 127 } else { time_limit };
603 self
604 }
605
606 #[must_use]
608 pub const fn with_time_latency(mut self, time_latency: u8) -> Self {
609 self.time_latency = time_latency;
610 self
611 }
612
613 #[must_use]
615 pub const fn with_time_window(mut self, time_window: u8) -> Self {
616 self.time_window = time_window;
617 self
618 }
619
620 #[must_use]
622 pub const fn with_latch(mut self, latch: LatchMode) -> Self {
623 self.latch = latch;
624 self
625 }
626
627 #[must_use]
629 pub const fn with_high_pass_filter(mut self, enable: bool) -> Self {
630 self.high_pass_filter = enable;
631 self
632 }
633}
634
635#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
637pub struct ActivityConfig {
638 pub enable: bool,
640 pub threshold: u8,
643 pub duration: u8,
646}
647
648impl ActivityConfig {
649 #[must_use]
651 pub const fn disabled() -> Self {
652 Self {
653 enable: false,
654 threshold: 0,
655 duration: 0,
656 }
657 }
658
659 #[must_use]
661 pub const fn with_enable(mut self, enable: bool) -> Self {
662 self.enable = enable;
663 self
664 }
665
666 #[must_use]
668 pub const fn with_threshold(mut self, threshold: u8) -> Self {
669 self.threshold = if threshold > 127 { 127 } else { threshold };
670 self
671 }
672
673 #[must_use]
675 pub const fn with_duration(mut self, duration: u8) -> Self {
676 self.duration = duration;
677 self
678 }
679}
680
681#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
683#[allow(clippy::struct_excessive_bools)]
684pub struct Int1Routing {
685 pub click: bool,
687 pub ia1: bool,
689 pub ia2: bool,
691 pub data_ready: bool,
693 pub fifo_watermark: bool,
695 pub fifo_overrun: bool,
697}
698
699impl Int1Routing {
700 #[must_use]
702 pub const fn none() -> Self {
703 Self {
704 click: false,
705 ia1: false,
706 ia2: false,
707 data_ready: false,
708 fifo_watermark: false,
709 fifo_overrun: false,
710 }
711 }
712
713 #[must_use]
715 pub const fn any(&self) -> bool {
716 self.click || self.ia1 || self.ia2 || self.data_ready || self.fifo_watermark || self.fifo_overrun
717 }
718}
719
720#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
722#[allow(clippy::struct_excessive_bools)]
723pub struct Int2Routing {
724 pub click: bool,
726 pub ia1: bool,
728 pub ia2: bool,
730 pub boot: bool,
732 pub activity: bool,
734}
735
736impl Int2Routing {
737 #[must_use]
739 pub const fn none() -> Self {
740 Self {
741 click: false,
742 ia1: false,
743 ia2: false,
744 boot: false,
745 activity: false,
746 }
747 }
748
749 #[must_use]
751 pub const fn any(&self) -> bool {
752 self.click || self.ia1 || self.ia2 || self.boot || self.activity
753 }
754}
755
756#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
758pub struct InterruptConfig {
759 pub polarity: InterruptPolarity,
761 pub int1: Int1Routing,
763 pub int2: Int2Routing,
765}
766
767impl InterruptConfig {
768 #[must_use]
770 pub const fn disabled() -> Self {
771 Self {
772 polarity: InterruptPolarity::ActiveHigh,
773 int1: Int1Routing::none(),
774 int2: Int2Routing::none(),
775 }
776 }
777
778 #[must_use]
780 pub const fn with_polarity(mut self, polarity: InterruptPolarity) -> Self {
781 self.polarity = polarity;
782 self
783 }
784
785 #[must_use]
787 pub const fn with_int1(mut self, int1: Int1Routing) -> Self {
788 self.int1 = int1;
789 self
790 }
791
792 #[must_use]
794 pub const fn with_int2(mut self, int2: Int2Routing) -> Self {
795 self.int2 = int2;
796 self
797 }
798}
799
800#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
806#[allow(clippy::struct_excessive_bools)]
807pub struct MotionStatus {
808 pub active: bool,
810 pub x_high: bool,
812 pub x_low: bool,
814 pub y_high: bool,
816 pub y_low: bool,
818 pub z_high: bool,
820 pub z_low: bool,
822}
823
824impl MotionStatus {
825 #[must_use]
827 pub const fn is_active(&self) -> bool {
828 self.active
829 }
830
831 #[must_use]
833 pub const fn x_event(&self) -> bool {
834 self.x_high || self.x_low
835 }
836
837 #[must_use]
839 pub const fn y_event(&self) -> bool {
840 self.y_high || self.y_low
841 }
842
843 #[must_use]
845 pub const fn z_event(&self) -> bool {
846 self.z_high || self.z_low
847 }
848
849 #[must_use]
851 pub const fn any_event(&self) -> bool {
852 self.x_high || self.x_low || self.y_high || self.y_low || self.z_high || self.z_low
853 }
854}
855
856impl From<field_sets::Int1Src> for MotionStatus {
857 fn from(raw: field_sets::Int1Src) -> Self {
858 Self {
859 active: raw.ia(),
860 x_high: raw.xh(),
861 x_low: raw.xl(),
862 y_high: raw.yh(),
863 y_low: raw.yl(),
864 z_high: raw.zh(),
865 z_low: raw.zl(),
866 }
867 }
868}
869
870impl From<field_sets::Int2Src> for MotionStatus {
871 fn from(raw: field_sets::Int2Src) -> Self {
872 Self {
873 active: raw.ia(),
874 x_high: raw.xh(),
875 x_low: raw.xl(),
876 y_high: raw.yh(),
877 y_low: raw.yl(),
878 z_high: raw.zh(),
879 z_low: raw.zl(),
880 }
881 }
882}
883
884#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
886#[allow(clippy::struct_excessive_bools)]
887pub struct ClickStatus {
888 pub active: bool,
890 pub double_click: bool,
892 pub single_click: bool,
894 pub negative: bool,
896 pub x: bool,
898 pub y: bool,
900 pub z: bool,
902}
903
904impl ClickStatus {
905 #[must_use]
907 pub const fn is_active(&self) -> bool {
908 self.active
909 }
910
911 #[must_use]
913 pub const fn is_double_click(&self) -> bool {
914 self.double_click
915 }
916
917 #[must_use]
919 pub const fn is_single_click(&self) -> bool {
920 self.single_click
921 }
922
923 #[must_use]
925 pub const fn is_negative(&self) -> bool {
926 self.negative
927 }
928
929 #[must_use]
931 pub const fn any_event(&self) -> bool {
932 self.x || self.y || self.z
933 }
934}
935
936impl From<field_sets::ClickSrc> for ClickStatus {
937 fn from(raw: field_sets::ClickSrc) -> Self {
938 Self {
939 active: raw.ia(),
940 double_click: raw.d_click(),
941 single_click: raw.s_click(),
942 negative: raw.sign(),
943 x: raw.x(),
944 y: raw.y(),
945 z: raw.z(),
946 }
947 }
948}
949
950#[derive(Copy, Clone, Debug, Default)]
952pub struct InterruptSources {
953 pub motion1: MotionStatus,
955 pub motion2: MotionStatus,
957 pub click: ClickStatus,
959}
960
961impl InterruptSources {
962 #[must_use]
964 pub const fn any_active(&self) -> bool {
965 self.motion1.active || self.motion2.active || self.click.active
966 }
967}
968
969#[derive(Copy, Clone, Debug, Eq, PartialEq)]
971#[must_use]
972pub struct FifoConfig {
973 pub enable: bool,
975 pub mode: FifoMode,
977 pub watermark: Option<u8>,
979}
980
981impl FifoConfig {
982 #[must_use]
984 pub const fn disabled() -> Self {
985 Self {
986 enable: false,
987 mode: FifoMode::Bypass,
988 watermark: None,
989 }
990 }
991
992 #[must_use]
994 pub const fn enabled(mode: FifoMode) -> Self {
995 Self {
996 enable: true,
997 mode,
998 watermark: None,
999 }
1000 }
1001
1002 #[must_use]
1004 pub const fn with_watermark(self, watermark: u8) -> Self {
1005 Self {
1006 watermark: Some(watermark),
1007 ..self
1008 }
1009 }
1010
1011 #[must_use]
1013 fn effective_threshold(self) -> u8 {
1014 if self.enable {
1015 match self.watermark {
1016 Some(level) if level <= FIFO_WATERMARK_MAX => level,
1017 Some(_) | None => FIFO_WATERMARK_MAX,
1018 }
1019 } else {
1020 0
1021 }
1022 }
1023}
1024
1025#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1032pub enum OperatingMode {
1033 #[deprecated(note = "LIS2DE12 is always 8-bit; LPen must always be 1. Use LowPower instead.")]
1035 Normal,
1036 LowPower,
1038}
1039
1040impl OperatingMode {
1041 const fn lpen(self) -> bool {
1042 true
1044 }
1045}
1046
1047#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1049pub struct AxesEnable {
1050 pub x: bool,
1052 pub y: bool,
1054 pub z: bool,
1056}
1057
1058impl AxesEnable {
1059 #[must_use]
1061 pub const fn any(self) -> bool {
1062 self.x || self.y || self.z
1063 }
1064}
1065
1066impl Default for AxesEnable {
1067 fn default() -> Self {
1068 Self {
1069 x: true,
1070 y: true,
1071 z: true,
1072 }
1073 }
1074}
1075
1076#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1078pub struct Lis2de12Config {
1079 pub odr: Odr,
1081 pub mode: OperatingMode,
1083 pub scale: Fs,
1085 pub axes: AxesEnable,
1087 pub block_data_update: bool,
1089 pub temperature_enable: bool,
1091 pub fifo: FifoConfig,
1093}
1094
1095impl Default for Lis2de12Config {
1096 fn default() -> Self {
1097 Self {
1098 odr: Odr::HundredHz,
1099 mode: OperatingMode::LowPower,
1100 scale: Fs::PlusMinus2G,
1101 axes: AxesEnable::default(),
1102 block_data_update: true,
1103 temperature_enable: false,
1104 fifo: FifoConfig::disabled(),
1105 }
1106 }
1107}
1108
1109impl Lis2de12Config {
1110 fn sensitivity_g_per_lsb(self) -> f32 {
1111 match self.scale {
1114 Fs::PlusMinus2G => 0.0156,
1115 Fs::PlusMinus4G => 0.0312,
1116 Fs::PlusMinus8G => 0.0625,
1117 Fs::PlusMinus16G => 0.1875,
1118 }
1119 }
1120
1121 fn sensitivity_mg_per_lsb(self) -> f32 {
1122 self.sensitivity_g_per_lsb() * 1000.0
1123 }
1124}
1125
1126#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1128#[must_use]
1129pub struct FifoStatus {
1130 pub watermark: bool,
1132 pub overrun: bool,
1134 pub empty: bool,
1136 pub frames: u8,
1138}
1139
1140impl FifoStatus {
1141 #[must_use]
1143 pub fn from_raw(raw: field_sets::FifoSrcReg) -> Self {
1144 let raw_frames = raw.fss();
1145 let frames = if raw.empty() {
1146 0
1147 } else if raw.ovrn_fifo() && raw_frames == 0 {
1148 FIFO_CAPACITY
1149 } else {
1150 raw_frames.min(FIFO_CAPACITY)
1151 };
1152
1153 Self {
1154 watermark: raw.wtm(),
1155 overrun: raw.ovrn_fifo(),
1156 empty: raw.empty(),
1157 frames,
1158 }
1159 }
1160
1161 #[must_use]
1163 pub const fn len(self) -> u8 {
1164 self.frames
1165 }
1166
1167 #[must_use]
1169 pub const fn has_data(self) -> bool {
1170 self.frames > 0
1171 }
1172
1173 #[must_use]
1175 pub const fn remaining_capacity(self) -> u8 {
1176 FIFO_CAPACITY.saturating_sub(self.frames)
1177 }
1178
1179 #[must_use]
1181 pub const fn is_watermark_triggered(self) -> bool {
1182 self.watermark
1183 }
1184
1185 #[must_use]
1187 pub const fn is_overrun(self) -> bool {
1188 self.overrun
1189 }
1190
1191 #[must_use]
1193 pub const fn is_empty(self) -> bool {
1194 self.empty
1195 }
1196}
1197
1198impl From<field_sets::FifoSrcReg> for FifoStatus {
1199 fn from(raw: field_sets::FifoSrcReg) -> Self {
1200 Self::from_raw(raw)
1201 }
1202}
1203
1204fn validate_config_common<E: Debug>(config: &Lis2de12Config) -> Result<(), Error<E>> {
1205 if !config.axes.any() {
1206 return Err(Error::new(ErrorKind::Device));
1207 }
1208 if config.fifo.enable
1209 && let Some(watermark) = config.fifo.watermark
1210 && watermark > FIFO_WATERMARK_MAX
1211 {
1212 return Err(Error::new(ErrorKind::Param));
1213 }
1214 Ok(())
1215}
1216
1217pub struct DeviceInterface<I2C> {
1219 pub i2c: I2C,
1221 pub address: u8,
1223}
1224
1225#[cfg(feature = "async")]
1227pub struct DeviceInterfaceAsync<I2C> {
1228 pub i2c: I2C,
1230 pub address: u8,
1232}
1233
1234pub struct SpiInterface<SPI> {
1236 pub spi: SPI,
1238}
1239
1240#[cfg(feature = "async")]
1242pub struct SpiInterfaceAsync<SPI> {
1243 pub spi: SPI,
1245}
1246
1247impl<I2C> BufferInterfaceError for DeviceInterface<I2C>
1248where
1249 I2C: hal::i2c::I2c,
1250{
1251 type Error = I2C::Error;
1252}
1253
1254#[cfg(feature = "async")]
1255impl<I2C> BufferInterfaceError for DeviceInterfaceAsync<I2C>
1256where
1257 I2C: AsyncI2c,
1258{
1259 type Error = I2C::Error;
1260}
1261
1262impl<I2C> RegisterInterface for DeviceInterface<I2C>
1263where
1264 I2C: hal::i2c::I2c,
1265{
1266 type Error = I2C::Error;
1267 type AddressType = u8;
1268
1269 fn write_register(&mut self, address: Self::AddressType, _size_bits: u32, data: &[u8]) -> Result<(), Self::Error> {
1270 let mut buf = [0u8; 1 + 8];
1271 buf[0] = address;
1272 let end = 1 + data.len();
1273 buf[1..end].copy_from_slice(data);
1274 self.i2c.write(self.address, &buf[..end])
1275 }
1276
1277 fn read_register(
1278 &mut self,
1279 address: Self::AddressType,
1280 _size_bits: u32,
1281 data: &mut [u8],
1282 ) -> Result<(), Self::Error> {
1283 self.i2c.write_read(self.address, &[address], data)
1284 }
1285}
1286
1287#[cfg(feature = "async")]
1288impl<I2C> AsyncRegisterInterface for DeviceInterfaceAsync<I2C>
1289where
1290 I2C: AsyncI2c,
1291{
1292 type Error = I2C::Error;
1293 type AddressType = u8;
1294
1295 async fn write_register(
1296 &mut self,
1297 address: Self::AddressType,
1298 _size_bits: u32,
1299 data: &[u8],
1300 ) -> Result<(), Self::Error> {
1301 let mut buf = [0u8; 1 + 8];
1302 buf[0] = address;
1303 let end = 1 + data.len();
1304 buf[1..end].copy_from_slice(data);
1305 self.i2c.write(self.address, &buf[..end]).await
1306 }
1307
1308 async fn read_register(
1309 &mut self,
1310 address: Self::AddressType,
1311 _size_bits: u32,
1312 data: &mut [u8],
1313 ) -> Result<(), Self::Error> {
1314 self.i2c.write_read(self.address, &[address], data).await
1315 }
1316}
1317
1318impl<I2C> BufferInterface for DeviceInterface<I2C>
1319where
1320 I2C: hal::i2c::I2c,
1321{
1322 type AddressType = u8;
1323
1324 fn read(
1325 &mut self,
1326 address: Self::AddressType,
1327 buf: &mut [u8],
1328 ) -> Result<usize, <Self as RegisterInterface>::Error> {
1329 self.i2c.write_read(self.address, &[address], buf)?;
1330 Ok(buf.len())
1331 }
1332
1333 fn write(&mut self, address: Self::AddressType, buf: &[u8]) -> Result<usize, <Self as RegisterInterface>::Error> {
1334 let mut data = [0u8; 1 + 32];
1335 data[0] = address;
1336 let end = 1 + buf.len();
1337 data[1..end].copy_from_slice(buf);
1338 self.i2c.write(self.address, &data[..end])?;
1339 Ok(buf.len())
1340 }
1341
1342 fn flush(&mut self, _address: Self::AddressType) -> Result<(), <Self as RegisterInterface>::Error> {
1343 Ok(())
1344 }
1345}
1346
1347#[cfg(feature = "async")]
1348impl<I2C> AsyncBufferInterface for DeviceInterfaceAsync<I2C>
1349where
1350 I2C: AsyncI2c,
1351{
1352 type AddressType = u8;
1353
1354 async fn read(&mut self, address: Self::AddressType, buf: &mut [u8]) -> Result<usize, Self::Error> {
1355 self.i2c.write_read(self.address, &[address], buf).await?;
1356 Ok(buf.len())
1357 }
1358
1359 async fn write(&mut self, address: Self::AddressType, buf: &[u8]) -> Result<usize, Self::Error> {
1360 let mut data = [0u8; 1 + 32];
1361 data[0] = address;
1362 let end = 1 + buf.len();
1363 data[1..end].copy_from_slice(buf);
1364 self.i2c.write(self.address, &data[..end]).await?;
1365 Ok(buf.len())
1366 }
1367
1368 async fn flush(&mut self, _address: Self::AddressType) -> Result<(), Self::Error> {
1369 Ok(())
1370 }
1371}
1372
1373impl<SPI> BufferInterfaceError for SpiInterface<SPI>
1374where
1375 SPI: hal::spi::SpiDevice,
1376{
1377 type Error = SPI::Error;
1378}
1379
1380#[cfg(feature = "async")]
1381impl<SPI> BufferInterfaceError for SpiInterfaceAsync<SPI>
1382where
1383 SPI: hal_async::spi::SpiDevice,
1384{
1385 type Error = SPI::Error;
1386}
1387
1388impl<SPI> RegisterInterface for SpiInterface<SPI>
1389where
1390 SPI: hal::spi::SpiDevice,
1391{
1392 type Error = SPI::Error;
1393 type AddressType = u8;
1394
1395 fn write_register(&mut self, address: Self::AddressType, _size_bits: u32, data: &[u8]) -> Result<(), Self::Error> {
1396 let mut buf = [0u8; 1 + 8];
1397 buf[0] = address; let end = 1 + data.len();
1399 buf[1..end].copy_from_slice(data);
1400 self.spi.write(&buf[..end])
1401 }
1402
1403 fn read_register(
1404 &mut self,
1405 address: Self::AddressType,
1406 _size_bits: u32,
1407 data: &mut [u8],
1408 ) -> Result<(), Self::Error> {
1409 let addr_byte = 0x80 | address; self.spi.transaction(&mut [
1411 hal::spi::Operation::Write(&[addr_byte]),
1412 hal::spi::Operation::Read(data),
1413 ])
1414 }
1415}
1416
1417#[cfg(feature = "async")]
1418impl<SPI> AsyncRegisterInterface for SpiInterfaceAsync<SPI>
1419where
1420 SPI: hal_async::spi::SpiDevice,
1421{
1422 type Error = SPI::Error;
1423 type AddressType = u8;
1424
1425 async fn write_register(
1426 &mut self,
1427 address: Self::AddressType,
1428 _size_bits: u32,
1429 data: &[u8],
1430 ) -> Result<(), Self::Error> {
1431 let mut buf = [0u8; 1 + 8];
1432 buf[0] = address; let end = 1 + data.len();
1434 buf[1..end].copy_from_slice(data);
1435 self.spi.write(&buf[..end]).await
1436 }
1437
1438 async fn read_register(
1439 &mut self,
1440 address: Self::AddressType,
1441 _size_bits: u32,
1442 data: &mut [u8],
1443 ) -> Result<(), Self::Error> {
1444 let addr_byte = 0x80 | address; self.spi.transaction(&mut [
1446 hal_async::spi::Operation::Write(&[addr_byte]),
1447 hal_async::spi::Operation::Read(data),
1448 ]).await
1449 }
1450}
1451
1452impl<SPI> BufferInterface for SpiInterface<SPI>
1453where
1454 SPI: hal::spi::SpiDevice,
1455{
1456 type AddressType = u8;
1457
1458 fn read(
1459 &mut self,
1460 address: Self::AddressType,
1461 buf: &mut [u8],
1462 ) -> Result<usize, <Self as RegisterInterface>::Error> {
1463 let addr_byte = 0xC0 | address;
1465 self.spi.transaction(&mut [
1466 hal::spi::Operation::Write(&[addr_byte]),
1467 hal::spi::Operation::Read(buf),
1468 ])?;
1469 Ok(buf.len())
1470 }
1471
1472 fn write(&mut self, address: Self::AddressType, buf: &[u8]) -> Result<usize, <Self as RegisterInterface>::Error> {
1473 let mut data = [0u8; 1 + 32];
1474 data[0] = 0x40 | address; let end = 1 + buf.len();
1476 data[1..end].copy_from_slice(buf);
1477 self.spi.write(&data[..end])?;
1478 Ok(buf.len())
1479 }
1480
1481 fn flush(&mut self, _address: Self::AddressType) -> Result<(), <Self as RegisterInterface>::Error> {
1482 Ok(())
1483 }
1484}
1485
1486#[cfg(feature = "async")]
1487impl<SPI> AsyncBufferInterface for SpiInterfaceAsync<SPI>
1488where
1489 SPI: hal_async::spi::SpiDevice,
1490{
1491 type AddressType = u8;
1492
1493 async fn read(&mut self, address: Self::AddressType, buf: &mut [u8]) -> Result<usize, Self::Error> {
1494 let addr_byte = 0xC0 | address;
1496 self.spi.transaction(&mut [
1497 hal_async::spi::Operation::Write(&[addr_byte]),
1498 hal_async::spi::Operation::Read(buf),
1499 ]).await?;
1500 Ok(buf.len())
1501 }
1502
1503 async fn write(&mut self, address: Self::AddressType, buf: &[u8]) -> Result<usize, Self::Error> {
1504 let mut data = [0u8; 1 + 32];
1505 data[0] = 0x40 | address; let end = 1 + buf.len();
1507 data[1..end].copy_from_slice(buf);
1508 self.spi.write(&data[..end]).await?;
1509 Ok(buf.len())
1510 }
1511
1512 async fn flush(&mut self, _address: Self::AddressType) -> Result<(), Self::Error> {
1513 Ok(())
1514 }
1515}
1516
1517pub enum SlaveAddr {
1523 Default,
1525 Alternative,
1527}
1528
1529impl SlaveAddr {
1530 const fn addr(self) -> u8 {
1531 match self {
1532 SlaveAddr::Default => 0x18,
1533 SlaveAddr::Alternative => 0x19,
1534 }
1535 }
1536}
1537
1538pub struct Lis2de12<IFACE> {
1540 device: Lis2de12Device<IFACE>,
1541 config: Lis2de12Config,
1542}
1543
1544pub type Lis2de12I2c<I2C> = Lis2de12<DeviceInterface<I2C>>;
1546
1547pub type Lis2de12Spi<SPI> = Lis2de12<SpiInterface<SPI>>;
1549
1550impl<IFACE> Lis2de12<IFACE>
1552where
1553 IFACE: RegisterInterface<AddressType = u8, Error = <IFACE as BufferInterfaceError>::Error> + BufferInterface<AddressType = u8>,
1554 <IFACE as RegisterInterface>::Error: Debug,
1555{
1556 pub const fn config(&self) -> Lis2de12Config {
1558 self.config
1559 }
1560
1561 pub fn set_config(&mut self, config: Lis2de12Config) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1563 validate_config_common::<<IFACE as RegisterInterface>::Error>(&config)?;
1564 self.apply_config(config)?;
1565 self.config = config;
1566 Ok(())
1567 }
1568
1569 pub fn read_raw(&mut self) -> Result<I16x3, Error<<IFACE as RegisterInterface>::Error>> {
1571 let frame = self.read_fifo_frame()?;
1572 Ok(decode_raw(&frame, self.config.mode))
1573 }
1574
1575 pub fn read_mg(&mut self) -> Result<I16x3, Error<<IFACE as RegisterInterface>::Error>> {
1577 let raw = self.read_raw()?;
1578 Ok(scale_to_mg(raw, self.config.sensitivity_mg_per_lsb()))
1579 }
1580
1581 pub fn read_g(&mut self) -> Result<F32x3, Error<<IFACE as RegisterInterface>::Error>> {
1583 let raw = self.read_raw()?;
1584 Ok(scale_to_g(raw, self.config.sensitivity_g_per_lsb()))
1585 }
1586
1587 pub fn read_fifo_frame(&mut self) -> Result<FifoFrame, Error<<IFACE as RegisterInterface>::Error>> {
1589 let mut buf: FifoFrame = [0; FIFO_FRAME_BYTES];
1590 let mut fifo = self.device.fifo_read_start();
1591 let mut offset = 0;
1592 while offset < buf.len() {
1593 let read = fifo.read(&mut buf[offset..]).map_err(Error::from)?;
1594 if read == 0 {
1595 return Err(Error::new(ErrorKind::Device));
1596 }
1597 offset += read;
1598 }
1599 Ok(buf)
1600 }
1601
1602 pub fn read_fifo_frames(&mut self, frames: &mut [FifoFrame]) -> Result<usize, Error<<IFACE as RegisterInterface>::Error>> {
1605 if frames.is_empty() {
1606 return Ok(0);
1607 }
1608
1609 let status = self.fifo_status()?;
1610 if status.is_empty() {
1611 return Ok(0);
1612 }
1613
1614 let to_read = cmp::min(status.len() as usize, frames.len());
1615 for slot in &mut frames[..to_read] {
1616 *slot = self.read_fifo_frame()?;
1617 }
1618 Ok(to_read)
1619 }
1620
1621 pub fn drain_fifo(&mut self) -> Result<usize, Error<<IFACE as RegisterInterface>::Error>> {
1623 let mut drained = 0;
1624 loop {
1625 let status = self.fifo_status()?;
1626 if status.is_empty() {
1627 break;
1628 }
1629 self.read_fifo_frame()?;
1630 drained += 1;
1631 }
1632 Ok(drained)
1633 }
1634
1635 pub fn fifo_status(&mut self) -> Result<FifoStatus, Error<<IFACE as RegisterInterface>::Error>> {
1637 let status = self.device.fifo_src_reg().read().map_err(Error::from)?;
1638 Ok(FifoStatus::from(status))
1639 }
1640
1641 pub fn set_temperature_sensor(&mut self, enable: bool) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1643 self.write_temperature_sensor(enable)?;
1644 self.config.temperature_enable = enable;
1645 Ok(())
1646 }
1647
1648 pub fn read_temperature_raw(&mut self) -> Result<i16, Error<<IFACE as RegisterInterface>::Error>> {
1652 let low = self.device.out_temp_l().read().map_err(Error::from)?.temp_l() as u8;
1653 let high = self.device.out_temp_h().read().map_err(Error::from)?.temp_h() as u8;
1654 Ok(i16::from_le_bytes([low, high]))
1655 }
1656
1657 pub fn read_temperature(&mut self) -> Result<f32, Error<<IFACE as RegisterInterface>::Error>> {
1683 let raw = self.read_temperature_raw()?;
1684 Ok((raw >> 8) as f32)
1688 }
1689
1690 pub fn set_high_pass_to_outputs(&mut self, enable: bool) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1694 self.device
1695 .ctrl_reg_2()
1696 .modify(|reg: &mut field_sets::CtrlReg2| reg.set_fds(enable))
1697 .map_err(Error::from)
1698 }
1699
1700 pub fn high_pass_to_outputs(&mut self) -> Result<bool, Error<<IFACE as RegisterInterface>::Error>> {
1702 Ok(self.device.ctrl_reg_2().read().map_err(Error::from)?.fds())
1703 }
1704
1705 pub fn set_sdo_pullup_connected(&mut self, connected: bool) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1709 self.device
1710 .ctrl_reg_0()
1711 .modify(|reg: &mut field_sets::CtrlReg0| reg.set_sdo_pu_disc(!connected))
1712 .map_err(Error::from)
1713 }
1714
1715 pub fn sdo_pullup_connected(&mut self) -> Result<bool, Error<<IFACE as RegisterInterface>::Error>> {
1717 Ok(!self.device.ctrl_reg_0().read().map_err(Error::from)?.sdo_pu_disc())
1718 }
1719
1720 pub fn reboot(&mut self) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1722 self.device
1723 .ctrl_reg_5()
1724 .write(|reg: &mut field_sets::CtrlReg5| reg.set_boot(true))
1725 .map_err(Error::from)
1726 }
1727
1728 pub fn set_motion1_config(&mut self, config: MotionConfig) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1734 self.write_motion_config_int1(config)
1735 }
1736
1737 pub fn set_motion2_config(&mut self, config: MotionConfig) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1739 self.write_motion_config_int2(config)
1740 }
1741
1742 pub fn motion1_status(&mut self) -> Result<MotionStatus, Error<<IFACE as RegisterInterface>::Error>> {
1744 let raw = self.device.int_1_src().read().map_err(Error::from)?;
1745 Ok(MotionStatus::from(raw))
1746 }
1747
1748 pub fn motion2_status(&mut self) -> Result<MotionStatus, Error<<IFACE as RegisterInterface>::Error>> {
1750 let raw = self.device.int_2_src().read().map_err(Error::from)?;
1751 Ok(MotionStatus::from(raw))
1752 }
1753
1754 pub fn set_click_config(&mut self, config: ClickConfig) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1760 self.write_click_config(config)
1761 }
1762
1763 pub fn click_status(&mut self) -> Result<ClickStatus, Error<<IFACE as RegisterInterface>::Error>> {
1765 let raw = self.device.click_src().read().map_err(Error::from)?;
1766 Ok(ClickStatus::from(raw))
1767 }
1768
1769 pub fn set_activity_config(&mut self, config: ActivityConfig) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1775 self.write_activity_config(config)
1776 }
1777
1778 pub fn set_interrupt_config(&mut self, config: InterruptConfig) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1784 self.write_interrupt_config(config)
1785 }
1786
1787 pub fn set_interrupt_polarity(&mut self, polarity: InterruptPolarity) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1789 self.device
1790 .ctrl_reg_6()
1791 .modify(|reg: &mut field_sets::CtrlReg6| {
1792 reg.set_int_polarity(matches!(polarity, InterruptPolarity::ActiveLow));
1793 })
1794 .map_err(Error::from)
1795 }
1796
1797 pub fn interrupt_sources(&mut self) -> Result<InterruptSources, Error<<IFACE as RegisterInterface>::Error>> {
1802 let motion1 = self.motion1_status()?;
1803 let motion2 = self.motion2_status()?;
1804 let click = self.click_status()?;
1805 Ok(InterruptSources { motion1, motion2, click })
1806 }
1807
1808 fn write_temperature_sensor(&mut self, enable: bool) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1809 self.device
1810 .temp_cfg_reg()
1811 .write(|reg: &mut field_sets::TempCfgReg| {
1812 reg.set_temp_en(if enable { TempEn::TempEn } else { TempEn::TempDis });
1813 })
1814 .map_err(Error::from)
1815 }
1816
1817 fn apply_config(&mut self, config: Lis2de12Config) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1818 self.device
1819 .ctrl_reg_1()
1820 .write(|reg: &mut field_sets::CtrlReg1| {
1821 reg.set_odr(config.odr);
1822 reg.set_lpen(config.mode.lpen());
1823 reg.set_xen(config.axes.x);
1824 reg.set_yen(config.axes.y);
1825 reg.set_zen(config.axes.z);
1826 })
1827 .map_err(Error::from)?;
1828
1829 self.device
1830 .ctrl_reg_4()
1831 .write(|reg: &mut field_sets::CtrlReg4| {
1832 reg.set_bdu(config.block_data_update);
1833 reg.set_fs(config.scale);
1834 reg.set_st(St::Normal);
1835 reg.set_sim(false);
1836 })
1837 .map_err(Error::from)?;
1838
1839 self.device
1840 .ctrl_reg_5()
1841 .write(|reg: &mut field_sets::CtrlReg5| {
1842 reg.set_fifo_en(config.fifo.enable);
1843 })
1844 .map_err(Error::from)?;
1845
1846 self.device
1847 .fifo_ctrl_reg()
1848 .write(|reg: &mut field_sets::FifoCtrlReg| {
1849 reg.set_fm(config.fifo.mode.into());
1850 reg.set_tr(false);
1851 reg.set_fth(config.fifo.effective_threshold());
1852 })
1853 .map_err(Error::from)?;
1854
1855 self.write_temperature_sensor(config.temperature_enable)?;
1856 Ok(())
1857 }
1858
1859 fn write_motion_config_int1(&mut self, config: MotionConfig) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1860 let (aoi, sixd, d4d) = mode_bits(config.mode);
1861
1862 self.device
1863 .int_1_cfg()
1864 .write(|reg: &mut field_sets::Int1Cfg| {
1865 reg.set_aoi(aoi);
1866 reg.set_sixd(sixd);
1867 reg.set_xhie(config.axes.x_high && config.enable);
1868 reg.set_xlie(config.axes.x_low && config.enable);
1869 reg.set_yhie(config.axes.y_high && config.enable);
1870 reg.set_ylie(config.axes.y_low && config.enable);
1871 reg.set_zhie(config.axes.z_high && config.enable);
1872 reg.set_zlie(config.axes.z_low && config.enable);
1873 })
1874 .map_err(Error::from)?;
1875
1876 self.device
1877 .int_1_ths()
1878 .write(|reg: &mut field_sets::Int1Ths| {
1879 reg.set_ths(config.threshold.min(127));
1880 })
1881 .map_err(Error::from)?;
1882
1883 self.device
1884 .int_1_duration()
1885 .write(|reg: &mut field_sets::Int1Duration| {
1886 reg.set_d(config.duration.min(127));
1887 })
1888 .map_err(Error::from)?;
1889
1890 self.device
1891 .ctrl_reg_5()
1892 .modify(|reg: &mut field_sets::CtrlReg5| {
1893 reg.set_lir_int_1(matches!(config.latch, LatchMode::Latched));
1894 reg.set_d_4_d_int_1(d4d);
1895 })
1896 .map_err(Error::from)?;
1897
1898 self.device
1899 .ctrl_reg_2()
1900 .modify(|reg: &mut field_sets::CtrlReg2| {
1901 reg.set_hp_ia_1(config.high_pass_filter);
1902 })
1903 .map_err(Error::from)?;
1904
1905 Ok(())
1906 }
1907
1908 fn write_motion_config_int2(&mut self, config: MotionConfig) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1909 let (aoi, sixd, d4d) = mode_bits(config.mode);
1910
1911 self.device
1912 .int_2_cfg()
1913 .write(|reg: &mut field_sets::Int2Cfg| {
1914 reg.set_aoi(aoi);
1915 reg.set_sixd(sixd);
1916 reg.set_xhie(config.axes.x_high && config.enable);
1917 reg.set_xlie(config.axes.x_low && config.enable);
1918 reg.set_yhie(config.axes.y_high && config.enable);
1919 reg.set_ylie(config.axes.y_low && config.enable);
1920 reg.set_zhie(config.axes.z_high && config.enable);
1921 reg.set_zlie(config.axes.z_low && config.enable);
1922 })
1923 .map_err(Error::from)?;
1924
1925 self.device
1926 .int_2_ths()
1927 .write(|reg: &mut field_sets::Int2Ths| {
1928 reg.set_ths(config.threshold.min(127));
1929 })
1930 .map_err(Error::from)?;
1931
1932 self.device
1933 .int_2_duration()
1934 .write(|reg: &mut field_sets::Int2Duration| {
1935 reg.set_d(config.duration.min(127));
1936 })
1937 .map_err(Error::from)?;
1938
1939 self.device
1940 .ctrl_reg_5()
1941 .modify(|reg: &mut field_sets::CtrlReg5| {
1942 reg.set_lir_int_2(matches!(config.latch, LatchMode::Latched));
1943 reg.set_d_4_d_int_2(d4d);
1944 })
1945 .map_err(Error::from)?;
1946
1947 self.device
1948 .ctrl_reg_2()
1949 .modify(|reg: &mut field_sets::CtrlReg2| {
1950 reg.set_hp_ia_2(config.high_pass_filter);
1951 })
1952 .map_err(Error::from)?;
1953
1954 Ok(())
1955 }
1956
1957 fn write_click_config(&mut self, config: ClickConfig) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
1958 self.device
1960 .click_cfg()
1961 .write(|reg: &mut field_sets::ClickCfg| {
1962 reg.set_xs(config.axes.x_single && config.enable);
1963 reg.set_xd(config.axes.x_double && config.enable);
1964 reg.set_ys(config.axes.y_single && config.enable);
1965 reg.set_yd(config.axes.y_double && config.enable);
1966 reg.set_zs(config.axes.z_single && config.enable);
1967 reg.set_zd(config.axes.z_double && config.enable);
1968 })
1969 .map_err(Error::from)?;
1970
1971 self.device
1973 .click_ths()
1974 .write(|reg: &mut field_sets::ClickThs| {
1975 reg.set_ths(config.threshold.min(127));
1976 reg.set_lir_click(matches!(config.latch, LatchMode::Latched));
1977 })
1978 .map_err(Error::from)?;
1979
1980 self.device
1982 .time_limit()
1983 .write(|reg: &mut field_sets::TimeLimit| {
1984 reg.set_tli(config.time_limit.min(127));
1985 })
1986 .map_err(Error::from)?;
1987
1988 self.device
1990 .time_latency()
1991 .write(|reg: &mut field_sets::TimeLatency| {
1992 reg.set_tla(config.time_latency);
1993 })
1994 .map_err(Error::from)?;
1995
1996 self.device
1998 .time_window()
1999 .write(|reg: &mut field_sets::TimeWindow| {
2000 reg.set_tw(config.time_window);
2001 })
2002 .map_err(Error::from)?;
2003
2004 self.device
2006 .ctrl_reg_2()
2007 .modify(|reg: &mut field_sets::CtrlReg2| {
2008 reg.set_hpclick(config.high_pass_filter);
2009 })
2010 .map_err(Error::from)?;
2011
2012 Ok(())
2013 }
2014
2015 fn write_activity_config(&mut self, config: ActivityConfig) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
2016 self.device
2018 .act_ths()
2019 .write(|reg: &mut field_sets::ActThs| {
2020 reg.set_acth(config.threshold.min(127));
2021 })
2022 .map_err(Error::from)?;
2023
2024 self.device
2026 .act_dur()
2027 .write(|reg: &mut field_sets::ActDur| {
2028 reg.set_act_d(config.duration);
2029 })
2030 .map_err(Error::from)?;
2031
2032 Ok(())
2033 }
2034
2035 fn write_interrupt_config(&mut self, config: InterruptConfig) -> Result<(), Error<<IFACE as RegisterInterface>::Error>> {
2036 self.device
2038 .ctrl_reg_3()
2039 .write(|reg: &mut field_sets::CtrlReg3| {
2040 reg.set_i_1_click(config.int1.click);
2041 reg.set_i_1_ia_1(config.int1.ia1);
2042 reg.set_i_1_ia_2(config.int1.ia2);
2043 reg.set_i_1_zyxda(config.int1.data_ready);
2044 reg.set_i_1_wtm(config.int1.fifo_watermark);
2045 reg.set_i_1_overrun(config.int1.fifo_overrun);
2046 })
2047 .map_err(Error::from)?;
2048
2049 self.device
2051 .ctrl_reg_6()
2052 .write(|reg: &mut field_sets::CtrlReg6| {
2053 reg.set_i_2_click(config.int2.click);
2054 reg.set_i_2_ia_1(config.int2.ia1);
2055 reg.set_i_2_ia_2(config.int2.ia2);
2056 reg.set_i_2_boot(config.int2.boot);
2057 reg.set_i_2_act(config.int2.activity);
2058 reg.set_int_polarity(matches!(config.polarity, InterruptPolarity::ActiveLow));
2059 })
2060 .map_err(Error::from)?;
2061
2062 Ok(())
2063 }
2064}
2065
2066impl<I2C> Lis2de12<DeviceInterface<I2C>>
2068where
2069 I2C: I2c,
2070 I2C::Error: Debug,
2071{
2072 pub fn new_i2c(i2c: I2C, addr: SlaveAddr) -> Result<Self, Error<I2C::Error>> {
2074 Self::new_i2c_with_config(i2c, addr, Lis2de12Config::default())
2075 }
2076
2077 pub fn new_i2c_with_config(i2c: I2C, addr: SlaveAddr, config: Lis2de12Config) -> Result<Self, Error<I2C::Error>> {
2079 validate_config_common::<I2C::Error>(&config)?;
2080
2081 let interface = DeviceInterface {
2082 i2c,
2083 address: addr.addr(),
2084 };
2085 let mut device = Lis2de12Device::new(interface);
2086 verify_device_id(&mut device)?;
2087 let mut this = Self { device, config };
2088 this.apply_config(config)?;
2089 Ok(this)
2090 }
2091
2092 pub fn new(i2c: I2C, addr: SlaveAddr) -> Result<Self, Error<I2C::Error>> {
2094 Self::new_i2c(i2c, addr)
2095 }
2096
2097 pub fn new_with_config(i2c: I2C, addr: SlaveAddr, config: Lis2de12Config) -> Result<Self, Error<I2C::Error>> {
2099 Self::new_i2c_with_config(i2c, addr, config)
2100 }
2101
2102 pub fn device(&mut self) -> &mut Lis2de12Device<DeviceInterface<I2C>> {
2104 &mut self.device
2105 }
2106
2107 pub fn destroy(self) -> I2C {
2109 self.device.interface.i2c
2110 }
2111}
2112
2113impl<SPI> Lis2de12<SpiInterface<SPI>>
2115where
2116 SPI: hal::spi::SpiDevice,
2117 SPI::Error: Debug,
2118{
2119 pub fn new_spi(spi: SPI) -> Result<Self, Error<SPI::Error>> {
2121 Self::new_spi_with_config(spi, Lis2de12Config::default())
2122 }
2123
2124 pub fn new_spi_with_config(spi: SPI, config: Lis2de12Config) -> Result<Self, Error<SPI::Error>> {
2126 validate_config_common::<SPI::Error>(&config)?;
2127
2128 let interface = SpiInterface { spi };
2129 let mut device = Lis2de12Device::new(interface);
2130 verify_device_id(&mut device)?;
2131 let mut this = Self { device, config };
2132 this.apply_config(config)?;
2133 Ok(this)
2134 }
2135
2136 pub fn device(&mut self) -> &mut Lis2de12Device<SpiInterface<SPI>> {
2138 &mut self.device
2139 }
2140
2141 pub fn destroy(self) -> SPI {
2143 self.device.interface.spi
2144 }
2145}
2146
2147impl<IFACE> RawAccelerometer<I16x3> for Lis2de12<IFACE>
2148where
2149 IFACE: RegisterInterface<AddressType = u8, Error = <IFACE as BufferInterfaceError>::Error> + BufferInterface<AddressType = u8>,
2150 <IFACE as RegisterInterface>::Error: Debug,
2151{
2152 type Error = <IFACE as RegisterInterface>::Error;
2153
2154 fn accel_raw(&mut self) -> Result<I16x3, Error<Self::Error>> {
2155 self.read_raw()
2156 }
2157}
2158
2159#[cfg(feature = "async")]
2161pub struct Lis2de12Async<IFACE> {
2162 device: Lis2de12Device<IFACE>,
2163 config: Lis2de12Config,
2164}
2165
2166#[cfg(feature = "async")]
2168pub type Lis2de12I2cAsync<I2C> = Lis2de12Async<DeviceInterfaceAsync<I2C>>;
2169
2170#[cfg(feature = "async")]
2172pub type Lis2de12SpiAsync<SPI> = Lis2de12Async<SpiInterfaceAsync<SPI>>;
2173
2174#[cfg(feature = "async")]
2175impl<IFACE> Lis2de12Async<IFACE>
2177where
2178 IFACE: AsyncRegisterInterface<AddressType = u8, Error = <IFACE as BufferInterfaceError>::Error> + AsyncBufferInterface<AddressType = u8>,
2179 <IFACE as AsyncRegisterInterface>::Error: Debug,
2180{
2181 pub const fn config(&self) -> Lis2de12Config {
2183 self.config
2184 }
2185
2186 pub async fn set_config(&mut self, config: Lis2de12Config) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2188 validate_config_common::<<IFACE as AsyncRegisterInterface>::Error>(&config)?;
2189 self.apply_config(config).await?;
2190 self.config = config;
2191 Ok(())
2192 }
2193
2194 pub async fn read_raw(&mut self) -> Result<I16x3, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2196 let frame = self.read_fifo_frame().await?;
2197 Ok(decode_raw(&frame, self.config.mode))
2198 }
2199
2200 pub async fn read_mg(&mut self) -> Result<I16x3, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2202 let raw = self.read_raw().await?;
2203 Ok(scale_to_mg(raw, self.config.sensitivity_mg_per_lsb()))
2204 }
2205
2206 pub async fn read_g(&mut self) -> Result<F32x3, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2208 let raw = self.read_raw().await?;
2209 Ok(scale_to_g(raw, self.config.sensitivity_g_per_lsb()))
2210 }
2211
2212 pub async fn read_fifo_frame(&mut self) -> Result<FifoFrame, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2214 let mut buf: FifoFrame = [0; FIFO_FRAME_BYTES];
2215 let mut fifo = self.device.fifo_read_start();
2216 let mut offset = 0;
2217 while offset < buf.len() {
2218 let read = fifo.read_async(&mut buf[offset..]).await.map_err(Error::from)?;
2219 if read == 0 {
2220 return Err(Error::new(ErrorKind::Device));
2221 }
2222 offset += read;
2223 }
2224 Ok(buf)
2225 }
2226
2227 pub async fn read_fifo_frames(&mut self, frames: &mut [FifoFrame]) -> Result<usize, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2229 if frames.is_empty() {
2230 return Ok(0);
2231 }
2232
2233 let status = self.fifo_status().await?;
2234 if status.is_empty() {
2235 return Ok(0);
2236 }
2237
2238 let to_read = cmp::min(status.len() as usize, frames.len());
2239 for slot in &mut frames[..to_read] {
2240 *slot = self.read_fifo_frame().await?;
2241 }
2242 Ok(to_read)
2243 }
2244
2245 pub async fn drain_fifo(&mut self) -> Result<usize, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2247 let mut drained = 0;
2248 loop {
2249 let status = self.fifo_status().await?;
2250 if status.is_empty() {
2251 break;
2252 }
2253 self.read_fifo_frame().await?;
2254 drained += 1;
2255 }
2256 Ok(drained)
2257 }
2258
2259 pub async fn fifo_status(&mut self) -> Result<FifoStatus, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2261 let status = self.device.fifo_src_reg().read_async().await.map_err(Error::from)?;
2262 Ok(FifoStatus::from(status))
2263 }
2264
2265 pub async fn set_temperature_sensor(&mut self, enable: bool) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2267 self.write_temperature_sensor(enable).await?;
2268 self.config.temperature_enable = enable;
2269 Ok(())
2270 }
2271
2272 pub async fn read_temperature_raw(&mut self) -> Result<i16, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2276 let low = self.device.out_temp_l().read_async().await.map_err(Error::from)?.temp_l() as u8;
2277 let high = self.device.out_temp_h().read_async().await.map_err(Error::from)?.temp_h() as u8;
2278 Ok(i16::from_le_bytes([low, high]))
2279 }
2280
2281 pub async fn read_temperature(&mut self) -> Result<f32, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2307 let raw = self.read_temperature_raw().await?;
2308 Ok((raw >> 8) as f32)
2312 }
2313
2314 pub async fn set_high_pass_to_outputs(&mut self, enable: bool) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2316 self.device
2317 .ctrl_reg_2()
2318 .modify_async(|reg: &mut field_sets::CtrlReg2| reg.set_fds(enable))
2319 .await
2320 .map_err(Error::from)
2321 }
2322
2323 pub async fn high_pass_to_outputs(&mut self) -> Result<bool, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2325 Ok(self.device.ctrl_reg_2().read_async().await.map_err(Error::from)?.fds())
2326 }
2327
2328 pub async fn set_sdo_pullup_connected(&mut self, connected: bool) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2330 self.device
2331 .ctrl_reg_0()
2332 .modify_async(|reg: &mut field_sets::CtrlReg0| reg.set_sdo_pu_disc(!connected))
2333 .await
2334 .map_err(Error::from)
2335 }
2336
2337 pub async fn sdo_pullup_connected(&mut self) -> Result<bool, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2339 Ok(!self.device.ctrl_reg_0().read_async().await.map_err(Error::from)?.sdo_pu_disc())
2340 }
2341
2342 pub async fn reboot(&mut self) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2344 self.device
2345 .ctrl_reg_5()
2346 .write_async(|reg: &mut field_sets::CtrlReg5| reg.set_boot(true))
2347 .await
2348 .map_err(Error::from)
2349 }
2350
2351 pub async fn set_motion1_config(&mut self, config: MotionConfig) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2357 self.write_motion_config_int1(config).await
2358 }
2359
2360 pub async fn set_motion2_config(&mut self, config: MotionConfig) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2362 self.write_motion_config_int2(config).await
2363 }
2364
2365 pub async fn motion1_status(&mut self) -> Result<MotionStatus, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2367 let raw = self.device.int_1_src().read_async().await.map_err(Error::from)?;
2368 Ok(MotionStatus::from(raw))
2369 }
2370
2371 pub async fn motion2_status(&mut self) -> Result<MotionStatus, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2373 let raw = self.device.int_2_src().read_async().await.map_err(Error::from)?;
2374 Ok(MotionStatus::from(raw))
2375 }
2376
2377 pub async fn set_click_config(&mut self, config: ClickConfig) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2383 self.write_click_config(config).await
2384 }
2385
2386 pub async fn click_status(&mut self) -> Result<ClickStatus, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2388 let raw = self.device.click_src().read_async().await.map_err(Error::from)?;
2389 Ok(ClickStatus::from(raw))
2390 }
2391
2392 pub async fn set_activity_config(&mut self, config: ActivityConfig) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2398 self.write_activity_config(config).await
2399 }
2400
2401 pub async fn set_interrupt_config(&mut self, config: InterruptConfig) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2407 self.write_interrupt_config(config).await
2408 }
2409
2410 pub async fn set_interrupt_polarity(&mut self, polarity: InterruptPolarity) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2412 self.device
2413 .ctrl_reg_6()
2414 .modify_async(|reg: &mut field_sets::CtrlReg6| {
2415 reg.set_int_polarity(matches!(polarity, InterruptPolarity::ActiveLow));
2416 })
2417 .await
2418 .map_err(Error::from)
2419 }
2420
2421 pub async fn interrupt_sources(&mut self) -> Result<InterruptSources, Error<<IFACE as AsyncRegisterInterface>::Error>> {
2426 let motion1 = self.motion1_status().await?;
2427 let motion2 = self.motion2_status().await?;
2428 let click = self.click_status().await?;
2429 Ok(InterruptSources { motion1, motion2, click })
2430 }
2431
2432 async fn write_temperature_sensor(&mut self, enable: bool) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2433 self.device
2434 .temp_cfg_reg()
2435 .write_async(|reg: &mut field_sets::TempCfgReg| {
2436 reg.set_temp_en(if enable { TempEn::TempEn } else { TempEn::TempDis });
2437 })
2438 .await
2439 .map_err(Error::from)
2440 }
2441
2442 async fn apply_config(&mut self, config: Lis2de12Config) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2443 self.device
2444 .ctrl_reg_1()
2445 .write_async(|reg: &mut field_sets::CtrlReg1| {
2446 reg.set_odr(config.odr);
2447 reg.set_lpen(config.mode.lpen());
2448 reg.set_xen(config.axes.x);
2449 reg.set_yen(config.axes.y);
2450 reg.set_zen(config.axes.z);
2451 })
2452 .await
2453 .map_err(Error::from)?;
2454
2455 self.device
2456 .ctrl_reg_4()
2457 .write_async(|reg: &mut field_sets::CtrlReg4| {
2458 reg.set_bdu(config.block_data_update);
2459 reg.set_fs(config.scale);
2460 reg.set_st(St::Normal);
2461 reg.set_sim(false);
2462 })
2463 .await
2464 .map_err(Error::from)?;
2465
2466 self.device
2467 .ctrl_reg_5()
2468 .write_async(|reg: &mut field_sets::CtrlReg5| {
2469 reg.set_fifo_en(config.fifo.enable);
2470 })
2471 .await
2472 .map_err(Error::from)?;
2473
2474 self.device
2475 .fifo_ctrl_reg()
2476 .write_async(|reg: &mut field_sets::FifoCtrlReg| {
2477 reg.set_fm(config.fifo.mode.into());
2478 reg.set_tr(false);
2479 reg.set_fth(config.fifo.effective_threshold());
2480 })
2481 .await
2482 .map_err(Error::from)?;
2483
2484 self.write_temperature_sensor(config.temperature_enable).await?;
2485 Ok(())
2486 }
2487
2488 async fn write_motion_config_int1(&mut self, config: MotionConfig) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2489 let (aoi, sixd, d4d) = mode_bits(config.mode);
2490
2491 self.device
2492 .int_1_cfg()
2493 .write_async(|reg: &mut field_sets::Int1Cfg| {
2494 reg.set_aoi(aoi);
2495 reg.set_sixd(sixd);
2496 reg.set_xhie(config.axes.x_high && config.enable);
2497 reg.set_xlie(config.axes.x_low && config.enable);
2498 reg.set_yhie(config.axes.y_high && config.enable);
2499 reg.set_ylie(config.axes.y_low && config.enable);
2500 reg.set_zhie(config.axes.z_high && config.enable);
2501 reg.set_zlie(config.axes.z_low && config.enable);
2502 })
2503 .await
2504 .map_err(Error::from)?;
2505
2506 self.device
2507 .int_1_ths()
2508 .write_async(|reg: &mut field_sets::Int1Ths| {
2509 reg.set_ths(config.threshold.min(127));
2510 })
2511 .await
2512 .map_err(Error::from)?;
2513
2514 self.device
2515 .int_1_duration()
2516 .write_async(|reg: &mut field_sets::Int1Duration| {
2517 reg.set_d(config.duration.min(127));
2518 })
2519 .await
2520 .map_err(Error::from)?;
2521
2522 self.device
2523 .ctrl_reg_5()
2524 .modify_async(|reg: &mut field_sets::CtrlReg5| {
2525 reg.set_lir_int_1(matches!(config.latch, LatchMode::Latched));
2526 reg.set_d_4_d_int_1(d4d);
2527 })
2528 .await
2529 .map_err(Error::from)?;
2530
2531 self.device
2532 .ctrl_reg_2()
2533 .modify_async(|reg: &mut field_sets::CtrlReg2| {
2534 reg.set_hp_ia_1(config.high_pass_filter);
2535 })
2536 .await
2537 .map_err(Error::from)?;
2538
2539 Ok(())
2540 }
2541
2542 async fn write_motion_config_int2(&mut self, config: MotionConfig) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2543 let (aoi, sixd, d4d) = mode_bits(config.mode);
2544
2545 self.device
2546 .int_2_cfg()
2547 .write_async(|reg: &mut field_sets::Int2Cfg| {
2548 reg.set_aoi(aoi);
2549 reg.set_sixd(sixd);
2550 reg.set_xhie(config.axes.x_high && config.enable);
2551 reg.set_xlie(config.axes.x_low && config.enable);
2552 reg.set_yhie(config.axes.y_high && config.enable);
2553 reg.set_ylie(config.axes.y_low && config.enable);
2554 reg.set_zhie(config.axes.z_high && config.enable);
2555 reg.set_zlie(config.axes.z_low && config.enable);
2556 })
2557 .await
2558 .map_err(Error::from)?;
2559
2560 self.device
2562 .int_2_ths()
2563 .write_async(|reg: &mut field_sets::Int2Ths| {
2564 reg.set_ths(config.threshold.min(127));
2565 })
2566 .await
2567 .map_err(Error::from)?;
2568
2569 self.device
2571 .int_2_duration()
2572 .write_async(|reg: &mut field_sets::Int2Duration| {
2573 reg.set_d(config.duration.min(127));
2574 })
2575 .await
2576 .map_err(Error::from)?;
2577
2578 self.device
2579 .ctrl_reg_5()
2580 .modify_async(|reg: &mut field_sets::CtrlReg5| {
2581 reg.set_lir_int_2(matches!(config.latch, LatchMode::Latched));
2582 reg.set_d_4_d_int_2(d4d);
2583 })
2584 .await
2585 .map_err(Error::from)?;
2586
2587 self.device
2588 .ctrl_reg_2()
2589 .modify_async(|reg: &mut field_sets::CtrlReg2| {
2590 reg.set_hp_ia_2(config.high_pass_filter);
2591 })
2592 .await
2593 .map_err(Error::from)?;
2594
2595 Ok(())
2596 }
2597
2598 async fn write_click_config(&mut self, config: ClickConfig) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2599 self.device
2601 .click_cfg()
2602 .write_async(|reg: &mut field_sets::ClickCfg| {
2603 reg.set_xs(config.axes.x_single && config.enable);
2604 reg.set_xd(config.axes.x_double && config.enable);
2605 reg.set_ys(config.axes.y_single && config.enable);
2606 reg.set_yd(config.axes.y_double && config.enable);
2607 reg.set_zs(config.axes.z_single && config.enable);
2608 reg.set_zd(config.axes.z_double && config.enable);
2609 })
2610 .await
2611 .map_err(Error::from)?;
2612
2613 self.device
2615 .click_ths()
2616 .write_async(|reg: &mut field_sets::ClickThs| {
2617 reg.set_ths(config.threshold.min(127));
2618 reg.set_lir_click(matches!(config.latch, LatchMode::Latched));
2619 })
2620 .await
2621 .map_err(Error::from)?;
2622
2623 self.device
2625 .time_limit()
2626 .write_async(|reg: &mut field_sets::TimeLimit| {
2627 reg.set_tli(config.time_limit.min(127));
2628 })
2629 .await
2630 .map_err(Error::from)?;
2631
2632 self.device
2634 .time_latency()
2635 .write_async(|reg: &mut field_sets::TimeLatency| {
2636 reg.set_tla(config.time_latency);
2637 })
2638 .await
2639 .map_err(Error::from)?;
2640
2641 self.device
2643 .time_window()
2644 .write_async(|reg: &mut field_sets::TimeWindow| {
2645 reg.set_tw(config.time_window);
2646 })
2647 .await
2648 .map_err(Error::from)?;
2649
2650 self.device
2652 .ctrl_reg_2()
2653 .modify_async(|reg: &mut field_sets::CtrlReg2| {
2654 reg.set_hpclick(config.high_pass_filter);
2655 })
2656 .await
2657 .map_err(Error::from)?;
2658
2659 Ok(())
2660 }
2661
2662 async fn write_activity_config(&mut self, config: ActivityConfig) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2663 self.device
2665 .act_ths()
2666 .write_async(|reg: &mut field_sets::ActThs| {
2667 reg.set_acth(config.threshold.min(127));
2668 })
2669 .await
2670 .map_err(Error::from)?;
2671
2672 self.device
2674 .act_dur()
2675 .write_async(|reg: &mut field_sets::ActDur| {
2676 reg.set_act_d(config.duration);
2677 })
2678 .await
2679 .map_err(Error::from)?;
2680
2681 Ok(())
2682 }
2683
2684 async fn write_interrupt_config(&mut self, config: InterruptConfig) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>> {
2685 self.device
2687 .ctrl_reg_3()
2688 .write_async(|reg: &mut field_sets::CtrlReg3| {
2689 reg.set_i_1_click(config.int1.click);
2690 reg.set_i_1_ia_1(config.int1.ia1);
2691 reg.set_i_1_ia_2(config.int1.ia2);
2692 reg.set_i_1_zyxda(config.int1.data_ready);
2693 reg.set_i_1_wtm(config.int1.fifo_watermark);
2694 reg.set_i_1_overrun(config.int1.fifo_overrun);
2695 })
2696 .await
2697 .map_err(Error::from)?;
2698
2699 self.device
2701 .ctrl_reg_6()
2702 .write_async(|reg: &mut field_sets::CtrlReg6| {
2703 reg.set_i_2_click(config.int2.click);
2704 reg.set_i_2_ia_1(config.int2.ia1);
2705 reg.set_i_2_ia_2(config.int2.ia2);
2706 reg.set_i_2_boot(config.int2.boot);
2707 reg.set_i_2_act(config.int2.activity);
2708 reg.set_int_polarity(matches!(config.polarity, InterruptPolarity::ActiveLow));
2709 })
2710 .await
2711 .map_err(Error::from)?;
2712
2713 Ok(())
2714 }
2715}
2716
2717#[cfg(feature = "async")]
2719impl<I2C> Lis2de12Async<DeviceInterfaceAsync<I2C>>
2720where
2721 I2C: AsyncI2c,
2722 I2C::Error: Debug,
2723{
2724 pub async fn new_i2c(i2c: I2C, addr: SlaveAddr) -> Result<Self, Error<I2C::Error>> {
2726 Self::new_i2c_with_config(i2c, addr, Lis2de12Config::default()).await
2727 }
2728
2729 pub async fn new_i2c_with_config(i2c: I2C, addr: SlaveAddr, config: Lis2de12Config) -> Result<Self, Error<I2C::Error>> {
2731 validate_config_common::<I2C::Error>(&config)?;
2732
2733 let interface = DeviceInterfaceAsync {
2734 i2c,
2735 address: addr.addr(),
2736 };
2737 let mut device = Lis2de12Device::new(interface);
2738 verify_device_id_async(&mut device).await?;
2739 let mut this = Self { device, config };
2740 this.apply_config(config).await?;
2741 Ok(this)
2742 }
2743
2744 pub async fn new(i2c: I2C, addr: SlaveAddr) -> Result<Self, Error<I2C::Error>> {
2746 Self::new_i2c(i2c, addr).await
2747 }
2748
2749 pub async fn new_with_config(i2c: I2C, addr: SlaveAddr, config: Lis2de12Config) -> Result<Self, Error<I2C::Error>> {
2751 Self::new_i2c_with_config(i2c, addr, config).await
2752 }
2753
2754 pub fn device(&mut self) -> &mut Lis2de12Device<DeviceInterfaceAsync<I2C>> {
2756 &mut self.device
2757 }
2758
2759 pub fn destroy(self) -> I2C {
2761 self.device.interface.i2c
2762 }
2763}
2764
2765#[cfg(feature = "async")]
2767impl<SPI> Lis2de12Async<SpiInterfaceAsync<SPI>>
2768where
2769 SPI: AsyncSpiDevice,
2770 SPI::Error: Debug,
2771{
2772 pub async fn new_spi(spi: SPI) -> Result<Self, Error<SPI::Error>> {
2774 Self::new_spi_with_config(spi, Lis2de12Config::default()).await
2775 }
2776
2777 pub async fn new_spi_with_config(spi: SPI, config: Lis2de12Config) -> Result<Self, Error<SPI::Error>> {
2779 validate_config_common::<SPI::Error>(&config)?;
2780
2781 let interface = SpiInterfaceAsync { spi };
2782 let mut device = Lis2de12Device::new(interface);
2783 verify_device_id_async(&mut device).await?;
2784 let mut this = Self { device, config };
2785 this.apply_config(config).await?;
2786 Ok(this)
2787 }
2788
2789 pub fn device(&mut self) -> &mut Lis2de12Device<SpiInterfaceAsync<SPI>> {
2791 &mut self.device
2792 }
2793
2794 pub fn destroy(self) -> SPI {
2796 self.device.interface.spi
2797 }
2798}
2799
2800fn verify_device_id<IFACE>(device: &mut Lis2de12Device<IFACE>) -> Result<(), Error<<IFACE as RegisterInterface>::Error>>
2801where
2802 IFACE: RegisterInterface<AddressType = u8>,
2803 <IFACE as RegisterInterface>::Error: Debug,
2804{
2805 let who = device.who_am_i().read().map_err(Error::from)?;
2806 if who != field_sets::WhoAmI::new() {
2807 return Err(Error::new(ErrorKind::Device));
2808 }
2809 Ok(())
2810}
2811
2812#[cfg(feature = "async")]
2813async fn verify_device_id_async<IFACE>(
2814 device: &mut Lis2de12Device<IFACE>,
2815) -> Result<(), Error<<IFACE as AsyncRegisterInterface>::Error>>
2816where
2817 IFACE: AsyncRegisterInterface<AddressType = u8>,
2818 <IFACE as AsyncRegisterInterface>::Error: Debug,
2819{
2820 let who = device.who_am_i().read_async().await.map_err(Error::from)?;
2821 if who != field_sets::WhoAmI::new() {
2822 return Err(Error::new(ErrorKind::Device));
2823 }
2824 Ok(())
2825}
2826
2827fn decode_raw(bytes: &FifoFrame, _mode: OperatingMode) -> I16x3 {
2828 let x = i16::from_le_bytes([bytes[0], bytes[1]]);
2832 let y = i16::from_le_bytes([bytes[2], bytes[3]]);
2833 let z = i16::from_le_bytes([bytes[4], bytes[5]]);
2834 I16x3::new(x >> 8, y >> 8, z >> 8)
2835}
2836
2837fn scale_to_mg(raw: I16x3, mg_per_lsb: f32) -> I16x3 {
2838 fn round_to_i16(value: f32) -> i16 {
2839 if value >= 0.0 {
2840 (value + 0.5) as i16
2841 } else {
2842 (value - 0.5) as i16
2843 }
2844 }
2845
2846 I16x3::new(
2847 round_to_i16(raw.x as f32 * mg_per_lsb),
2848 round_to_i16(raw.y as f32 * mg_per_lsb),
2849 round_to_i16(raw.z as f32 * mg_per_lsb),
2850 )
2851}
2852
2853fn scale_to_g(raw: I16x3, g_per_lsb: f32) -> F32x3 {
2854 F32x3::new(
2855 raw.x as f32 * g_per_lsb,
2856 raw.y as f32 * g_per_lsb,
2857 raw.z as f32 * g_per_lsb,
2858 )
2859}
2860
2861#[cfg(test)]
2862mod tests {
2863 use core::f32::EPSILON;
2864
2865 use super::*;
2866
2867 #[test]
2868 fn validate_config_requires_enabled_axis() {
2869 let mut config = Lis2de12Config::default();
2870 config.axes = AxesEnable {
2871 x: false,
2872 y: false,
2873 z: false,
2874 };
2875
2876 let err = validate_config_common::<()>(&config).unwrap_err();
2877 assert_eq!(err.kind(), ErrorKind::Device);
2878 }
2879
2880 #[test]
2881 fn validate_config_enforces_watermark_limit() {
2882 let mut config = Lis2de12Config::default();
2883 config.fifo = FifoConfig::enabled(FifoMode::Fifo).with_watermark(FIFO_WATERMARK_MAX + 1);
2884
2885 let err = validate_config_common::<()>(&config).unwrap_err();
2886 assert_eq!(err.kind(), ErrorKind::Param);
2887 }
2888
2889 #[test]
2890 fn validate_config_accepts_valid_fifo_settings() {
2891 let mut config = Lis2de12Config::default();
2892 config.fifo = FifoConfig::enabled(FifoMode::Stream).with_watermark(FIFO_WATERMARK_MAX);
2893
2894 assert!(validate_config_common::<()>(&config).is_ok());
2895 }
2896
2897 #[test]
2898 fn fifo_status_parses_flags_and_length() {
2899 let mut raw = field_sets::FifoSrcReg::new();
2900 raw.set_wtm(true);
2901 raw.set_ovrn_fifo(false);
2902 raw.set_empty(false);
2903 raw.set_fss(5);
2904
2905 let status = FifoStatus::from_raw(raw);
2906 assert!(status.is_watermark_triggered());
2907 assert!(!status.is_overrun());
2908 assert!(!status.is_empty());
2909 assert_eq!(status.len(), 5);
2910 assert_eq!(status.remaining_capacity(), (FIFO_CAPACITY as u8).saturating_sub(5));
2911 }
2912
2913 #[test]
2914 fn fifo_status_reports_full_when_overrun() {
2915 let mut raw = field_sets::FifoSrcReg::new();
2916 raw.set_wtm(true);
2917 raw.set_ovrn_fifo(true);
2918 raw.set_empty(false);
2919 raw.set_fss(0);
2920
2921 let status = FifoStatus::from_raw(raw);
2922 assert!(status.is_overrun());
2923 assert_eq!(status.len(), FIFO_CAPACITY as u8);
2924 }
2925
2926 #[test]
2927 fn decode_raw_extracts_h_byte_with_sign_extension() {
2928 let frame: FifoFrame = [0x00, 0x01, 0x00, 0x02, 0x00, 0x03];
2931 let decoded = decode_raw(&frame, OperatingMode::LowPower);
2932 assert_eq!(decoded.x, 1);
2933 assert_eq!(decoded.y, 2);
2934 assert_eq!(decoded.z, 3);
2935
2936 let frame_neg: FifoFrame = [0x00, 0xFF, 0x00, 0xFE, 0x00, 0x80];
2938 let decoded_neg = decode_raw(&frame_neg, OperatingMode::LowPower);
2939 assert_eq!(decoded_neg.x, -1);
2940 assert_eq!(decoded_neg.y, -2);
2941 assert_eq!(decoded_neg.z, -128);
2942 }
2943
2944 #[test]
2945 fn scale_to_mg_rounds_toward_nearest() {
2946 let raw = I16x3::new(1, -1, 2);
2947 let scaled = scale_to_mg(raw, 1.5);
2948
2949 assert_eq!(scaled.x, 2);
2950 assert_eq!(scaled.y, -2);
2951 assert_eq!(scaled.z, 3);
2952 }
2953
2954 #[test]
2955 fn scale_to_g_scales_components() {
2956 let raw = I16x3::new(2, -4, 0);
2957 let scaled = scale_to_g(raw, 0.5);
2958
2959 assert!((scaled.x - 1.0).abs() <= EPSILON);
2960 assert!((scaled.y + 2.0).abs() <= EPSILON);
2961 assert!(scaled.z.abs() <= EPSILON);
2962 }
2963
2964 #[test]
2965 fn fifo_config_effective_threshold_zero_when_disabled() {
2966 let config = FifoConfig {
2967 enable: false,
2968 mode: FifoMode::Bypass,
2969 watermark: Some(12),
2970 };
2971
2972 assert_eq!(config.effective_threshold(), 0);
2973 }
2974
2975 #[test]
2976 fn fifo_config_effective_threshold_clamps_to_max() {
2977 let config = FifoConfig {
2978 enable: true,
2979 mode: FifoMode::Stream,
2980 watermark: Some(40),
2981 };
2982
2983 assert_eq!(config.effective_threshold(), FIFO_WATERMARK_MAX);
2984 }
2985
2986 #[test]
2987 fn fifo_status_reports_empty_flag() {
2988 let mut raw = field_sets::FifoSrcReg::new();
2989 raw.set_wtm(false);
2990 raw.set_ovrn_fifo(false);
2991 raw.set_empty(true);
2992 raw.set_fss(7);
2993
2994 let status = FifoStatus::from_raw(raw);
2995 assert!(status.is_empty());
2996 assert_eq!(status.len(), 0);
2997 assert_eq!(status.remaining_capacity(), FIFO_CAPACITY as u8);
2998 }
2999
3000 #[test]
3005 fn motion_axes_config_all_high_enables_only_high() {
3006 let axes = MotionAxesConfig::all_high();
3007 assert!(axes.x_high);
3008 assert!(!axes.x_low);
3009 assert!(axes.y_high);
3010 assert!(!axes.y_low);
3011 assert!(axes.z_high);
3012 assert!(!axes.z_low);
3013 assert!(axes.any());
3014 }
3015
3016 #[test]
3017 fn motion_axes_config_none_disables_all() {
3018 let axes = MotionAxesConfig::none();
3019 assert!(!axes.x_high);
3020 assert!(!axes.x_low);
3021 assert!(!axes.y_high);
3022 assert!(!axes.y_low);
3023 assert!(!axes.z_high);
3024 assert!(!axes.z_low);
3025 assert!(!axes.any());
3026 }
3027
3028 #[test]
3029 fn motion_config_builder_methods() {
3030 let config = MotionConfig::disabled()
3031 .with_enable(true)
3032 .with_threshold(200) .with_duration(64)
3034 .with_latch(LatchMode::Latched)
3035 .with_mode(MotionDetectionMode::AndCombination)
3036 .with_axes(MotionAxesConfig::all_high())
3037 .with_high_pass_filter(true);
3038
3039 assert!(config.enable);
3040 assert_eq!(config.threshold, 127); assert_eq!(config.duration, 64);
3042 assert!(matches!(config.latch, LatchMode::Latched));
3043 assert!(matches!(config.mode, MotionDetectionMode::AndCombination));
3044 assert!(config.axes.x_high);
3045 assert!(config.high_pass_filter);
3046 }
3047
3048 #[test]
3049 fn click_axes_config_all_single_enables_only_single() {
3050 let axes = ClickAxesConfig::all_single();
3051 assert!(axes.x_single);
3052 assert!(!axes.x_double);
3053 assert!(axes.y_single);
3054 assert!(!axes.y_double);
3055 assert!(axes.z_single);
3056 assert!(!axes.z_double);
3057 assert!(axes.any());
3058 }
3059
3060 #[test]
3061 fn click_config_builder_methods() {
3062 let config = ClickConfig::disabled()
3063 .with_enable(true)
3064 .with_threshold(50)
3065 .with_time_limit(10)
3066 .with_time_latency(20)
3067 .with_time_window(100)
3068 .with_latch(LatchMode::Latched)
3069 .with_axes(ClickAxesConfig::all_double());
3070
3071 assert!(config.enable);
3072 assert_eq!(config.threshold, 50);
3073 assert_eq!(config.time_limit, 10);
3074 assert_eq!(config.time_latency, 20);
3075 assert_eq!(config.time_window, 100);
3076 assert!(matches!(config.latch, LatchMode::Latched));
3077 assert!(config.axes.x_double);
3078 }
3079
3080 #[test]
3081 fn activity_config_threshold_clamps() {
3082 let config = ActivityConfig::disabled()
3083 .with_threshold(255); assert_eq!(config.threshold, 127);
3086 }
3087
3088 #[test]
3089 fn int1_routing_none_disables_all() {
3090 let routing = Int1Routing::none();
3091 assert!(!routing.click);
3092 assert!(!routing.ia1);
3093 assert!(!routing.ia2);
3094 assert!(!routing.data_ready);
3095 assert!(!routing.fifo_watermark);
3096 assert!(!routing.fifo_overrun);
3097 assert!(!routing.any());
3098 }
3099
3100 #[test]
3101 fn int2_routing_any_detects_enabled() {
3102 let mut routing = Int2Routing::none();
3103 assert!(!routing.any());
3104 routing.activity = true;
3105 assert!(routing.any());
3106 }
3107
3108 #[test]
3109 fn motion_status_event_detection() {
3110 let status = MotionStatus {
3111 active: true,
3112 x_high: true,
3113 x_low: false,
3114 y_high: false,
3115 y_low: true,
3116 z_high: false,
3117 z_low: false,
3118 };
3119
3120 assert!(status.is_active());
3121 assert!(status.x_event());
3122 assert!(status.y_event());
3123 assert!(!status.z_event());
3124 assert!(status.any_event());
3125 }
3126
3127 #[test]
3128 fn click_status_detection() {
3129 let status = ClickStatus {
3130 active: true,
3131 double_click: false,
3132 single_click: true,
3133 negative: true,
3134 x: false,
3135 y: false,
3136 z: true,
3137 };
3138
3139 assert!(status.is_active());
3140 assert!(!status.is_double_click());
3141 assert!(status.is_single_click());
3142 assert!(status.is_negative());
3143 assert!(status.any_event());
3144 }
3145
3146 #[test]
3147 fn interrupt_sources_any_active() {
3148 let sources = InterruptSources {
3149 motion1: MotionStatus { active: false, ..Default::default() },
3150 motion2: MotionStatus { active: true, ..Default::default() },
3151 click: ClickStatus::default(),
3152 };
3153
3154 assert!(sources.any_active());
3155 }
3156
3157 #[test]
3158 fn interrupt_config_builder() {
3159 let config = InterruptConfig::disabled()
3160 .with_polarity(InterruptPolarity::ActiveLow)
3161 .with_int1(Int1Routing { ia1: true, ..Default::default() })
3162 .with_int2(Int2Routing { activity: true, ..Default::default() });
3163
3164 assert!(matches!(config.polarity, InterruptPolarity::ActiveLow));
3165 assert!(config.int1.ia1);
3166 assert!(config.int2.activity);
3167 }
3168}