2025-01-12 00:53:26 +01:00

278 lines
8.8 KiB
Rust

use {
crate::lsm6ds3tr::data::XYZ,
crate::lsm6ds3tr::registers::{
FreeFall, FreeFallThreshold, Int1Ctrl, Int2Ctrl, IntDur2, Md1Cfg, Md2Cfg, RegisterConfig,
TapCfg, TapThs6d, WakeUpDur, WakeUpThs,
},
};
/// Interrupt pin/pad routing selection
#[derive(Default, Clone, Copy)]
pub enum InterruptRoute {
#[default]
None,
Int1,
Int2,
Both,
}
#[derive(Default, Clone, Copy)]
pub enum TapRecognitionMode {
#[default]
None,
Single,
Double,
Both,
}
#[derive(Default, Clone, Copy)]
pub struct FreeFallIrqSettings {
pub interrupt_route: InterruptRoute,
pub threshold: FreeFallThreshold,
pub duration_samples: u8,
}
#[derive(Default)]
pub struct WakeUpIrqSettings {
pub interrupt_route: InterruptRoute,
pub threshold: u8,
}
#[derive(Default)]
pub struct OrientationDetectionIrqSettings {
pub interrupt_route: InterruptRoute,
// TODO
}
#[derive(Default)]
pub struct TapIrqSettings {
pub interrupt_route: InterruptRoute,
pub recognition_mode: TapRecognitionMode,
pub direction_enable: XYZ<bool>,
pub threshold: u8,
pub shock_samples: u8,
pub quiet_samples: u8,
pub duration_samples: u8,
}
#[derive(Default)]
pub struct ActivityIrqSettings {
pub interrupt_route: InterruptRoute,
// TODO
}
/// Interrupt settings
#[derive(Default)]
pub struct IrqSettings {
pub free_fall: FreeFallIrqSettings,
pub wake_up: WakeUpIrqSettings,
pub orientation_detection: OrientationDetectionIrqSettings,
pub tap: TapIrqSettings,
pub activity: ActivityIrqSettings,
registers: IrqRegisters,
}
#[derive(Default)]
struct IrqRegisters {
int1_ctrl: Int1Ctrl,
int2_ctrl: Int2Ctrl,
md1_cfg: Md1Cfg,
md2_cfg: Md2Cfg,
tap_cfg: TapCfg,
tap_ths_6d: TapThs6d,
free_fall: FreeFall,
wake_up_dur: WakeUpDur,
wake_up_ths: WakeUpThs,
int_dur2: IntDur2,
}
impl IrqSettings {
/// Enables Free Fall interrupt
pub fn enable_free_fall_irq(
&mut self,
threshold: FreeFallThreshold,
duration_samples: u8,
interrupt_route: InterruptRoute,
latched_irq: bool,
) {
self.enable_irqs(latched_irq);
self.free_fall.threshold = threshold;
self.free_fall.duration_samples = duration_samples;
self.free_fall.interrupt_route = interrupt_route;
self.update_registers();
}
/// Enables Wake Up interrupt
pub fn enable_wake_up_irq(
&mut self,
threshold: u8,
interrupt_route: InterruptRoute,
latched_irq: bool,
) {
self.enable_irqs(latched_irq);
self.wake_up.threshold = threshold;
self.wake_up.interrupt_route = interrupt_route;
self.update_registers();
}
// TODO provide helper function calculating desired tap time to register values
/// Enables Single/Double Tap interrupt
pub fn enable_tap_irq(
&mut self,
recognition_mode: TapRecognitionMode,
direction_enable: XYZ<bool>,
// threshold: u8,
// shock_samples: u8,
// quiet_samples: u8,
// duration_samples: u8,
interrupt_route: InterruptRoute,
latched_irq: bool,
) {
self.enable_irqs(latched_irq);
self.tap.recognition_mode = recognition_mode;
self.tap.direction_enable = direction_enable;
// self.tap.threshold = threshold;
// self.tap.shock_samples = shock_samples;
// self.tap.quiet_samples = quiet_samples;
// self.tap.duration_samples = duration_samples;
self.tap.interrupt_route = interrupt_route;
self.update_registers();
}
/// Enables basic interrupts
pub fn enable_irqs(&mut self, latched_irq: bool) {
self.registers.tap_cfg.enable_basic_interrupts = 1.into();
self.registers.tap_cfg.latched_interrupt = latched_irq.into();
self.update_registers();
}
/// Disables basic interrupts
pub fn disable_irqs(&mut self) {
self.registers.tap_cfg.enable_basic_interrupts = 0.into();
self.update_registers();
}
/// Returns interrupt-related registers configs to be written
pub fn configs(&self) -> [RegisterConfig; 10] {
[
self.registers.int1_ctrl.config(),
self.registers.int2_ctrl.config(),
self.registers.int_dur2.config(),
self.registers.md1_cfg.config(),
self.registers.md2_cfg.config(),
self.registers.tap_cfg.config(),
self.registers.tap_ths_6d.config(),
self.registers.free_fall.config(),
self.registers.wake_up_dur.config(),
self.registers.wake_up_ths.config(),
]
}
fn update_registers(&mut self) {
self.update_free_fall_registers();
self.update_wake_up_registers();
self.update_tap_registers();
}
fn update_free_fall_registers(&mut self) {
(
self.registers.md1_cfg.free_fall_event,
self.registers.md2_cfg.free_fall_event,
) = match self.free_fall.interrupt_route {
InterruptRoute::None => (0.into(), 0.into()),
InterruptRoute::Int1 => (1.into(), 0.into()),
InterruptRoute::Int2 => (0.into(), 1.into()),
InterruptRoute::Both => (1.into(), 1.into()),
};
self.registers.free_fall.threshold = self.free_fall.threshold;
self.registers.wake_up_dur.free_fall_duration_event =
(((self.free_fall.threshold as u8) >> 5) & 0b1).into();
self.registers.free_fall.duration_event = self.free_fall.duration_samples.into();
}
fn update_wake_up_registers(&mut self) {
(
self.registers.md1_cfg.wake_up_event,
self.registers.md2_cfg.wake_up_event,
) = match self.wake_up.interrupt_route {
InterruptRoute::None => (0.into(), 0.into()),
InterruptRoute::Int1 => (1.into(), 0.into()),
InterruptRoute::Int2 => (0.into(), 1.into()),
InterruptRoute::Both => (1.into(), 1.into()),
};
self.registers.wake_up_ths.wake_up_threshold = self.wake_up.threshold.into();
}
fn update_tap_registers(&mut self) {
match self.tap.recognition_mode {
TapRecognitionMode::None | TapRecognitionMode::Single => {
self.registers.wake_up_ths.single_double_tap_enabled = 0.into()
}
TapRecognitionMode::Double | TapRecognitionMode::Both => {
self.registers.wake_up_ths.single_double_tap_enabled = 1.into()
}
}
match self.tap.recognition_mode {
TapRecognitionMode::None => {
self.registers.tap_cfg.enable_basic_interrupts = false.into()
}
TapRecognitionMode::Single => {
self.registers.tap_cfg.enable_basic_interrupts = true.into();
self.update_single_tap_registers()
}
TapRecognitionMode::Double => {
self.registers.tap_cfg.enable_basic_interrupts = true.into();
self.update_double_tap_registers()
}
TapRecognitionMode::Both => {
self.registers.tap_cfg.enable_basic_interrupts = true.into();
self.update_single_tap_registers();
self.update_double_tap_registers();
}
};
self.registers.tap_cfg.enable_basic_interrupts = 1.into();
self.registers.tap_cfg.enable_x_direction_tap_recognition =
self.tap.direction_enable.x.into();
self.registers.tap_cfg.enable_y_direction_tap_recognition =
self.tap.direction_enable.y.into();
self.registers.tap_cfg.enable_z_direction_tap_recognition =
self.tap.direction_enable.z.into();
self.registers.tap_ths_6d.tap_threshold = self.tap.threshold.into();
self.registers.int_dur2.duration = self.tap.duration_samples.into();
self.registers.int_dur2.quiet = self.tap.quiet_samples.into();
self.registers.int_dur2.shock = self.tap.shock_samples.into();
}
fn update_single_tap_registers(&mut self) {
(
self.registers.md1_cfg.single_tap_event,
self.registers.md2_cfg.single_tap_event,
) = match self.tap.interrupt_route {
InterruptRoute::None => (0.into(), 0.into()),
InterruptRoute::Int1 => (1.into(), 0.into()),
InterruptRoute::Int2 => (0.into(), 1.into()),
InterruptRoute::Both => (1.into(), 1.into()),
};
}
fn update_double_tap_registers(&mut self) {
(
self.registers.md1_cfg.double_tap_event,
self.registers.md2_cfg.double_tap_event,
) = match self.tap.interrupt_route {
InterruptRoute::None => (0.into(), 0.into()),
InterruptRoute::Int1 => (1.into(), 0.into()),
InterruptRoute::Int2 => (0.into(), 1.into()),
InterruptRoute::Both => (1.into(), 1.into()),
};
}
}