278 lines
8.8 KiB
Rust
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()),
|
|
};
|
|
}
|
|
}
|