#![allow(unused_parens)]
use modular_bitfield::prelude::*;
use crate::params::{
Bandwidth, ExtClk, ExtSync, FifoFormat, FifoMode, InstantOnThreshold, LinkLoopMode, LowNoise,
OutputDataRate, PowerMode, SettleFilter, WakeUpRate,
};
pub const REG_DEVID_AD: u8 = 0x00;
pub const REG_DEVID_MST: u8 = 0x01;
pub const REG_PARTID: u8 = 0x02;
pub const REG_REVID: u8 = 0x03;
pub const REG_STATUS: u8 = 0x04;
pub const REG_STATUS2: u8 = 0x05;
pub const REG_FIFO_ENTRIES2: u8 = 0x06;
pub const REG_FIFO_ENTRIES: u8 = 0x07;
pub const REG_XDATA_H: u8 = 0x08;
pub const REG_XDATA_L: u8 = 0x09;
pub const REG_YDATA_H: u8 = 0x0A;
pub const REG_YDATA_L: u8 = 0x0B;
pub const REG_ZDATA_H: u8 = 0x0C;
pub const REG_ZDATA_L: u8 = 0x0D;
pub const REG_TEMP_DATA: u8 = 0x0E;
pub const REG_FIFO_DATA: u8 = 0x42;
pub const REG_FIFO_SAMPLES: u8 = 0x39;
pub const REG_FIFO_CTL: u8 = 0x3A;
pub const REG_HPF: u8 = 0x3C;
pub const REG_TIMING: u8 = 0x3D;
pub const REG_MEASURE: u8 = 0x3E;
pub const REG_POWER_CTL: u8 = 0x3F;
pub const REG_SELF_TEST: u8 = 0x40;
pub const REG_RESET: u8 = 0x41;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RegisterAccess {
ReadOnly,
WriteOnly,
ReadWrite,
}
pub trait Register {
type Raw: Copy;
const ADDRESS: u8;
const ACCESS: RegisterAccess;
const RESET_VALUE: Option<Self::Raw>;
}
#[allow(unused_parens)]
#[bitfield]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Status {
pub data_ready: bool,
pub fifo_ready: bool,
pub fifo_full: bool,
pub fifo_overrun: bool,
#[skip]
__: B1,
pub user_nvm_busy: bool,
pub awake: bool,
pub err_user_regs: bool,
}
impl From<u8> for Status {
fn from(value: u8) -> Self {
Self::from_bytes([value])
}
}
impl From<Status> for u8 {
fn from(value: Status) -> Self {
value.into_bytes()[0]
}
}
#[allow(unused_parens)]
#[bitfield]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Status2 {
#[skip]
__: B4,
pub inactivity: bool,
pub activity: bool,
pub activity2: bool,
#[skip]
__: B1,
}
impl From<u8> for Status2 {
fn from(value: u8) -> Self {
Self::from_bytes([value])
}
}
impl From<Status2> for u8 {
fn from(value: Status2) -> Self {
value.into_bytes()[0]
}
}
#[allow(unused_parens)]
#[bitfield]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FifoEntriesUpper {
pub upper: B2,
#[skip]
__: B6,
}
impl FifoEntriesUpper {
pub fn as_u16(self) -> u16 {
self.upper() as u16
}
}
#[allow(unused_parens)]
#[bitfield]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FifoControl {
pub samples_msb: bool,
pub mode: FifoMode,
pub format: FifoFormat,
#[skip]
__: B2,
}
impl From<u8> for FifoControl {
fn from(value: u8) -> Self {
Self::from_bytes([value])
}
}
impl From<FifoControl> for u8 {
fn from(value: FifoControl) -> Self {
value.into_bytes()[0]
}
}
#[allow(unused_parens)]
#[bitfield]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Timing {
pub ext_sync: ExtSync,
pub ext_clk: ExtClk,
pub wake_up_rate: WakeUpRate,
pub odr: OutputDataRate,
}
impl From<u8> for Timing {
fn from(value: u8) -> Self {
Self::from_bytes([value])
}
}
impl From<Timing> for u8 {
fn from(value: Timing) -> Self {
value.into_bytes()[0]
}
}
#[allow(unused_parens)]
#[bitfield]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Measure {
pub bandwidth: Bandwidth,
pub low_noise: LowNoise,
pub link_loop_mode: LinkLoopMode,
pub autosleep: bool,
pub user_or_disable: bool,
}
impl From<u8> for Measure {
fn from(value: u8) -> Self {
Self::from_bytes([value])
}
}
impl From<Measure> for u8 {
fn from(value: Measure) -> Self {
value.into_bytes()[0]
}
}
#[allow(unused_parens)]
#[bitfield]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PowerControl {
pub mode: PowerMode,
pub hpf_disable: bool,
pub lpf_disable: bool,
pub filter_settle: SettleFilter,
pub instant_on_threshold: InstantOnThreshold,
#[skip]
__: B1,
pub i2c_high_speed_enable: bool,
}
impl From<u8> for PowerControl {
fn from(value: u8) -> Self {
Self::from_bytes([value])
}
}
impl From<PowerControl> for u8 {
fn from(value: PowerControl) -> Self {
value.into_bytes()[0]
}
}
#[allow(unused_parens)]
#[bitfield]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SelfTest {
pub st: bool,
pub st_done: bool,
pub user_st: bool,
#[skip]
__: B5,
}
impl From<u8> for SelfTest {
fn from(value: u8) -> Self {
Self::from_bytes([value])
}
}
impl From<SelfTest> for u8 {
fn from(value: SelfTest) -> Self {
value.into_bytes()[0]
}
}
impl Register for Status {
type Raw = u8;
const ADDRESS: u8 = REG_STATUS;
const ACCESS: RegisterAccess = RegisterAccess::ReadOnly;
const RESET_VALUE: Option<Self::Raw> = Some(0xA0);
}
impl Register for Status2 {
type Raw = u8;
const ADDRESS: u8 = REG_STATUS2;
const ACCESS: RegisterAccess = RegisterAccess::ReadOnly;
const RESET_VALUE: Option<Self::Raw> = Some(0x00);
}
impl Register for FifoControl {
type Raw = u8;
const ADDRESS: u8 = REG_FIFO_CTL;
const ACCESS: RegisterAccess = RegisterAccess::ReadWrite;
const RESET_VALUE: Option<Self::Raw> = Some(0x00);
}
impl Register for Timing {
type Raw = u8;
const ADDRESS: u8 = REG_TIMING;
const ACCESS: RegisterAccess = RegisterAccess::ReadWrite;
const RESET_VALUE: Option<Self::Raw> = Some(0x00);
}
impl Register for Measure {
type Raw = u8;
const ADDRESS: u8 = REG_MEASURE;
const ACCESS: RegisterAccess = RegisterAccess::ReadWrite;
const RESET_VALUE: Option<Self::Raw> = Some(0x00);
}
impl Register for PowerControl {
type Raw = u8;
const ADDRESS: u8 = REG_POWER_CTL;
const ACCESS: RegisterAccess = RegisterAccess::ReadWrite;
const RESET_VALUE: Option<Self::Raw> = Some(0x00);
}
impl Register for SelfTest {
type Raw = u8;
const ADDRESS: u8 = REG_SELF_TEST;
const ACCESS: RegisterAccess = RegisterAccess::ReadWrite;
const RESET_VALUE: Option<Self::Raw> = Some(0x00);
}
pub fn fifo_entry_count(upper: FifoEntriesUpper, lower: u8) -> u16 {
(upper.as_u16() << 8) | lower as u16
}
pub fn split_fifo_entry_count(count: u16) -> (FifoEntriesUpper, u8) {
let upper = FifoEntriesUpper::new().with_upper(((count >> 8) & 0x03) as u8);
let lower = (count & 0xFF) as u8;
(upper, lower)
}
pub const RESET_COMMAND: u8 = 0x52;
pub const EXPECTED_DEVID_AD: u8 = 0xAD;
pub const EXPECTED_DEVID_MST: u8 = 0x1D;
pub const EXPECTED_PART_ID: u8 = 0xFA;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn status_layout_matches_datasheet() {
let status = Status::from(0b1010_0000);
assert!(!status.data_ready());
assert!(!status.fifo_ready());
assert!(!status.fifo_full());
assert!(!status.fifo_overrun());
assert!(status.user_nvm_busy());
assert!(!status.awake());
assert!(status.err_user_regs());
}
#[test]
fn timing_roundtrip() {
let timing = Timing::new()
.with_ext_sync(ExtSync::Enabled)
.with_ext_clk(ExtClk::Disabled)
.with_wake_up_rate(WakeUpRate::Ms512)
.with_odr(OutputDataRate::Od1600Hz);
assert_eq!(u8::from(timing), 0b010_011_0_1);
let decoded = Timing::from(u8::from(timing));
assert_eq!(decoded.wake_up_rate(), WakeUpRate::Ms512);
assert_eq!(decoded.odr(), OutputDataRate::Od1600Hz);
assert_eq!(decoded.ext_sync(), ExtSync::Enabled);
assert_eq!(decoded.ext_clk(), ExtClk::Disabled);
}
}