lis3dh_async/
interrupts.rs

1use crate::register::*;
2
3#[derive(Debug, Copy, Clone)]
4#[cfg_attr(feature = "defmt", derive(defmt::Format))]
5pub struct Interrupt1;
6
7#[derive(Debug, Copy, Clone)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub struct Interrupt2;
10
11pub trait Interrupt {
12    fn cfg_reg() -> Register;
13    fn ths_reg() -> Register;
14    fn src_reg() -> Register;
15    fn duration_reg() -> Register;
16    fn lir_int_bit() -> u8;
17    fn d4d_int_bit() -> u8;
18}
19
20impl Interrupt for Interrupt1 {
21    fn cfg_reg() -> Register {
22        Register::INT1_CFG
23    }
24
25    fn ths_reg() -> Register {
26        Register::INT1_THS
27    }
28
29    fn src_reg() -> Register {
30        Register::INT1_SRC
31    }
32
33    fn duration_reg() -> Register {
34        Register::INT1_DURATION
35    }
36
37    fn lir_int_bit() -> u8 {
38        3
39    }
40
41    fn d4d_int_bit() -> u8 {
42        2
43    }
44}
45
46impl Interrupt for Interrupt2 {
47    fn cfg_reg() -> Register {
48        Register::INT2_CFG
49    }
50
51    fn ths_reg() -> Register {
52        Register::INT2_THS
53    }
54
55    fn src_reg() -> Register {
56        Register::INT2_SRC
57    }
58
59    fn duration_reg() -> Register {
60        Register::INT2_DURATION
61    }
62
63    fn lir_int_bit() -> u8 {
64        1
65    }
66
67    fn d4d_int_bit() -> u8 {
68        0
69    }
70}
71
72/// When to generate an interrupt.
73///
74/// Internal representation:
75///
76/// | AOI | 6D | Interrupt mode |
77/// | - | - | --- |
78/// | 0 | 0 | OR combination of interrupt events  |
79/// | 0 | 1 | 6-direction movement recognition  |
80/// | 1 | 0 | AND combination of interrupt events  |
81/// | 1 | 1 | 6-direction position recognition  |
82#[derive(Debug, Copy, Clone)]
83#[cfg_attr(feature = "defmt", derive(defmt::Format))]
84#[derive(Default)]
85pub enum InterruptMode {
86    #[default]
87    OrCombination = 0b00 << 6,
88    Movement = 0b01 << 6,
89    AndCombination = 0b10 << 6,
90    Position = 0b11 << 6,
91}
92
93impl InterruptMode {
94    const fn from_bits(input: u8) -> Self {
95        match input >> 6 {
96            0b00 => InterruptMode::OrCombination,
97            0b01 => InterruptMode::Movement,
98            0b10 => InterruptMode::AndCombination,
99            0b11 => InterruptMode::Position,
100            _ => {
101                // change to unreachable when https://github.com/rust-lang/rust/issues/51999 is stable
102                InterruptMode::Position
103            }
104        }
105    }
106    const fn to_bits(self) -> u8 {
107        match self {
108            InterruptMode::OrCombination => 0b00 << 6,
109            InterruptMode::Movement => 0b01 << 6,
110            InterruptMode::AndCombination => 0b10 << 6,
111            InterruptMode::Position => 0b11 << 6,
112        }
113    }
114}
115
116impl From<u8> for InterruptMode {
117    fn from(input: u8) -> Self {
118        Self::from_bits(input)
119    }
120}
121
122/// Configure which events on which axes trigger an interrupt.
123#[derive(Debug, Copy, Clone, Default)]
124#[cfg_attr(feature = "defmt", derive(defmt::Format))]
125#[doc(alias = "INT1_CFG")]
126#[doc(alias = "INT2_CFG")]
127pub struct InterruptConfig {
128    pub z_axis_high: bool,
129    pub z_axis_low: bool,
130
131    pub y_axis_high: bool,
132    pub y_axis_low: bool,
133
134    pub x_axis_high: bool,
135    pub x_axis_low: bool,
136}
137
138impl InterruptConfig {
139    /// Don't generate an interrupt for any event
140    pub const fn none() -> Self {
141        Self {
142            z_axis_high: false,
143            z_axis_low: false,
144
145            y_axis_high: false,
146            y_axis_low: false,
147
148            x_axis_high: false,
149            x_axis_low: false,
150        }
151    }
152
153    /// Generate an interrupt for a low and a high event
154    /// on any of the axes
155    pub const fn high_and_low() -> Self {
156        Self {
157            z_axis_high: true,
158            z_axis_low: true,
159
160            y_axis_high: true,
161            y_axis_low: true,
162
163            x_axis_high: true,
164            x_axis_low: true,
165        }
166    }
167
168    /// Generate an interrupt for a high event
169    /// on any of the axes
170    pub const fn high() -> Self {
171        Self {
172            z_axis_high: true,
173            z_axis_low: false,
174
175            y_axis_high: true,
176            y_axis_low: false,
177
178            x_axis_high: true,
179            x_axis_low: false,
180        }
181    }
182
183    /// Generate an interrupt for a low event
184    /// on any of the axes
185    pub const fn low() -> Self {
186        Self {
187            z_axis_high: false,
188            z_axis_low: true,
189
190            y_axis_high: false,
191            y_axis_low: true,
192
193            x_axis_high: false,
194            x_axis_low: true,
195        }
196    }
197
198    pub fn to_bits(self, interrupt_mode: InterruptMode) -> u8 {
199        interrupt_mode.to_bits()
200            | (self.z_axis_high as u8) << 5
201            | (self.z_axis_low as u8) << 4
202            | (self.y_axis_high as u8) << 3
203            | (self.y_axis_low as u8) << 2
204            | (self.x_axis_high as u8) << 1
205            | (self.x_axis_low as u8)
206    }
207
208    pub const fn from_bits(irq_src: u8) -> Self {
209        Self {
210            z_axis_high: irq_src & (1 << 5) != 0,
211            z_axis_low: irq_src & (1 << 4) != 0,
212            y_axis_high: irq_src & (1 << 3) != 0,
213            y_axis_low: irq_src & (1 << 2) != 0,
214            x_axis_high: irq_src & (1 << 1) != 0,
215            x_axis_low: irq_src & (1 << 0) != 0,
216        }
217    }
218}
219
220#[derive(Debug, Copy, Clone, Default)]
221#[cfg_attr(feature = "defmt", derive(defmt::Format))]
222#[doc(alias = "CTRL_REG3")]
223pub struct IrqPin1Config {
224    pub click_en: bool,    // 7
225    pub ia1_en: bool,      // 6
226    pub ia2_en: bool,      // 5
227    pub zyxda_en: bool,    // 4
228    pub adc321da_en: bool, // 3
229    pub wtm_en: bool,      // 2
230    pub overrun_en: bool,  // 1
231}
232
233#[derive(Debug, Copy, Clone, Default)]
234#[cfg_attr(feature = "defmt", derive(defmt::Format))]
235#[doc(alias = "CTRL_REG6")]
236pub struct IrqPin2Config {
237    pub click_en: bool,   // 7
238    pub ia1_en: bool,     // 6
239    pub ia2_en: bool,     // 5
240    pub boot_en: bool,    // 4
241    pub act_en: bool,     // 3
242    pub active_low: bool, // 1
243}
244
245pub trait IrqPin {
246    fn ctrl_reg() -> Register;
247    fn bits(self) -> u8;
248}
249
250impl IrqPin for IrqPin1Config {
251    fn ctrl_reg() -> Register {
252        Register::CTRL3
253    }
254
255    fn bits(self) -> u8 {
256        (self.click_en as u8) << 7
257            | (self.ia1_en as u8) << 6
258            | (self.ia2_en as u8) << 5
259            | (self.zyxda_en as u8) << 4
260            | (self.adc321da_en as u8) << 3
261            | (self.wtm_en as u8) << 2
262            | (self.overrun_en as u8) << 1
263    }
264}
265
266impl IrqPin for IrqPin2Config {
267    fn ctrl_reg() -> Register {
268        Register::CTRL6
269    }
270
271    fn bits(self) -> u8 {
272        (self.click_en as u8) << 7
273            | (self.ia1_en as u8) << 6
274            | (self.ia2_en as u8) << 5
275            | (self.boot_en as u8) << 4
276            | (self.act_en as u8) << 3
277            | (self.active_low as u8) << 1
278    }
279}
280
281#[derive(Debug, Copy, Clone, Default)]
282#[cfg_attr(feature = "defmt", derive(defmt::Format))]
283#[doc(alias = "INT1_SRC")]
284#[doc(alias = "INT2_SRC")]
285pub struct InterruptSource {
286    pub interrupt_active: bool,
287
288    pub z_axis_high: bool,
289    pub z_axis_low: bool,
290
291    pub y_axis_high: bool,
292    pub y_axis_low: bool,
293
294    pub x_axis_high: bool,
295    pub x_axis_low: bool,
296}
297
298impl InterruptSource {
299    pub const fn from_bits(input: u8) -> Self {
300        // NOTE the leftmost bit is unused
301        Self {
302            interrupt_active: input & (1 << 6) != 0,
303            z_axis_high: input & (1 << 5) != 0,
304            z_axis_low: input & (1 << 4) != 0,
305            y_axis_high: input & (1 << 3) != 0,
306            y_axis_low: input & (1 << 2) != 0,
307            x_axis_high: input & (1 << 1) != 0,
308            x_axis_low: input & (1 << 0) != 0,
309        }
310    }
311}
312
313/// Latch (keep active) the interrupt until the [`get_irq_src`] is read.
314///
315/// [`get_irq_src`]: crate::Lis3dh::get_irq_src
316#[derive(Debug, Copy, Clone)]
317#[cfg_attr(feature = "defmt", derive(defmt::Format))]
318#[derive(Default)]
319pub enum LatchInterruptRequest {
320    Enable,
321    #[default]
322    Disable,
323}
324
325impl From<bool> for LatchInterruptRequest {
326    fn from(input: bool) -> Self {
327        if input {
328            Self::Enable
329        } else {
330            Self::Disable
331        }
332    }
333}
334
335/// 4D detection is a subset of the 6D detection where detection on the Z axis is disabled.
336/// This setting only has effect when the interrupt mode is either `Movement` or `Position`.
337#[derive(Debug, Copy, Clone)]
338#[cfg_attr(feature = "defmt", derive(defmt::Format))]
339#[derive(Default)]
340pub enum Detect4D {
341    Enable,
342    #[default]
343    Disable,
344}
345
346impl From<bool> for Detect4D {
347    fn from(input: bool) -> Self {
348        if input {
349            Self::Enable
350        } else {
351            Self::Disable
352        }
353    }
354}