lis2dh12/
lib.rs

1//! Platform-agnostic LIS2DH12 accelerometer driver which uses I2C via
2//! [embedded-hal] and implements the [`Accelerometer` trait][trait]
3//! from the `accelerometer` crate.
4//!
5//! [embedded-hal]: https://docs.rs/embedded-hal
6//! [trait]: https://docs.rs/accelerometer/latest/accelerometer/trait.Accelerometer.html
7//!
8
9#![deny(missing_docs)]
10#![deny(warnings)]
11#![no_std]
12#![forbid(unsafe_code)]
13
14mod reg;
15
16use core::fmt::Debug;
17use core::marker::PhantomData;
18
19#[cfg(feature = "out_f32")]
20pub use accelerometer::vector::F32x3;
21pub use accelerometer::vector::I16x3;
22pub use accelerometer::{Accelerometer, Error, ErrorKind, RawAccelerometer};
23use cast::u16;
24#[cfg(feature = "out_f32")]
25use cast::{f32, i16};
26use embedded_hal as hal;
27use hal::i2c::I2c;
28#[cfg(feature = "out_f32")]
29use num_traits::FromPrimitive;
30
31use crate::reg::*;
32pub use crate::reg::{Aoi6d, FifoMode, FullScale, Mode, Odr};
33
34/// Possible slave addresses
35pub enum SlaveAddr {
36    /// Default slave address
37    Default,
38    /// Alternative slave address providing bit value for `A0`
39    Alternative(bool),
40}
41
42impl SlaveAddr {
43    fn addr(self) -> u8 {
44        match self {
45            SlaveAddr::Default => I2C_SAD,
46            SlaveAddr::Alternative(a0) => I2C_SAD | a0 as u8,
47        }
48    }
49}
50
51/// Data status structure,
52/// decoded from STATUS_REG register
53#[derive(Debug)]
54pub struct DataStatus {
55    /// ZYXOR bit
56    pub zyxor: bool,
57    /// (XOR, YOR, ZOR) bits
58    pub xyzor: (bool, bool, bool),
59    /// ZYXDA bit
60    pub zyxda: bool,
61    /// (XDA, YDA, ZDA) bits
62    pub xyzda: (bool, bool, bool),
63}
64
65/// `LIS2DH12` driver
66pub struct Lis2dh12<I2C> {
67    /// The concrete I²C device implementation
68    i2c: I2C,
69    /// The I²C device slave address
70    addr: u8,
71    /// Current full-scale
72    #[cfg(feature = "out_f32")]
73    fs: FullScale,
74}
75
76/// Errors returned from the [detect_i2c_addr]
77#[derive(Debug)]
78pub enum AddrDetectionError<I2cError: Debug> {
79    /// Other I2C error trying to detect a device address.
80    I2c(I2cError),
81    /// Invalid device ID read from device.
82    InvalidDeviceId,
83}
84
85impl<I2cError: Debug> From<I2cError> for AddrDetectionError<I2cError> {
86    fn from(value: I2cError) -> Self {
87        AddrDetectionError::I2c(value)
88    }
89}
90
91/// This function tries to detect the I2C address of the device by scanning all possible I2C
92/// addresses.
93pub fn detect_i2c_addr<I2C: I2c>(
94    i2c: &mut I2C,
95) -> Result<SlaveAddr, AddrDetectionError<I2C::Error>> {
96    let mut buf = [0u8];
97    let write_buf = &[reg::Register::WHO_AM_I.addr()];
98    match i2c.write_read(reg::I2C_SAD | 0b1, write_buf, &mut buf) {
99        Ok(_) => {
100            if buf[0] == reg::DEVICE_ID {
101                return Ok(SlaveAddr::Alternative(true));
102            }
103            Err(AddrDetectionError::InvalidDeviceId)
104        }
105        Err(_) => {
106            let result = i2c.write_read(reg::I2C_SAD, write_buf, &mut buf);
107            if result.is_ok() {
108                if buf[0] == reg::DEVICE_ID {
109                    return Ok(SlaveAddr::Default);
110                } else {
111                    return Err(AddrDetectionError::InvalidDeviceId);
112                }
113            }
114            Err(result.unwrap_err().into())
115        }
116    }
117}
118
119/// Interrupt setting and status
120pub struct Int<'a, REG, I2C> {
121    dev: &'a mut Lis2dh12<I2C>,
122    reg: PhantomData<REG>,
123}
124
125impl<I2C: I2c> Lis2dh12<I2C> {
126    /// Create a new `LIS2DH12` driver from the given `I2C` peripheral
127    pub fn new(i2c: I2C, addr: SlaveAddr) -> Result<Self, Error<I2C::Error>> {
128        let mut dev = Self {
129            i2c,
130            addr: addr.addr(),
131            #[cfg(feature = "out_f32")]
132            fs: FullScale::G2,
133        };
134
135        // Ensure we have the correct device ID
136        if dev.get_device_id()? != DEVICE_ID {
137            ErrorKind::Device.err()?;
138        }
139
140        Ok(dev)
141    }
142
143    /// Destroy driver instance, return `I2C` bus instance
144    pub fn destroy(self) -> I2C {
145        self.i2c
146    }
147
148    /// `WHO_AM_I` register
149    pub fn get_device_id(&mut self) -> Result<u8, Error<I2C::Error>> {
150        self.read_reg(Register::WHO_AM_I).map_err(Into::into)
151    }
152
153    /// Operating mode selection,
154    /// `CTRL_REG1`: `LPen` bit,
155    /// `CTRL_REG4`: `HR` bit
156    pub fn set_mode(&mut self, mode: Mode) -> Result<(), Error<I2C::Error>> {
157        match mode {
158            Mode::LowPower => {
159                self.reg_reset_bits(Register::CTRL_REG4, HR)?;
160                self.reg_set_bits(Register::CTRL_REG1, LPen)?;
161            }
162            Mode::Normal => {
163                self.reg_reset_bits(Register::CTRL_REG1, LPen)?;
164                self.reg_reset_bits(Register::CTRL_REG4, HR)?;
165            }
166            Mode::HighResolution => {
167                self.reg_reset_bits(Register::CTRL_REG1, LPen)?;
168                self.reg_set_bits(Register::CTRL_REG4, HR)?;
169            }
170        }
171        Ok(())
172    }
173
174    /// Data rate selection,
175    /// `CTRL_REG1`: `ODR`
176    pub fn set_odr(&mut self, odr: Odr) -> Result<(), Error<I2C::Error>> {
177        self.modify_reg(Register::CTRL_REG1, |v| {
178            (v & !ODR_MASK) | ((odr as u8) << 4)
179        })?;
180        // By design, when the device from high-resolution configuration (HR) is set to power-down mode (PD),
181        // it is recommended to read register REFERENCE (26h) for a complete reset of the filtering block
182        // before switching to normal/high-performance mode again.
183        if let Odr::PowerDown = odr {
184            self.get_ref()?;
185        }
186        Ok(())
187    }
188
189    /// X,Y,Z-axis enable,
190    /// `CTRL_REG1`: `Xen`, `Yen`, `Zen`
191    pub fn enable_axis(&mut self, (x, y, z): (bool, bool, bool)) -> Result<(), Error<I2C::Error>> {
192        self.modify_reg(Register::CTRL_REG1, |mut v| {
193            v &= !(Xen | Yen | Zen); // disable all axises
194            v |= if x { Xen } else { 0 };
195            v |= if y { Yen } else { 0 };
196            v |= if z { Zen } else { 0 };
197            v
198        })?;
199        Ok(())
200    }
201
202    /// Enable high-pass filter for CLICK/IA2/IA1
203    pub fn enable_hp_filter(
204        &mut self,
205        click: bool,
206        ia2: bool,
207        ia1: bool,
208    ) -> Result<(), Error<I2C::Error>> {
209        self.modify_reg(Register::CTRL_REG2, |mut v| {
210            v &= !(HPCLICK | HP_IA2 | HP_IA1); // disable all filters
211            v |= if click { HPCLICK } else { 0 };
212            v |= if ia2 { HP_IA2 } else { 0 };
213            v |= if ia1 { HP_IA1 } else { 0 };
214            v
215        })?;
216        Ok(())
217    }
218
219    /// `CLICK` interrupt on `INT1` pin,
220    /// `CTRL_REG3`: `I1_CLICK`
221    pub fn enable_i1_click(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
222        self.reg_xset_bits(Register::CTRL_REG3, I1_CLICK, enable)?;
223        Ok(())
224    }
225
226    /// `IA1` interrupt on `INT1` pin,
227    /// `CTRL_REG3`: `I1_IA1`
228    pub fn enable_i1_ia1(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
229        self.reg_xset_bits(Register::CTRL_REG3, I1_IA1, enable)?;
230        Ok(())
231    }
232
233    /// `IA2` interrupt on `INT1` pin,
234    /// `CTRL_REG3`: `I1_IA2`
235    pub fn enable_i1_ia2(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
236        self.reg_xset_bits(Register::CTRL_REG3, I1_IA2, enable)?;
237        Ok(())
238    }
239
240    /// `ZYXDA` interrupt on `INT1` pin,
241    /// `CTRL_REG3`: `I2_ZYXDA`
242    pub fn enable_i1_zyxda(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
243        self.reg_xset_bits(Register::CTRL_REG3, I1_ZYXDA, enable)?;
244        Ok(())
245    }
246
247    /// FIFO watermark on `INT1` pin,
248    /// `CTRL_REG3`: `I2_ZYXDA`
249    pub fn enable_i1_wtm(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
250        self.reg_xset_bits(Register::CTRL_REG3, I1_WTM, enable)?;
251        Ok(())
252    }
253
254    /// Get the amount of samples currently stored in the FIFO queue
255    pub fn get_stored_samples(&mut self) -> Result<u8, Error<I2C::Error>> {
256        let value = self.read_reg(Register::FIFO_SRC_REG)?;
257        Ok(value & FSS)
258    }
259
260    /// FIFO overrun on `INT1` pin,
261    /// `CTRL_REG3`: `I1_OVERRUN`
262    pub fn enable_i1_overrun(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
263        self.reg_xset_bits(Register::CTRL_REG3, I1_OVERRUN, enable)?;
264        Ok(())
265    }
266
267    /// Block data update,
268    /// `CTRL_REG4`: `BDU`
269    pub fn set_bdu(&mut self, bdu: bool) -> Result<(), Error<I2C::Error>> {
270        self.reg_xset_bits(Register::CTRL_REG4, BDU, bdu)?;
271        Ok(())
272    }
273
274    /// Full-scale selection,
275    /// `CTRL_REG4`: `FS`
276    pub fn set_fs(&mut self, fs: FullScale) -> Result<(), Error<I2C::Error>> {
277        self.modify_reg(Register::CTRL_REG4, |v| (v & !FS_MASK) | ((fs as u8) << 4))?;
278        #[cfg(feature = "out_f32")]
279        {
280            self.fs = fs;
281        }
282        Ok(())
283    }
284
285    /// Reboot memory content,
286    /// `CTRL_REG5`: `BOOT`
287    pub fn reboot(&mut self, reboot: bool) -> Result<(), Error<I2C::Error>> {
288        self.reg_xset_bits(Register::CTRL_REG5, BOOT, reboot)?;
289        Ok(())
290    }
291
292    /// In boot,
293    /// `CTRL_REG5`: `BOOT`
294    pub fn in_boot(&mut self) -> Result<bool, Error<I2C::Error>> {
295        let reg = self.read_reg(Register::CTRL_REG5)?;
296        Ok((reg & BOOT) != 0)
297    }
298
299    /// FIFO enable,
300    /// `CTRL_REG5`: `FIFO_EN`
301    pub fn enable_fifo(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
302        self.reg_xset_bits(Register::CTRL_REG5, FIFO_EN, enable)?;
303        Ok(())
304    }
305
306    /// Latch interrupt request on INT1_SRC (31h),
307    /// with INT1_SRC (31h) register cleared by reading INT1_SRC (31h) itself,
308    /// `CTRL_REG5`: `LIR_INT1`
309    pub fn enable_lir_int1(&mut self, latch: bool) -> Result<(), Error<I2C::Error>> {
310        self.reg_xset_bits(Register::CTRL_REG5, LIR_INT1, latch)?;
311        Ok(())
312    }
313
314    /// 4D enable: 4D detection is enabled on INT1 pin
315    /// when 6D bit on INT1_CFG (30h) is set to 1,
316    /// `CTRL_REG5`: `D4D_INT1`
317    pub fn enable_d4d_int1(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
318        self.reg_xset_bits(Register::CTRL_REG5, D4D_INT1, enable)?;
319        Ok(())
320    }
321
322    /// Latch interrupt request on INT2_SRC (35h) register,
323    /// with INT2_SRC (35h) register cleared by reading INT2_SRC (35h) itself,
324    /// `CTRL_REG5`: `LIR_INT2`
325    pub fn enable_lir_int2(&mut self, latch: bool) -> Result<(), Error<I2C::Error>> {
326        self.reg_xset_bits(Register::CTRL_REG5, LIR_INT2, latch)?;
327        Ok(())
328    }
329
330    /// 4D enable: 4D detection is enabled on INT2 pin
331    /// when 6D bit on INT2_CFG (34h) is set to 1,
332    /// `CTRL_REG5`: `D4D_INT2`
333    pub fn enable_d4d_int2(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
334        self.reg_xset_bits(Register::CTRL_REG5, D4D_INT2, enable)?;
335        Ok(())
336    }
337
338    /// `CLICK` interrupt on `INT2` pin,
339    /// `CTRL_REG6`: `I2_CLICK`
340    pub fn enable_i2_click(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
341        self.reg_xset_bits(Register::CTRL_REG6, I2_CLICK, enable)?;
342        Ok(())
343    }
344
345    /// `IA1` interrupt on `INT2` pin,
346    /// `CTRL_REG6`: `I2_IA1`
347    pub fn enable_i2_ia1(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
348        self.reg_xset_bits(Register::CTRL_REG6, I2_IA1, enable)?;
349        Ok(())
350    }
351
352    /// `IA2` interrupt on `INT2` pin,
353    /// `CTRL_REG6`: `I2_IA2`
354    pub fn enable_i2_ia2(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
355        self.reg_xset_bits(Register::CTRL_REG6, I2_IA2, enable)?;
356        Ok(())
357    }
358
359    /// Boot interrupt on `INT2` pin,
360    /// `CTRL_REG6`: `I2_BOOT`
361    pub fn enable_i2_boot(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
362        self.reg_xset_bits(Register::CTRL_REG6, I2_BOOT, enable)?;
363        Ok(())
364    }
365
366    /// Activity interrupt on `INT2` pin,
367    /// `CTRL_REG6`: `I2_ACT`
368    pub fn enable_i2_act(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
369        self.reg_xset_bits(Register::CTRL_REG6, I2_ACT, enable)?;
370        Ok(())
371    }
372
373    /// INT1/INT2 pin polarity,
374    /// `CTRL_REG6`: `INT_POLARITY`
375    pub fn set_int_polarity(&mut self, active_low: bool) -> Result<(), Error<I2C::Error>> {
376        self.reg_xset_bits(Register::CTRL_REG6, INT_POLARITY, active_low)?;
377        Ok(())
378    }
379
380    /// Data status,
381    /// `STATUS_REG`: as
382    /// DataStatus {zyxor: `ZYXOR`, xyzor: (`XOR`, `YOR`, `ZOR`), zyxda: `ZYXDA`, xyzda: (`XDA`, `YDA`, `ZDA`)}
383    pub fn get_status(&mut self) -> Result<DataStatus, Error<I2C::Error>> {
384        let reg = self.read_reg(Register::STATUS_REG)?;
385        Ok(DataStatus {
386            zyxor: (reg & ZYXOR) != 0,
387            xyzor: ((reg & XOR) != 0, (reg & YOR) != 0, (reg & ZOR) != 0),
388            zyxda: (reg & ZYXDA) != 0,
389            xyzda: ((reg & XDA) != 0, (reg & YDA) != 0, (reg & ZDA) != 0),
390        })
391    }
392
393    /// FIFO mode selection,
394    /// `FIFO_CTRL_REG`: `FM`
395    pub fn set_fm(&mut self, fm: FifoMode) -> Result<(), Error<I2C::Error>> {
396        self.modify_reg(Register::FIFO_CTRL_REG, |v| {
397            (v & !FM_MASK) | ((fm as u8) << 6)
398        })?;
399        Ok(())
400    }
401
402    /// FIFO threshold,
403    /// `FIFO_CTRL_REG`: `FTH`
404    pub fn set_fth(&mut self, fth: u8) -> Result<(), Error<I2C::Error>> {
405        self.modify_reg(Register::FIFO_CTRL_REG, |v| {
406            (v & !FTH_MASK) | (fth & FTH_MASK)
407        })?;
408        Ok(())
409    }
410
411    /// Disable click interrupt,
412    /// `CLICK_CFG` clean all bits
413    pub fn disable_click(&mut self) -> Result<(), Error<I2C::Error>> {
414        self.write_reg(Register::CLICK_CFG, 0x00)?;
415        Ok(())
416    }
417
418    /// Enable interrupt double-click on X,Y,Z axis,
419    /// `CLICK_CFG`: `XD`, `YD`, `ZD`
420    pub fn enable_double_click(
421        &mut self,
422        (x, y, z): (bool, bool, bool),
423    ) -> Result<(), Error<I2C::Error>> {
424        self.modify_reg(Register::CLICK_CFG, |mut v| {
425            v &= !(XD | YD | ZD); // disable all axises
426            v |= if x { XD } else { 0 };
427            v |= if y { YD } else { 0 };
428            v |= if z { ZD } else { 0 };
429            v
430        })?;
431        Ok(())
432    }
433
434    /// Enable interrupt single-click on X,Y,Z axis,
435    /// `CLICK_CFG`: `XS`, `YS`, `ZS`
436    pub fn enable_single_click(
437        &mut self,
438        (x, y, z): (bool, bool, bool),
439    ) -> Result<(), Error<I2C::Error>> {
440        self.modify_reg(Register::CLICK_CFG, |mut v| {
441            v &= !(XS | YS | ZS); // disable all axises
442            v |= if x { XS } else { 0 };
443            v |= if y { YS } else { 0 };
444            v |= if z { ZS } else { 0 };
445            v
446        })?;
447        Ok(())
448    }
449
450    /// Click source,
451    /// `CLICK_SRC` decoded as ((`DClick`, `SClick`), `Sign`, (`X`, `Y`, `Z`))
452    #[allow(clippy::type_complexity)]
453    pub fn get_click_src(
454        &mut self,
455    ) -> Result<Option<((bool, bool), bool, (bool, bool, bool))>, Error<I2C::Error>> {
456        let reg = self.read_reg(Register::CLICK_SRC)?;
457        if (reg & IA) != 0 {
458            Ok(Some((
459                ((reg & DClick) != 0, (reg & SClick) != 0),
460                (reg & Sign) != 0,
461                ((reg & X) != 0, (reg & Y) != 0, (reg & Z) != 0),
462            )))
463        } else {
464            Ok(None)
465        }
466    }
467
468    /// If the LIR_Click bit is not set, the interrupt is kept high
469    /// for the duration of the latency window.
470    /// If the LIR_Click bit is set, the interrupt is kept high
471    /// until the CLICK_SRC (39h) register is read.
472    /// `CLICK_THS`: `LIR_Click`
473    pub fn enable_lir_click(&mut self, latch: bool) -> Result<(), Error<I2C::Error>> {
474        self.reg_xset_bits(Register::CLICK_THS, LIR_Click, latch)?;
475        Ok(())
476    }
477
478    /// Click threshold,
479    /// `CLICK_THS`: `Ths`
480    pub fn set_click_ths(&mut self, ths: u8) -> Result<(), Error<I2C::Error>> {
481        self.write_reg(Register::CLICK_THS, ths & THS_MASK)?;
482        Ok(())
483    }
484
485    /// Click threshold as f32,
486    /// `CLICK_THS`: `Ths`
487    #[cfg(feature = "out_f32")]
488    pub fn set_click_thsf(&mut self, ths: f32) -> Result<(), Error<I2C::Error>> {
489        self.set_click_ths(self.fs.convert_ths_f32tou8(ths))
490    }
491
492    /// Click time limit,
493    /// `TIME_LIMIT`: `TLI`
494    pub fn set_time_limit(&mut self, tli: u8) -> Result<(), Error<I2C::Error>> {
495        self.write_reg(Register::TIME_LIMIT, tli & TLI_MASK)?;
496        Ok(())
497    }
498
499    /// Click time latency,
500    /// `TIME_LATENCY`: `TLA`
501    pub fn set_time_latency(&mut self, tla: u8) -> Result<(), Error<I2C::Error>> {
502        self.write_reg(Register::TIME_LATENCY, tla)?;
503        Ok(())
504    }
505
506    /// Click time window,
507    /// `TIME_WINDOW`: `TW`
508    pub fn set_time_window(&mut self, tw: u8) -> Result<(), Error<I2C::Error>> {
509        self.write_reg(Register::TIME_WINDOW, tw)?;
510        Ok(())
511    }
512
513    /// Sleep-to-wake, return-to-sleep activation threshold in low-power mode,
514    /// `ACT_THS`: `Acth`
515    pub fn set_act_ths(&mut self, ths: u8) -> Result<(), Error<I2C::Error>> {
516        self.write_reg(Register::ACT_THS, ths & Acth_MASK)?;
517        Ok(())
518    }
519
520    /// Sleep-to-wake, return-to-sleep activation threshold as f32,
521    /// `ACT_THS`: `Acth`
522    #[cfg(feature = "out_f32")]
523    pub fn set_act_thsf(&mut self, ths: f32) -> Result<(), Error<I2C::Error>> {
524        self.set_act_ths(self.fs.convert_ths_f32tou8(ths))
525    }
526
527    /// Sleep-to-wake, return-to-sleep duration,
528    /// `ACT_DUR`: `ActD`
529    pub fn set_act_dur(&mut self, d: u8) -> Result<(), Error<I2C::Error>> {
530        self.write_reg(Register::ACT_DUR, d)?;
531        Ok(())
532    }
533
534    /// Temperature sensor enable,
535    /// `TEMP_CFG_REG`: `TEMP_EN`,
536    /// the `BDU` bit in `CTRL_REG4` is also set
537    pub fn enable_temp(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
538        self.reg_xset_bits(Register::TEMP_CFG_REG, TEMP_EN, enable)?;
539        if enable {
540            // enable block data update (required for temp reading)
541            self.reg_set_bits(Register::CTRL_REG4, BDU)?;
542        }
543        Ok(())
544    }
545
546    /// Temperature data status,
547    /// `STATUS_REG_AUX`: `TOR` - Temperature data overrun,
548    ///                   `TDA` - Temperature new data available
549    pub fn get_temp_status(&mut self) -> Result<(bool, bool), Error<I2C::Error>> {
550        let reg = self.read_reg(Register::STATUS_REG_AUX)?;
551        Ok(((reg & TOR) != 0, (reg & TDA) != 0))
552    }
553
554    /// Temperature sensor data,
555    /// `OUT_TEMP_H`, `OUT_TEMP_L`
556    pub fn get_temp_out(&mut self) -> Result<(i8, u8), Error<I2C::Error>> {
557        let mut buf = [0u8; 2];
558        self.read_regs(Register::OUT_TEMP_L, &mut buf)?;
559        Ok((buf[1] as i8, buf[0]))
560    }
561
562    /// Temperature sensor data as float,
563    /// `OUT_TEMP_H`, `OUT_TEMP_L` converted to `f32`
564    #[cfg(feature = "out_f32")]
565    pub fn get_temp_outf(&mut self) -> Result<f32, Error<I2C::Error>> {
566        let (out_h, out_l) = self.get_temp_out()?;
567        // 10-bit resolution
568        let value = (i16(out_h) << 8) | i16(out_l);
569        Ok(25.0 + f32(value) / 256.0)
570    }
571
572    /// `REFERENCE` register
573    pub fn set_ref(&mut self, reference: u8) -> Result<(), Error<I2C::Error>> {
574        self.write_reg(Register::REFERENCE, reference)?;
575        Ok(())
576    }
577
578    /// `REFERENCE` register
579    pub fn get_ref(&mut self) -> Result<u8, Error<I2C::Error>> {
580        self.read_reg(Register::REFERENCE).map_err(Into::into)
581    }
582
583    /// INT1
584    pub fn int1(&mut self) -> Int<Int1Regs, I2C> {
585        Int::new(self)
586    }
587
588    /// INT2
589    pub fn int2(&mut self) -> Int<Int2Regs, I2C> {
590        Int::new(self)
591    }
592
593    /// Resets all registers to their default
594    pub fn reset(&mut self) -> Result<(), Error<I2C::Error>> {
595        self.write_reg(Register::CTRL_REG1, CTRL_REG1_DEFAULT)?;
596        self.write_reg(Register::CTRL_REG2, CTRL_REG2_DEFAULT)?;
597        self.write_reg(Register::CTRL_REG3, CTRL_REG3_DEFAULT)?;
598        self.write_reg(Register::CTRL_REG4, CTRL_REG4_DEFAULT)?;
599        self.write_reg(Register::CTRL_REG5, CTRL_REG5_DEFAULT)?;
600        self.write_reg(Register::CTRL_REG6, CTRL_REG6_DEFAULT)?;
601        self.write_reg(Register::INT1_CFG, INT_CFG_DEFAULT)?;
602        self.write_reg(Register::INT2_CFG, INT_CFG_DEFAULT)?;
603        self.write_reg(Register::INT1_THS, INT_THS_DEFAULT)?;
604        self.write_reg(Register::INT2_THS, INT_THS_DEFAULT)?;
605        Ok(())
606    }
607
608    /// Enable self test 0, this shouldn't be enabled at the same time as self test 1
609    pub fn enable_st0(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
610        self.reg_xset_bits(Register::CTRL_REG4, ST0, enable)?;
611        Ok(())
612    }
613
614    /// Enable self test 1, this shouldn't be enabled at the same time as self test 0
615    pub fn enable_st1(&mut self, enable: bool) -> Result<(), Error<I2C::Error>> {
616        self.reg_xset_bits(Register::CTRL_REG4, ST1, enable)?;
617        Ok(())
618    }
619
620    /// Dump registers
621    #[cfg(debug_assertions)]
622    pub fn dump_regs<W>(&mut self, w: &mut W) -> Result<(), Error<I2C::Error>>
623    where
624        W: core::fmt::Write,
625    {
626        writeln!(
627            w,
628            "CTRL_REG1 (20h) = {:#010b}",
629            self.read_reg(Register::CTRL_REG1)?
630        )
631        .unwrap();
632        writeln!(
633            w,
634            "CTRL_REG3 (22h) = {:#010b}",
635            self.read_reg(Register::CTRL_REG3)?
636        )
637        .unwrap();
638        writeln!(
639            w,
640            "CTRL_REG4 (23h) = {:#010b}",
641            self.read_reg(Register::CTRL_REG4)?
642        )
643        .unwrap();
644        writeln!(
645            w,
646            "CTRL_REG5 (24h) = {:#010b}",
647            self.read_reg(Register::CTRL_REG5)?
648        )
649        .unwrap();
650        writeln!(
651            w,
652            "CTRL_REG6 (25h) = {:#010b}",
653            self.read_reg(Register::CTRL_REG6)?
654        )
655        .unwrap();
656        writeln!(
657            w,
658            "INT1_CFG (30h) = {:#010b}",
659            self.read_reg(Register::INT1_CFG)?
660        )
661        .unwrap();
662        writeln!(
663            w,
664            "INT1_THS (32h) = {:#010b}",
665            self.read_reg(Register::INT1_THS)?
666        )
667        .unwrap();
668        writeln!(
669            w,
670            "FIFO_SRC_REG (2Fh) = {:#010b}",
671            self.read_reg(Register::FIFO_SRC_REG)?
672        )
673        .unwrap();
674        writeln!(
675            w,
676            "FIFO_CTRL_REG (2Fh) = {:#010b}",
677            self.read_reg(Register::FIFO_CTRL_REG)?
678        )
679        .unwrap();
680        Ok(())
681    }
682
683    #[inline]
684    fn read_reg(&mut self, reg: Register) -> Result<u8, I2C::Error> {
685        let mut buf = [0u8];
686        self.i2c.write_read(self.addr, &[reg.addr()], &mut buf)?;
687        Ok(buf[0])
688    }
689
690    #[inline]
691    fn read_regs(&mut self, reg: Register, buffer: &mut [u8]) -> Result<(), I2C::Error> {
692        self.i2c
693            .write_read(self.addr, &[reg.addr() | I2C_SUB_MULTI], buffer)
694    }
695
696    #[inline]
697    fn write_reg(&mut self, reg: Register, val: u8) -> Result<(), I2C::Error> {
698        self.i2c.write(self.addr, &[reg.addr(), val])
699    }
700
701    #[inline]
702    fn modify_reg<F>(&mut self, reg: Register, f: F) -> Result<(), I2C::Error>
703    where
704        F: FnOnce(u8) -> u8,
705    {
706        let r = self.read_reg(reg)?;
707        self.write_reg(reg, f(r))?;
708        Ok(())
709    }
710
711    #[inline]
712    fn reg_set_bits(&mut self, reg: Register, bits: u8) -> Result<(), I2C::Error> {
713        self.modify_reg(reg, |v| v | bits)
714    }
715
716    #[inline]
717    fn reg_reset_bits(&mut self, reg: Register, bits: u8) -> Result<(), I2C::Error> {
718        self.modify_reg(reg, |v| v & !bits)
719    }
720
721    #[inline]
722    fn reg_xset_bits(&mut self, reg: Register, bits: u8, set: bool) -> Result<(), I2C::Error> {
723        if set {
724            self.reg_set_bits(reg, bits)
725        } else {
726            self.reg_reset_bits(reg, bits)
727        }
728    }
729}
730
731impl<I2C: I2c> RawAccelerometer<I16x3> for Lis2dh12<I2C> {
732    type Error = I2C::Error;
733
734    /// Get acceleration reading from the accelerometer
735    fn accel_raw(&mut self) -> Result<I16x3, Error<Self::Error>> {
736        let mut buf = [0u8; 6];
737        self.read_regs(Register::OUT_X_L, &mut buf)?;
738
739        Ok(I16x3::new(
740            (u16(buf[0]) + (u16(buf[1]) << 8)) as i16,
741            (u16(buf[2]) + (u16(buf[3]) << 8)) as i16,
742            (u16(buf[4]) + (u16(buf[5]) << 8)) as i16,
743        ))
744    }
745}
746
747#[cfg(feature = "out_f32")]
748impl<I2C: I2c> Accelerometer for Lis2dh12<I2C> {
749    type Error = I2C::Error;
750
751    /// Get normalized ±g reading from the accelerometer
752    fn accel_norm(&mut self) -> Result<F32x3, Error<Self::Error>> {
753        let acc_raw: I16x3 = self.accel_raw()?;
754
755        Ok(F32x3::new(
756            self.fs.convert_out_i16tof32(acc_raw.x),
757            self.fs.convert_out_i16tof32(acc_raw.y),
758            self.fs.convert_out_i16tof32(acc_raw.z),
759        ))
760    }
761
762    /// Get sample rate of accelerometer in Hz
763    fn sample_rate(&mut self) -> Result<f32, Error<Self::Error>> {
764        let creg1 = self.read_reg(Register::CTRL_REG1)?;
765        let rate = match FromPrimitive::from_u8(creg1 >> 4) {
766            Some(Odr::PowerDown) => 0.0,
767            Some(Odr::Hz1) => 1.0,
768            Some(Odr::Hz10) => 10.0,
769            Some(Odr::Hz25) => 25.0,
770            Some(Odr::Hz50) => 50.0,
771            Some(Odr::Hz100) => 100.0,
772            Some(Odr::Hz200) => 200.0,
773            Some(Odr::Hz400) => 400.0,
774            Some(Odr::HighRate0) => 1620.0,
775            Some(Odr::HighRate1) => {
776                if creg1 & LPen == 0 {
777                    1344.0
778                } else {
779                    5376.0
780                }
781            }
782            None => 0.0,
783        };
784        Ok(rate)
785    }
786}
787
788impl<'a, REG, I2C: I2c> Int<'a, REG, I2C>
789where
790    REG: IntRegs,
791{
792    fn new(dev: &'a mut Lis2dh12<I2C>) -> Self {
793        Self {
794            dev,
795            reg: PhantomData,
796        }
797    }
798
799    /// Disable interrupt,
800    /// `INTx_CFG` clean all bits
801    pub fn disable(&mut self) -> Result<(), Error<I2C::Error>> {
802        self.dev.write_reg(REG::reg_cfg(), 0x00)?;
803        Ok(())
804    }
805
806    /// AOI-6D Interrupt mode,
807    /// `INTx_CFG`: `AOI`, `6D`
808    pub fn set_mode(&mut self, mode: Aoi6d) -> Result<(), Error<I2C::Error>> {
809        self.dev
810            .modify_reg(REG::reg_cfg(), |v| (v & !AOI_6D_MASK) | ((mode as u8) << 6))?;
811        Ok(())
812    }
813
814    /// X,Y,Z high event enable,
815    /// `INTx_CFG`: `XHIE`, `YHIE`, `ZHIE`
816    pub fn enable_high(&mut self, (x, y, z): (bool, bool, bool)) -> Result<(), Error<I2C::Error>> {
817        self.dev.modify_reg(REG::reg_cfg(), |mut v| {
818            v &= !(XHIE | YHIE | ZHIE); // disable all axises
819            v |= if x { XHIE } else { 0 };
820            v |= if y { YHIE } else { 0 };
821            v |= if z { ZHIE } else { 0 };
822            v
823        })?;
824        Ok(())
825    }
826
827    /// X,Y,Z low event enable,
828    /// `INTx_CFG`: `XLIE`, `YLIE`, `ZLIE`
829    pub fn enable_low(&mut self, (x, y, z): (bool, bool, bool)) -> Result<(), Error<I2C::Error>> {
830        self.dev.modify_reg(REG::reg_cfg(), |mut v| {
831            v &= !(XLIE | YLIE | ZLIE); // disable all axises
832            v |= if x { XLIE } else { 0 };
833            v |= if y { YLIE } else { 0 };
834            v |= if z { ZLIE } else { 0 };
835            v
836        })?;
837        Ok(())
838    }
839
840    /// Source,
841    /// `INTx_SRC` decoded as ((`XH`, `XL`), (`YH`, `YL`), (`ZH`, `ZL`))
842    #[allow(clippy::type_complexity)]
843    pub fn get_src(
844        &mut self,
845    ) -> Result<Option<((bool, bool), (bool, bool), (bool, bool))>, Error<I2C::Error>> {
846        let reg = self.dev.read_reg(REG::reg_src())?;
847        if (reg & IA) != 0 {
848            Ok(Some((
849                ((reg & XH) != 0, (reg & XL) != 0),
850                ((reg & YH) != 0, (reg & YL) != 0),
851                ((reg & ZH) != 0, (reg & ZL) != 0),
852            )))
853        } else {
854            Ok(None)
855        }
856    }
857
858    /// Threshold,
859    /// `INTx_THS`: `THS`
860    pub fn set_ths(&mut self, ths: u8) -> Result<(), Error<I2C::Error>> {
861        self.dev.write_reg(REG::reg_ths(), ths & THS_MASK)?;
862        Ok(())
863    }
864
865    /// Threshold as f32,
866    /// `INTx_THS`: `THS`
867    #[cfg(feature = "out_f32")]
868    pub fn set_thsf(&mut self, ths: f32) -> Result<(), Error<I2C::Error>> {
869        self.set_ths(self.dev.fs.convert_ths_f32tou8(ths))
870    }
871
872    /// Duration,
873    /// `INTx_DURATION`: `D`
874    pub fn set_duration(&mut self, d: u8) -> Result<(), Error<I2C::Error>> {
875        self.dev.write_reg(REG::reg_duration(), d & D_MASK)?;
876        Ok(())
877    }
878}