use core::convert::TryInto;
use num_enum::TryFromPrimitive;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum SlaveAddr {
Default = 0x18,
Alternate = 0x19,
}
impl SlaveAddr {
pub fn addr(self) -> u8 {
self as u8
}
}
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum Register {
STATUS_AUX = 0x07,
OUT_ADC1_L = 0x08,
OUT_ADC1_H = 0x09,
OUT_ADC2_L = 0x0A,
OUT_ADC2_H = 0x0B,
OUT_ADC3_L = 0x0C,
OUT_ADC3_H = 0x0D,
WHOAMI = 0x0F,
CTRL0 = 0x1E,
TEMP_CFG = 0x1F,
CTRL1 = 0x20,
CTRL2 = 0x21,
CTRL3 = 0x22,
CTRL4 = 0x23,
CTRL5 = 0x24,
CTRL6 = 0x25,
REFERENCE = 0x26,
STATUS = 0x27,
OUT_X_L = 0x28,
OUT_X_H = 0x29,
OUT_Y_L = 0x2A,
OUT_Y_H = 0x2B,
OUT_Z_L = 0x2C,
OUT_Z_H = 0x2D,
FIFO_CTRL = 0x2E,
FIFO_SRC = 0x2F,
INT1_CFG = 0x30,
INT1_SRC = 0x31,
INT1_THS = 0x32,
INT1_DURATION = 0x33,
INT2_CFG = 0x34,
INT2_SRC = 0x35,
INT2_THS = 0x36,
INT2_DURATION = 0x37,
CLICK_CFG = 0x38,
CLICK_SRC = 0x39,
CLICK_THS = 0x3A,
TIME_LIMIT = 0x3B,
TIME_LATENCY = 0x3C,
TIME_WINDOW = 0x3D,
ACT_THS = 0x3E,
ACT_DUR = 0x3F,
}
impl Register {
pub fn addr(self) -> u8 {
self as u8
}
pub fn read_only(self) -> bool {
matches!(
self,
Register::STATUS_AUX
| Register::OUT_ADC1_L
| Register::OUT_ADC1_H
| Register::OUT_ADC2_L
| Register::OUT_ADC2_H
| Register::OUT_ADC3_L
| Register::OUT_ADC3_H
| Register::WHOAMI
| Register::STATUS
| Register::OUT_X_L
| Register::OUT_X_H
| Register::OUT_Y_L
| Register::OUT_Y_H
| Register::OUT_Z_L
| Register::OUT_Z_H
| Register::FIFO_SRC
| Register::INT1_SRC
| Register::INT2_SRC
| Register::CLICK_SRC
)
}
}
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum Range {
G16 = 0b11,
G8 = 0b10,
G4 = 0b01,
G2 = 0b00,
}
impl Range {
pub const fn bits(self) -> u8 {
self as u8
}
pub const fn as_mg(self) -> u8 {
match self {
Range::G16 => 186,
Range::G8 => 62,
Range::G4 => 32,
Range::G2 => 16,
}
}
}
impl Default for Range {
fn default() -> Self {
Range::G2
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Threshold(pub(crate) u8);
impl Threshold {
#[inline(always)]
pub fn g(range: Range, gs: f32) -> Self {
Self::mg(range, gs * 1000.0)
}
#[inline(always)]
pub fn mg(range: Range, mgs: f32) -> Self {
let value = mgs / (range.as_mg() as f32);
let result = crude_ceil(value);
Threshold(result.try_into().unwrap())
}
pub const ZERO: Self = Threshold(0);
}
fn crude_ceil(value: f32) -> u64 {
let truncated = value as u64;
let round_up = value - (truncated as f32) > 0.0;
if round_up {
truncated + 1
} else {
truncated
}
}
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum DataRate {
Hz_400 = 0b0111,
Hz_200 = 0b0110,
Hz_100 = 0b0101,
Hz_50 = 0b0100,
Hz_25 = 0b0011,
Hz_10 = 0b0010,
Hz_1 = 0b0001,
PowerDown = 0b0000,
}
impl DataRate {
pub const fn bits(self) -> u8 {
self as u8
}
pub const fn sample_rate(self) -> f32 {
match self {
DataRate::Hz_400 => 400.0,
DataRate::Hz_200 => 200.0,
DataRate::Hz_100 => 100.0,
DataRate::Hz_50 => 50.0,
DataRate::Hz_25 => 25.0,
DataRate::Hz_10 => 10.0,
DataRate::Hz_1 => 1.0,
DataRate::PowerDown => 0.0,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Duration(pub(crate) u8);
impl Duration {
#[inline(always)]
pub fn seconds(output_data_rate: DataRate, seconds: f32) -> Self {
let duration = output_data_rate.sample_rate() * seconds;
Self(duration as u8)
}
#[inline(always)]
pub fn miliseconds(output_data_rate: DataRate, miliseconds: f32) -> Self {
Self::seconds(output_data_rate, miliseconds * 1000.0)
}
pub const ZERO: Self = Duration(0);
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DataStatus {
pub zyxor: bool,
pub xyzor: (bool, bool, bool),
pub zyxda: bool,
pub xyzda: (bool, bool, bool),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FifoStatus {
pub watermark: bool,
pub overrun: bool,
pub empty: bool,
pub stack_size: u8,
}
impl FifoStatus {
pub const fn from_bits(status: u8) -> Self {
Self {
watermark: (status >> 7) & 1 == 1,
overrun: (status >> 6) & 1 == 1,
empty: (status >> 5) & 1 == 1,
stack_size: status & 0b0001_1111,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FifoMode {
ByPass,
Fifo,
Stream,
StreamToFifoInt1,
StreamToFifoInt2,
}
impl FifoMode {
pub const fn to_bits(self) -> u8 {
let mut trigger = false;
let mode = match self {
FifoMode::ByPass => 0b00,
FifoMode::Fifo => 0b01,
FifoMode::Stream => 0b10,
FifoMode::StreamToFifoInt1 => 0b11,
FifoMode::StreamToFifoInt2 => {
trigger = true;
0b11
}
};
mode << 6 | (trigger as u8) << 5
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum Mode {
HighResolution,
Normal,
LowPower,
}
pub const DEVICE_ID: u8 = 0x33;
pub const ADC_EN: u8 = 0b1000_0000;
pub const TEMP_EN: u8 = 0b0100_0000;
pub const ODR_MASK: u8 = 0b1111_0000;
pub const LP_EN: u8 = 0b0000_1000;
pub const Z_EN: u8 = 0b0000_0100;
pub const Y_EN: u8 = 0b0000_0010;
pub const X_EN: u8 = 0b0000_0001;
pub const BDU: u8 = 0b1000_0000;
pub const FS_MASK: u8 = 0b0011_0000;
pub const HR: u8 = 0b0000_1000;
pub const ZYXOR: u8 = 0b1000_0000;
pub const ZOR: u8 = 0b0100_0000;
pub const YOR: u8 = 0b0010_0000;
pub const XOR: u8 = 0b0001_0000;
pub const ZYXDA: u8 = 0b0000_1000;
pub const ZDA: u8 = 0b0000_0100;
pub const YDA: u8 = 0b0000_0010;
pub const XDA: u8 = 0b0000_0001;
#[cfg(test)]
mod test {
use super::*;
#[test]
fn threshold_g_vs_mg() {
assert_eq!(
Threshold::g(Range::G2, 1.5),
Threshold::mg(Range::G2, 1500.0)
);
}
#[test]
fn duration_seconds_vs_miliseconds() {
assert_eq!(
Duration::seconds(DataRate::Hz_400, 1.5),
Duration::miliseconds(DataRate::Hz_400, 1500.0)
);
}
}