pub const BMI160_CHIP_ID: u8 = 0xD1;
pub const BMI260_CHIP_ID: u8 = 0x27;
pub const BMI270_CHIP_ID: u8 = 0x24;
#[derive(Debug)]
pub enum Error<CommE> {
Comm(CommE),
Alloc,
InvalidChipId,
BufferTooSmall,
InitFailed,
}
pub struct Burst {
max: u16,
kind: BurstKind,
}
enum BurstKind {
Max,
Other(u16),
}
impl Default for BurstKind {
fn default() -> Self {
Self::Max
}
}
impl Burst {
pub fn new(max: u16) -> Self {
Self {
max,
kind: BurstKind::default(),
}
}
pub fn custom(max: u16, value: u16) -> Self {
Self {
max,
kind: BurstKind::Other(value),
}
}
pub fn val(&self) -> u16 {
match self.kind {
BurstKind::Max => self.max,
BurstKind::Other(v) => v.min(self.max),
}
}
}
impl Default for Burst {
fn default() -> Self {
Self::new(512)
}
}
pub struct ErrRegMask;
impl ErrRegMask {
pub const AUX_ERR: u8 = 1 << 7;
pub const FIFO_ERR: u8 = 1 << 6;
pub const INTERNAL_ERR: u8 = 0b0001_1110;
pub const FATAL_ERR: u8 = 1;
}
pub struct ErrorReg {
pub fatal_err: bool,
pub internal_err: u8,
pub fifo_err: bool,
pub aux_err: bool,
}
impl ErrorReg {
pub fn from_reg(reg: u8) -> ErrorReg {
ErrorReg {
fatal_err: (reg & ErrRegMask::FATAL_ERR) != 0,
internal_err: reg & ErrRegMask::INTERNAL_ERR,
fifo_err: (reg & ErrRegMask::FIFO_ERR) != 0,
aux_err: (reg & ErrRegMask::AUX_ERR) != 0,
}
}
}
pub struct StatusBits;
impl StatusBits {
pub const DRDY_ACC: u8 = 1 << 7;
pub const DRDY_GYR: u8 = 1 << 6;
pub const DRDY_AUX: u8 = 1 << 5;
pub const CMD_RDY: u8 = 1 << 4;
pub const AUX_BUSY: u8 = 1 << 2;
}
pub struct Status {
pub acc_data_ready: bool,
pub gyr_data_ready: bool,
pub aux_data_ready: bool,
pub cmd_ready: bool,
pub aux_dev_busy: bool,
}
impl Status {
pub fn from_reg(reg: u8) -> Status {
Status {
acc_data_ready: (reg & StatusBits::DRDY_ACC) != 0,
gyr_data_ready: (reg & StatusBits::DRDY_GYR) != 0,
aux_data_ready: (reg & StatusBits::DRDY_AUX) != 0,
cmd_ready: (reg & StatusBits::CMD_RDY) != 0,
aux_dev_busy: (reg & StatusBits::AUX_BUSY) != 0,
}
}
}
pub struct AxisData {
pub x: i16,
pub y: i16,
pub z: i16,
}
pub struct AuxData {
pub axis: AxisData,
pub r: i16,
}
pub struct Data {
pub acc: AxisData,
pub gyr: AxisData,
pub time: u32,
}
pub struct EventMask;
impl EventMask {
pub const ERR_CODE: u8 = 0b0001_1100;
pub const POR_DETECTED: u8 = 1;
}
#[repr(u8)]
pub enum PersistentErrors {
NoErr = 0x00,
AccErr = 0x01,
GyrErr = 0x02,
AccGyrErr = 0x03,
}
pub struct Event {
pub por_detected: bool,
pub persistent_err: PersistentErrors,
}
impl Event {
pub fn from_reg(reg: u8) -> Event {
Event {
por_detected: (reg & EventMask::POR_DETECTED) != 0,
persistent_err: match (reg & EventMask::ERR_CODE) >> 2 {
0x00 => PersistentErrors::NoErr,
0x01 => PersistentErrors::AccErr,
0x02 => PersistentErrors::GyrErr,
0x03 => PersistentErrors::AccGyrErr,
_ => panic!(), },
}
}
}
pub struct InterruptStatus0Mask;
impl InterruptStatus0Mask {
pub const SIG_MOTION_OUT: u8 = 1;
pub const STEP_COUNTER_OUT: u8 = 1 << 1;
pub const ACTIVITY_OUT: u8 = 1 << 2;
pub const WRIST_WEAR_WAKEUP_OUT: u8 = 1 << 3;
pub const WRIST_GESTURE_OUT: u8 = 1 << 4;
pub const NO_MOTION_OUT: u8 = 1 << 5;
pub const ANY_MOTION_OUT: u8 = 1 << 6;
}
pub struct InterruptStatus1Mask;
impl InterruptStatus1Mask {
pub const FFULL_INT: u8 = 1;
pub const FWM_INT: u8 = 1 << 1;
pub const ERR_INT: u8 = 1 << 2;
pub const AUX_DRDY_INT: u8 = 1 << 5;
pub const GYR_DRDY_INT: u8 = 1 << 6;
pub const ACC_DRDY_INT: u8 = 1 << 7;
}
pub struct InterruptStatus {
pub sig_motion_out: bool,
pub step_counter_out: bool,
pub activity_out: bool,
pub wrist_wear_wakeup_out: bool,
pub wrist_gesture_out: bool,
pub no_motion_out: bool,
pub any_motion_out: bool,
pub ffull_int: bool,
pub fwm_int: bool,
pub err_int: bool,
pub aux_drdy_int: bool,
pub gyr_drdy_int: bool,
pub acc_drdy_int: bool,
}
impl InterruptStatus {
pub fn from_regs(int_stat_0: u8, int_stat_1: u8) -> InterruptStatus {
InterruptStatus {
sig_motion_out: (int_stat_0 & InterruptStatus0Mask::SIG_MOTION_OUT) != 0,
step_counter_out: (int_stat_0 & InterruptStatus0Mask::STEP_COUNTER_OUT) != 0,
activity_out: (int_stat_0 & InterruptStatus0Mask::ACTIVITY_OUT) != 0,
wrist_wear_wakeup_out: (int_stat_0 & InterruptStatus0Mask::WRIST_WEAR_WAKEUP_OUT) != 0,
wrist_gesture_out: (int_stat_0 & InterruptStatus0Mask::WRIST_GESTURE_OUT) != 0,
no_motion_out: (int_stat_0 & InterruptStatus0Mask::NO_MOTION_OUT) != 0,
any_motion_out: (int_stat_0 & InterruptStatus0Mask::ANY_MOTION_OUT) != 0,
ffull_int: (int_stat_1 & InterruptStatus1Mask::FFULL_INT) != 0,
fwm_int: (int_stat_1 & InterruptStatus1Mask::FWM_INT) != 0,
err_int: (int_stat_1 & InterruptStatus1Mask::ERR_INT) != 0,
aux_drdy_int: (int_stat_1 & InterruptStatus1Mask::AUX_DRDY_INT) != 0,
gyr_drdy_int: (int_stat_1 & InterruptStatus1Mask::GYR_DRDY_INT) != 0,
acc_drdy_int: (int_stat_1 & InterruptStatus1Mask::ACC_DRDY_INT) != 0,
}
}
}
pub struct WristGestureActivityMask;
impl WristGestureActivityMask {
pub const WRIST_GESTURE: u8 = 0b0000_0111;
pub const ACTIVITY: u8 = 0b0001_1000;
}
#[repr(u8)]
pub enum WristGesture {
Unknown = 0x00,
PushArmDown = 0x01,
PivotUp = 0x02,
Shake = 0x03,
FlickIn = 0x04,
FlickOut = 0x05,
}
#[repr(u8)]
pub enum Activity {
Still = 0x00,
Walking = 0x01,
Running = 0x02,
Unknown = 0x03,
}
pub struct WristGestureActivity {
pub wrist_gesture: WristGesture,
pub activity: Activity,
}
impl WristGestureActivity {
pub fn from_reg(reg: u8) -> WristGestureActivity {
WristGestureActivity {
wrist_gesture: match reg & WristGestureActivityMask::WRIST_GESTURE {
0x00 => WristGesture::Unknown,
0x01 => WristGesture::PushArmDown,
0x02 => WristGesture::PivotUp,
0x03 => WristGesture::Shake,
0x04 => WristGesture::FlickIn,
0x05 => WristGesture::FlickOut,
_ => panic!(), },
activity: match (reg & WristGestureActivityMask::ACTIVITY) >> 3 {
0x00 => Activity::Still,
0x01 => Activity::Walking,
0x02 => Activity::Running,
0x03 => Activity::Unknown,
_ => panic!(), },
}
}
}
pub struct InternalStatusMask;
impl InternalStatusMask {
pub const MESSAGE: u8 = 0b0000_0111;
pub const AXES_REMAP_ERROR: u8 = 1 << 5;
pub const ODR_50HZ_ERROR: u8 = 1 << 6;
}
#[repr(u8)]
pub enum Message {
NotInit = 0x00,
InitOk = 0x01,
InitErr = 0x02,
DrvErr = 0x03,
SnsErr = 0x04,
NvmErr = 0x05,
StartUpErr = 0x06,
CompatErr = 0x07,
}
pub struct InternalStatus {
pub message: Message,
pub axes_remap_error: bool,
pub odr_50hz_error: bool,
}
impl InternalStatus {
pub fn from_reg(reg: u8) -> InternalStatus {
InternalStatus {
message: match reg & InternalStatusMask::MESSAGE {
0x00 => Message::NotInit,
0x01 => Message::InitOk,
0x02 => Message::InitErr,
0x03 => Message::DrvErr,
0x04 => Message::SnsErr,
0x05 => Message::NvmErr,
0x06 => Message::StartUpErr,
0x07 => Message::CompatErr,
_ => panic!(), },
axes_remap_error: (reg & InternalStatusMask::AXES_REMAP_ERROR) != 0,
odr_50hz_error: (reg & InternalStatusMask::ODR_50HZ_ERROR) != 0,
}
}
}
pub const FIFO_LENGTH_1_MASK: u8 = 0b0011_1111;
pub struct AccConfMask;
impl AccConfMask {
pub const ACC_ODR: u8 = 0b0000_1111;
pub const ACC_BWP: u8 = 0b0111_0000;
pub const ACC_FILTER_PERF: u8 = 1 << 7;
}
#[repr(u8)]
pub enum Odr {
Odr0p78 = 0x01,
Odr1p5 = 0x02,
Odr3p1 = 0x03,
Odr6p25 = 0x04,
Odr12p5 = 0x05,
Odr25 = 0x06,
Odr50 = 0x07,
Odr100 = 0x08,
Odr200 = 0x09,
Odr400 = 0x0A,
Odr800 = 0x0B,
Odr1k6 = 0x0C,
Odr3k2 = 0x0D,
Odr6k4 = 0x0E,
Odr12k8 = 0x0F,
}
#[repr(u8)]
pub enum AccBwp {
Osr4Avg1 = 0x00,
Osr2Avg2 = 0x01,
NormAvg4 = 0x02,
CicAvg8 = 0x03,
ResAvg16 = 0x04,
ResAvg32 = 0x05,
ResAvg64 = 0x06,
ResAvg128 = 0x07,
}
#[repr(u8)]
pub enum PerfMode {
Power = 0x00,
Perf = 0x01,
}
pub struct AccConf {
pub odr: Odr,
pub bwp: AccBwp,
pub filter_perf: PerfMode,
}
impl AccConf {
pub fn from_reg(reg: u8) -> AccConf {
AccConf {
odr: match reg & AccConfMask::ACC_ODR {
0x01 => Odr::Odr0p78,
0x02 => Odr::Odr1p5,
0x03 => Odr::Odr3p1,
0x04 => Odr::Odr6p25,
0x05 => Odr::Odr12p5,
0x06 => Odr::Odr25,
0x07 => Odr::Odr50,
0x08 => Odr::Odr100,
0x09 => Odr::Odr200,
0x0A => Odr::Odr400,
0x0B => Odr::Odr800,
0x0C => Odr::Odr1k6,
0x0D => Odr::Odr3k2,
0x0E => Odr::Odr6k4,
0x0F => Odr::Odr12k8,
_ => panic!(), },
bwp: match (reg & AccConfMask::ACC_BWP) >> 4 {
0x00 => AccBwp::Osr4Avg1,
0x01 => AccBwp::Osr2Avg2,
0x02 => AccBwp::NormAvg4,
0x03 => AccBwp::CicAvg8,
0x04 => AccBwp::ResAvg16,
0x05 => AccBwp::ResAvg32,
0x06 => AccBwp::ResAvg64,
0x07 => AccBwp::ResAvg128,
_ => panic!(), },
filter_perf: match (reg & AccConfMask::ACC_FILTER_PERF) >> 7 {
0x00 => PerfMode::Power,
0x01 => PerfMode::Perf,
_ => panic!(), },
}
}
pub fn to_reg(self) -> u8 {
let odr = self.odr as u8;
let bwp = self.bwp as u8;
let filter_perf = self.filter_perf as u8;
odr | bwp << 4 | filter_perf << 7
}
}
#[repr(u8)]
pub enum AccRange {
Range2g = 0x00,
Range4g = 0x01,
Range8g = 0x02,
Range16g = 0x03,
}
impl AccRange {
pub fn from_reg(reg: u8) -> AccRange {
match reg {
0x00 => AccRange::Range2g,
0x01 => AccRange::Range4g,
0x02 => AccRange::Range8g,
0x03 => AccRange::Range16g,
_ => panic!(), }
}
}
pub struct GyrConfMask;
impl GyrConfMask {
pub const GYR_ODR: u8 = 0b0000_1111;
pub const GYR_BWP: u8 = 0b0011_0000;
pub const GYR_NOISE_PERF: u8 = 1 << 6;
pub const GYR_FILTER_PERF: u8 = 1 << 7;
}
#[repr(u8)]
pub enum GyrBwp {
Osr4 = 0x00,
Osr2 = 0x01,
Norm = 0x02,
Res = 0x03,
}
pub struct GyrConf {
pub odr: Odr,
pub bwp: GyrBwp,
pub noise_perf: PerfMode,
pub filter_perf: PerfMode,
}
impl GyrConf {
pub fn from_reg(reg: u8) -> GyrConf {
GyrConf {
odr: match reg & GyrConfMask::GYR_ODR {
0x01 => Odr::Odr0p78,
0x02 => Odr::Odr1p5,
0x03 => Odr::Odr3p1,
0x04 => Odr::Odr6p25,
0x05 => Odr::Odr12p5,
0x06 => Odr::Odr25,
0x07 => Odr::Odr50,
0x08 => Odr::Odr100,
0x09 => Odr::Odr200,
0x0A => Odr::Odr400,
0x0B => Odr::Odr800,
0x0C => Odr::Odr1k6,
0x0D => Odr::Odr3k2,
0x0E => Odr::Odr6k4,
0x0F => Odr::Odr12k8,
_ => panic!(), },
bwp: match (reg & GyrConfMask::GYR_BWP) >> 4 {
0x00 => GyrBwp::Osr4,
0x01 => GyrBwp::Osr2,
0x02 => GyrBwp::Norm,
0x03 => GyrBwp::Res,
_ => panic!(), },
noise_perf: match (reg & GyrConfMask::GYR_NOISE_PERF) >> 6 {
0x00 => PerfMode::Power,
0x01 => PerfMode::Perf,
_ => panic!(), },
filter_perf: match (reg & GyrConfMask::GYR_FILTER_PERF) >> 7 {
0x00 => PerfMode::Power,
0x01 => PerfMode::Perf,
_ => panic!(), },
}
}
pub fn to_reg(self) -> u8 {
let odr = self.odr as u8;
let bwp = self.bwp as u8;
let noise_perf = self.noise_perf as u8;
let filter_perf = self.filter_perf as u8;
odr | bwp << 4 | noise_perf << 6 | filter_perf << 7
}
}
pub struct GyrRangeMask;
impl GyrRangeMask {
pub const GYR_RANGE: u8 = 0b0000_0011;
pub const OIS_RANGE: u8 = 1 << 3;
}
#[repr(u8)]
pub enum GyrRangeVal {
Range2000 = 0x00,
Range1000 = 0x01,
Range500 = 0x02,
Range250 = 0x03,
Range125 = 0x04,
}
#[repr(u8)]
pub enum OisRange {
Range250 = 0x00,
Range2000 = 0x01,
}
pub struct GyrRange {
pub range: GyrRangeVal,
pub ois_range: OisRange,
}
impl GyrRange {
pub fn from_reg(reg: u8) -> GyrRange {
GyrRange {
range: match reg & GyrRangeMask::GYR_RANGE {
0x00 => GyrRangeVal::Range2000,
0x01 => GyrRangeVal::Range1000,
0x02 => GyrRangeVal::Range500,
0x03 => GyrRangeVal::Range250,
0x04 => GyrRangeVal::Range125,
_ => panic!(), },
ois_range: match (reg & GyrRangeMask::OIS_RANGE) >> 3 {
0x00 => OisRange::Range250,
0x01 => OisRange::Range2000,
_ => panic!(), },
}
}
pub fn to_reg(self) -> u8 {
let range = self.range as u8;
let ois = self.ois_range as u8;
range | ois << 3
}
}
pub struct AuxConfMask;
impl AuxConfMask {
pub const AUX_ODR: u8 = 0b0000_1111;
pub const AUX_OFFSET: u8 = 0b1111_0000;
}
pub struct AuxConf {
pub odr: Odr,
pub offset: u8,
}
impl AuxConf {
pub fn from_reg(reg: u8) -> AuxConf {
AuxConf {
odr: match reg & AuxConfMask::AUX_ODR {
0x01 => Odr::Odr0p78,
0x02 => Odr::Odr1p5,
0x03 => Odr::Odr3p1,
0x04 => Odr::Odr6p25,
0x05 => Odr::Odr12p5,
0x06 => Odr::Odr25,
0x07 => Odr::Odr50,
0x08 => Odr::Odr100,
0x09 => Odr::Odr200,
0x0A => Odr::Odr400,
0x0B => Odr::Odr800,
0x0C => Odr::Odr1k6,
0x0D => Odr::Odr3k2,
0x0E => Odr::Odr6k4,
0x0F => Odr::Odr12k8,
_ => panic!(), },
offset: (reg & AuxConfMask::AUX_OFFSET) >> 4,
}
}
pub fn to_reg(self) -> u8 {
let odr = self.odr as u8;
let offset = self.offset;
odr | offset << 4
}
}
pub struct FifoDownsMask;
impl FifoDownsMask {
pub const GYR_FIFO_DOWNS: u8 = 0b0000_0111;
pub const GYR_FIFO_FILT_DATA: u8 = 1 << 3;
pub const ACC_FIFO_DOWNS: u8 = 0b0111_0000;
pub const ACC_FIFO_FILT_DATA: u8 = 1 << 7;
}
#[repr(u8)]
pub enum FilterData {
Unfiltered = 0x00,
Filtered = 0x01,
}
pub struct FifoDowns {
pub gyr_downs: u8,
pub gyr_filt_data: FilterData,
pub acc_downs: u8,
pub acc_filt_data: FilterData,
}
impl FifoDowns {
pub fn from_reg(reg: u8) -> FifoDowns {
FifoDowns {
gyr_downs: reg & FifoDownsMask::GYR_FIFO_DOWNS,
gyr_filt_data: match (reg & FifoDownsMask::GYR_FIFO_FILT_DATA) >> 3 {
0x00 => FilterData::Unfiltered,
0x01 => FilterData::Filtered,
_ => panic!(), },
acc_downs: (reg & FifoDownsMask::ACC_FIFO_DOWNS) >> 4,
acc_filt_data: match (reg & FifoDownsMask::ACC_FIFO_FILT_DATA) >> 7 {
0x00 => FilterData::Unfiltered,
0x01 => FilterData::Filtered,
_ => panic!(), },
}
}
pub fn to_reg(self) -> u8 {
let gyr_downs = self.gyr_downs;
let gyr_filt_data = self.gyr_filt_data as u8;
let acc_downs = self.acc_downs;
let acc_filt_data = self.acc_filt_data as u8;
gyr_downs | gyr_filt_data << 3 | acc_downs << 4 | acc_filt_data << 7
}
}
pub struct FifoConfig0Mask;
impl FifoConfig0Mask {
pub const STOP_ON_FULL: u8 = 1;
pub const TIME_EN: u8 = 1 << 1;
}
pub struct FifoConfig1Mask;
impl FifoConfig1Mask {
pub const TAG_INT1_EN: u8 = 0b000_0011;
pub const TAG_INT2_EN: u8 = 0b000_1100;
pub const HEADER_EN: u8 = 1 << 4;
pub const AUX_EN: u8 = 1 << 5;
pub const ACC_EN: u8 = 1 << 6;
pub const GYR_EN: u8 = 1 << 7;
}
#[repr(u8)]
pub enum FifoTagIntEnable {
IntEdge = 0x00,
IntLevel = 0x01,
AccSat = 0x02,
GyrSat = 0x03,
}
pub struct FifoConf {
pub stop_on_full: bool,
pub time_enable: bool,
pub tag_int1_en: FifoTagIntEnable,
pub tag_int2_en: FifoTagIntEnable,
pub header_enable: bool,
pub aux_enable: bool,
pub acc_enable: bool,
pub gyr_enable: bool,
}
impl FifoConf {
pub fn from_regs(reg_0: u8, reg_1: u8) -> FifoConf {
FifoConf {
stop_on_full: (reg_0 & FifoConfig0Mask::STOP_ON_FULL) != 0,
time_enable: (reg_0 & FifoConfig0Mask::TIME_EN) != 0,
tag_int1_en: match reg_1 & FifoConfig1Mask::TAG_INT1_EN {
0x00 => FifoTagIntEnable::IntEdge,
0x01 => FifoTagIntEnable::IntLevel,
0x02 => FifoTagIntEnable::AccSat,
0x03 => FifoTagIntEnable::GyrSat,
_ => panic!(), },
tag_int2_en: match (reg_1 & FifoConfig1Mask::TAG_INT2_EN) >> 2 {
0x00 => FifoTagIntEnable::IntEdge,
0x01 => FifoTagIntEnable::IntLevel,
0x02 => FifoTagIntEnable::AccSat,
0x03 => FifoTagIntEnable::GyrSat,
_ => panic!(), },
header_enable: (reg_1 & FifoConfig1Mask::HEADER_EN) >> 4 != 0,
aux_enable: (reg_1 & FifoConfig1Mask::AUX_EN) >> 5 != 0,
acc_enable: (reg_1 & FifoConfig1Mask::ACC_EN) >> 6 != 0,
gyr_enable: (reg_1 & FifoConfig1Mask::GYR_EN) >> 7 != 0,
}
}
pub fn to_regs(self) -> (u8, u8) {
let stop_on_full: u8 = if self.stop_on_full { 0x01 } else { 0x00 };
let time_enable: u8 = if self.time_enable { 0x01 } else { 0x00 };
let tag_int1_en = self.tag_int1_en as u8;
let tag_int2_en = self.tag_int2_en as u8;
let header_enable = if self.header_enable { 0x01 } else { 0x00 };
let aux_enable: u8 = if self.aux_enable { 0x01 } else { 0x00 };
let acc_enable: u8 = if self.acc_enable { 0x01 } else { 0x00 };
let gyr_enable: u8 = if self.gyr_enable { 0x01 } else { 0x00 };
(
stop_on_full | time_enable << 1,
tag_int1_en
| tag_int2_en << 2
| header_enable << 4
| aux_enable << 5
| acc_enable << 6
| gyr_enable << 7,
)
}
}
pub struct SaturationMask;
impl SaturationMask {
pub const ACC_X: u8 = 1;
pub const ACC_Y: u8 = 1 << 1;
pub const ACC_Z: u8 = 1 << 2;
pub const GYR_X: u8 = 1 << 3;
pub const GYR_Y: u8 = 1 << 4;
pub const GYR_Z: u8 = 1 << 5;
}
pub struct Saturation {
pub acc_x: bool,
pub acc_y: bool,
pub acc_z: bool,
pub gyr_x: bool,
pub gyr_y: bool,
pub gyr_z: bool,
}
impl Saturation {
pub fn from_reg(reg: u8) -> Saturation {
Saturation {
acc_x: reg & SaturationMask::ACC_X != 0,
acc_y: (reg & SaturationMask::ACC_Y) >> 1 != 0,
acc_z: (reg & SaturationMask::ACC_Z) >> 2 != 0,
gyr_x: (reg & SaturationMask::GYR_X) >> 3 != 0,
gyr_y: (reg & SaturationMask::GYR_Y) >> 4 != 0,
gyr_z: (reg & SaturationMask::GYR_Z) >> 5 != 0,
}
}
}
pub struct AuxIfConfMask;
impl AuxIfConfMask {
pub const AUX_RD_BURST: u8 = 0b000_0011;
pub const MAN_RD_BURST: u8 = 0b000_1100;
pub const AUX_FCU_WRITE_EN: u8 = 1 << 6;
pub const AUX_MANUAL_EN: u8 = 1 << 7;
}
#[repr(u8)]
pub enum ReadBurst {
Burst1Byte = 0x00,
Burst2Byte = 0x01,
Burst4Byte = 0x02,
Burst8Byte = 0x03,
}
pub struct AuxIfConf {
pub aux_read_burst: ReadBurst,
pub man_read_burst: ReadBurst,
pub aux_fcu_write_en: bool,
pub aux_manual_en: bool,
}
impl AuxIfConf {
pub fn from_reg(reg: u8) -> AuxIfConf {
AuxIfConf {
aux_read_burst: match reg & AuxIfConfMask::AUX_RD_BURST {
0x00 => ReadBurst::Burst1Byte,
0x01 => ReadBurst::Burst2Byte,
0x02 => ReadBurst::Burst4Byte,
0x03 => ReadBurst::Burst8Byte,
_ => panic!(), },
man_read_burst: match (reg & AuxIfConfMask::MAN_RD_BURST) >> 2 {
0x00 => ReadBurst::Burst1Byte,
0x01 => ReadBurst::Burst2Byte,
0x02 => ReadBurst::Burst4Byte,
0x03 => ReadBurst::Burst8Byte,
_ => panic!(), },
aux_fcu_write_en: (reg & AuxIfConfMask::AUX_FCU_WRITE_EN) >> 6 != 0,
aux_manual_en: (reg & AuxIfConfMask::AUX_MANUAL_EN) >> 7 != 0,
}
}
pub fn to_reg(self) -> u8 {
let aux_read_burst = self.aux_read_burst as u8;
let man_read_burst = self.man_read_burst as u8;
let aux_fcu_write_en = if self.aux_fcu_write_en { 0x01 } else { 0x00 };
let aux_manual_en = if self.aux_manual_en { 0x01 } else { 0x00 };
aux_read_burst | man_read_burst << 2 | aux_fcu_write_en << 6 | aux_manual_en << 7
}
}
pub struct ErrorRegMsk {
pub fatal_err: bool,
pub internal_err: bool,
pub fifo_err: bool,
pub aux_err: bool,
}
impl ErrorRegMsk {
pub fn from_reg(reg: u8) -> ErrorRegMsk {
ErrorRegMsk {
fatal_err: (reg & ErrRegMask::FATAL_ERR) != 0,
internal_err: (reg & ErrRegMask::INTERNAL_ERR) != 0,
fifo_err: (reg & ErrRegMask::FIFO_ERR) != 0,
aux_err: (reg & ErrRegMask::AUX_ERR) != 0,
}
}
pub fn to_reg(self) -> u8 {
let fatal_err = if self.fatal_err { 0x01 } else { 0x00 };
let internal_err = if self.internal_err { 0b0001_1110 } else { 0x00 };
let fifo_err = if self.fifo_err { 0x01 } else { 0x00 };
let aux_err = if self.aux_err { 0x01 } else { 0x00 };
fatal_err | internal_err << 1 | fifo_err << 6 | aux_err << 7
}
}
pub struct IntIoCtrlMask;
impl IntIoCtrlMask {
pub const LEVEL: u8 = 1 << 1;
pub const OD: u8 = 1 << 2;
pub const OUTPUT_EN: u8 = 1 << 3;
pub const INPUT_EN: u8 = 1 << 4;
}
#[repr(u8)]
pub enum OutputLevel {
ActiveLow = 0x00,
ActiveHigh = 0x01,
}
#[repr(u8)]
pub enum OutputBehavior {
PushPull = 0x00,
OpenDrain = 0x01,
}
pub struct IntIoCtrl {
pub level: OutputLevel,
pub od: OutputBehavior,
pub output_en: bool,
pub input_en: bool,
}
impl IntIoCtrl {
pub fn from_reg(reg: u8) -> IntIoCtrl {
IntIoCtrl {
level: match (reg & IntIoCtrlMask::LEVEL) >> 1 {
0x00 => OutputLevel::ActiveLow,
0x01 => OutputLevel::ActiveHigh,
_ => panic!(), },
od: match (reg & IntIoCtrlMask::OD) >> 2 {
0x00 => OutputBehavior::PushPull,
0x01 => OutputBehavior::OpenDrain,
_ => panic!(), },
output_en: (reg & IntIoCtrlMask::OUTPUT_EN) != 0,
input_en: (reg & IntIoCtrlMask::INPUT_EN) != 0,
}
}
pub fn to_reg(self) -> u8 {
let level = self.level as u8;
let od = self.od as u8;
let output_en = if self.output_en { 0x01 } else { 0x00 };
let input_en = if self.input_en { 0x01 } else { 0x00 };
level << 1 | od << 2 | output_en << 3 | input_en << 4
}
}
pub struct IntLatchMask;
impl IntLatchMask {
pub const LATCH: u8 = 1;
}
#[repr(u8)]
pub enum IntLatch {
None = 0x00,
Permanent = 0x01,
}
impl IntLatch {
pub fn from_reg(reg: u8) -> IntLatch {
match reg & IntLatchMask::LATCH {
0x00 => IntLatch::None,
0x01 => IntLatch::Permanent,
_ => panic!(), }
}
}
pub struct IntMapFeatMask;
impl IntMapFeatMask {
pub const SIG_MOTION_OUT: u8 = 1;
pub const STEP_COUNTER_OUT: u8 = 1 << 1;
pub const ACTIVITY_OUT: u8 = 1 << 2;
pub const WRIST_WEAR_WAKEUP_OUT: u8 = 1 << 3;
pub const WRIST_GESTURE_OUT: u8 = 1 << 4;
pub const NO_MOTION_OUT: u8 = 1 << 5;
pub const ANY_MOTION_OUT: u8 = 1 << 6;
}
pub struct IntMapFeat {
pub sig_motion_out: bool,
pub step_counter_out: bool,
pub activity_out: bool,
pub wrist_wear_wakeup_out: bool,
pub wrist_gesture_out: bool,
pub no_motion_out: bool,
pub any_motion_out: bool,
}
impl IntMapFeat {
pub fn from_reg(reg: u8) -> IntMapFeat {
IntMapFeat {
sig_motion_out: (reg & IntMapFeatMask::SIG_MOTION_OUT) != 0,
step_counter_out: (reg & IntMapFeatMask::STEP_COUNTER_OUT) != 0,
activity_out: (reg & IntMapFeatMask::ACTIVITY_OUT) != 0,
wrist_wear_wakeup_out: (reg & IntMapFeatMask::WRIST_WEAR_WAKEUP_OUT) != 0,
wrist_gesture_out: (reg & IntMapFeatMask::WRIST_GESTURE_OUT) != 0,
no_motion_out: (reg & IntMapFeatMask::NO_MOTION_OUT) != 0,
any_motion_out: (reg & IntMapFeatMask::ANY_MOTION_OUT) != 0,
}
}
pub fn to_reg(self) -> u8 {
let sig_motion_out = if self.sig_motion_out { 0x01 } else { 0x00 };
let step_counter_out = if self.step_counter_out { 0x01 } else { 0x00 };
let activity_out = if self.activity_out { 0x01 } else { 0x00 };
let wrist_wear_wakeup_out = if self.wrist_wear_wakeup_out {
0x01
} else {
0x00
};
let wrist_gesture_out = if self.wrist_gesture_out { 0x01 } else { 0x00 };
let no_motion_out = if self.no_motion_out { 0x01 } else { 0x00 };
let any_motion_out = if self.any_motion_out { 0x01 } else { 0x00 };
sig_motion_out
| step_counter_out << 1
| activity_out << 2
| wrist_wear_wakeup_out << 3
| wrist_gesture_out << 4
| no_motion_out << 5
| any_motion_out << 6
}
}
pub struct IntMapDataMask;
impl IntMapDataMask {
pub const FFULL_INT1: u8 = 1;
pub const FWM_INT1: u8 = 1 << 1;
pub const DRDY_INT1: u8 = 1 << 2;
pub const ERR_INT1: u8 = 1 << 3;
pub const FFULL_INT2: u8 = 1 << 4;
pub const FWM_INT2: u8 = 1 << 5;
pub const DRDY_INT2: u8 = 1 << 6;
pub const ERR_INT2: u8 = 1 << 7;
}
pub struct MapData {
pub ffull: bool,
pub fwm: bool,
pub drdy: bool,
pub err: bool,
}
pub struct IntMapData {
pub int1: MapData,
pub int2: MapData,
}
impl IntMapData {
pub fn from_reg(reg: u8) -> IntMapData {
IntMapData {
int1: MapData {
ffull: (reg & IntMapDataMask::FFULL_INT1) != 0,
fwm: (reg & IntMapDataMask::FWM_INT1) != 0,
drdy: (reg & IntMapDataMask::DRDY_INT1) != 0,
err: (reg & IntMapDataMask::ERR_INT1) != 0,
},
int2: MapData {
ffull: (reg & IntMapDataMask::FFULL_INT2) != 0,
fwm: (reg & IntMapDataMask::FWM_INT2) != 0,
drdy: (reg & IntMapDataMask::DRDY_INT2) != 0,
err: (reg & IntMapDataMask::ERR_INT2) != 0,
},
}
}
pub fn to_reg(self) -> u8 {
let ffull_int1 = if self.int1.ffull { 0x01 } else { 0x00 };
let fwm_int1 = if self.int1.fwm { 0x01 } else { 0x00 };
let drdy_int1 = if self.int1.drdy { 0x01 } else { 0x00 };
let err_int1 = if self.int1.err { 0x01 } else { 0x00 };
let ffull_int2 = if self.int2.ffull { 0x01 } else { 0x00 };
let fwm_int2 = if self.int2.fwm { 0x01 } else { 0x00 };
let drdy_int2 = if self.int2.drdy { 0x01 } else { 0x00 };
let err_int2 = if self.int2.err { 0x01 } else { 0x00 };
ffull_int1
| fwm_int1 << 1
| drdy_int1 << 2
| err_int1 << 3
| ffull_int2 << 4
| fwm_int2 << 5
| drdy_int2 << 6
| err_int2 << 7
}
}
pub struct InternalErrorMask;
impl InternalErrorMask {
pub const INT_ERR_1: u8 = 1;
pub const INT_ERR_2: u8 = 1 << 2;
pub const FEAT_ENG_DIS: u8 = 1 << 4;
}
pub struct InternalError {
pub int_err_1: bool,
pub int_err_2: bool,
pub feat_eng_dis: bool,
}
impl InternalError {
pub fn from_reg(reg: u8) -> InternalError {
InternalError {
int_err_1: (reg & InternalErrorMask::INT_ERR_1) != 0,
int_err_2: (reg & InternalErrorMask::INT_ERR_2) >> 2 != 0,
feat_eng_dis: (reg & InternalErrorMask::FEAT_ENG_DIS) >> 4 != 0,
}
}
}
pub struct AuxIfTrimMask;
impl AuxIfTrimMask {
pub const PUPSEL: u8 = 0b0000_0011;
}
#[repr(u8)]
pub enum PullUpConf {
PullUpOff = 0x00,
PullUp40K = 0x01,
PullUp10K = 0x02,
PullUp2K = 0x03,
}
impl PullUpConf {
pub fn from_reg(reg: u8) -> PullUpConf {
match reg & AuxIfTrimMask::PUPSEL {
0x00 => PullUpConf::PullUpOff,
0x01 => PullUpConf::PullUp40K,
0x02 => PullUpConf::PullUp10K,
0x03 => PullUpConf::PullUp2K,
_ => panic!(), }
}
pub fn to_reg(self) -> u8 {
self as u8
}
}
pub struct GyrCrtConfMask;
impl GyrCrtConfMask {
pub const CRT_RUNNING: u8 = 1 << 2;
pub const RDY_FOR_DL: u8 = 1 << 3;
}
#[repr(u8)]
pub enum ReadyForDl {
OnGoing = 0x00,
Complete = 0x01,
}
pub struct GyrCrtConf {
pub crt_running: bool,
pub rdy_for_dl: ReadyForDl,
}
impl GyrCrtConf {
pub fn from_reg(reg: u8) -> GyrCrtConf {
GyrCrtConf {
crt_running: reg & GyrCrtConfMask::CRT_RUNNING >> 2 != 0,
rdy_for_dl: match (reg & GyrCrtConfMask::RDY_FOR_DL) >> 3 {
0x00 => ReadyForDl::OnGoing,
0x01 => ReadyForDl::Complete,
_ => panic!(), },
}
}
pub fn to_reg(self) -> u8 {
let crt_running = if self.crt_running { 0x01 } else { 0x00 };
crt_running << 2
}
}
pub struct IfConfMask;
impl IfConfMask {
pub const SPI3: u8 = 1;
pub const SPI3_OIS: u8 = 1 << 1;
pub const OIS_EN: u8 = 1 << 4;
pub const AUX_EN: u8 = 1 << 5;
}
#[repr(u8)]
pub enum SpiMode {
Spi4 = 0x00,
Spi3 = 0x01,
}
pub struct IfConf {
pub spi_mode: SpiMode,
pub spi_mode_ois: SpiMode,
pub ois_en: bool,
pub aux_en: bool,
}
impl IfConf {
pub fn from_reg(reg: u8) -> IfConf {
IfConf {
spi_mode: match reg & IfConfMask::SPI3 {
0x00 => SpiMode::Spi4,
0x01 => SpiMode::Spi3,
_ => panic!(), },
spi_mode_ois: match (reg & IfConfMask::SPI3_OIS) >> 1 {
0x00 => SpiMode::Spi4,
0x01 => SpiMode::Spi3,
_ => panic!(), },
ois_en: (reg & IfConfMask::OIS_EN) >> 4 != 0,
aux_en: (reg & IfConfMask::AUX_EN) >> 5 != 0,
}
}
pub fn to_reg(self) -> u8 {
let spi_mode = self.spi_mode as u8;
let spi_mode_ois = self.spi_mode_ois as u8;
let ois_en = if self.ois_en { 0x01 } else { 0x00 };
let aux_en = if self.aux_en { 0x01 } else { 0x00 };
spi_mode | spi_mode_ois << 1 | ois_en << 4 | aux_en << 5
}
}
pub struct DrvMask;
impl DrvMask {
pub const IO_PAD_DRV1: u8 = 0b0000_0111;
pub const IO_PAD_I2C_B1: u8 = 1 << 3;
pub const IO_PAD_DRV2: u8 = 0b0111_0000;
pub const IO_PAD_I2C_B2: u8 = 1 << 7;
}
#[repr(u8)]
pub enum DriveStrength {
L0 = 0b000,
L1 = 0b001,
L2 = 0b010,
L3 = 0b011,
L4 = 0b100,
L5 = 0b101,
L6 = 0b110,
L7 = 0b111,
}
pub struct Drv {
pub io_pad_drv1: DriveStrength,
pub io_pad_i2c_b1: bool,
pub io_pad_drv2: DriveStrength,
pub io_pad_i2c_b2: bool,
}
impl Drv {
pub fn from_reg(reg: u8) -> Drv {
Drv {
io_pad_drv1: match reg & DrvMask::IO_PAD_DRV1 {
0b000 => DriveStrength::L0,
0b001 => DriveStrength::L1,
0b010 => DriveStrength::L2,
0b011 => DriveStrength::L3,
0b100 => DriveStrength::L4,
0b101 => DriveStrength::L5,
0b110 => DriveStrength::L6,
0b111 => DriveStrength::L7,
_ => panic!(), },
io_pad_i2c_b1: (reg & DrvMask::IO_PAD_I2C_B1) >> 3 != 0,
io_pad_drv2: match (reg & DrvMask::IO_PAD_DRV2) >> 4 {
0b000 => DriveStrength::L0,
0b001 => DriveStrength::L1,
0b010 => DriveStrength::L2,
0b011 => DriveStrength::L3,
0b100 => DriveStrength::L4,
0b101 => DriveStrength::L5,
0b110 => DriveStrength::L6,
0b111 => DriveStrength::L7,
_ => panic!(), },
io_pad_i2c_b2: (reg & DrvMask::IO_PAD_I2C_B2) >> 7 != 0,
}
}
pub fn to_reg(self) -> u8 {
let io_pad_drv1 = self.io_pad_drv1 as u8;
let io_pad_i2c_b1 = if self.io_pad_i2c_b1 { 0x01 } else { 0x00 };
let io_pad_drv2 = self.io_pad_drv2 as u8;
let io_pad_i2c_b2 = if self.io_pad_i2c_b2 { 0x01 } else { 0x00 };
io_pad_drv1 | io_pad_i2c_b1 << 3 | io_pad_drv2 << 4 | io_pad_i2c_b2 << 7
}
}
pub struct AccSelfTestMask;
impl AccSelfTestMask {
pub const ACC_SELF_TEST_EN: u8 = 1;
pub const ACC_SELF_TEST_SIGN: u8 = 1 << 2;
pub const ACC_SELF_TEST_AMP: u8 = 1 << 3;
}
#[repr(u8)]
pub enum Sign {
Negative = 0x00,
Positive = 0x01,
}
#[repr(u8)]
pub enum Amplitude {
Low = 0x00,
High = 0x01,
}
pub struct AccSelfTest {
pub enable: bool,
pub sign: Sign,
pub amplitude: Amplitude,
}
impl AccSelfTest {
pub fn from_reg(reg: u8) -> AccSelfTest {
AccSelfTest {
enable: (reg & AccSelfTestMask::ACC_SELF_TEST_EN) != 0,
sign: match (reg & AccSelfTestMask::ACC_SELF_TEST_SIGN) >> 2 {
0x00 => Sign::Negative,
0x01 => Sign::Positive,
_ => panic!(), },
amplitude: match (reg & AccSelfTestMask::ACC_SELF_TEST_AMP) >> 3 {
0x00 => Amplitude::Low,
0x01 => Amplitude::High,
_ => panic!(), },
}
}
pub fn to_reg(self) -> u8 {
let enable = if self.enable { 0x01 } else { 0x00 };
let sign = self.sign as u8;
let amplitude = self.amplitude as u8;
enable | sign << 2 | amplitude << 3
}
}
pub struct GyrSelfTestMask;
impl GyrSelfTestMask {
pub const GYR_ST_AXES_DONE: u8 = 1;
pub const GYR_AXIS_X_OK: u8 = 1 << 1;
pub const GYR_AXIS_Y_OK: u8 = 1 << 2;
pub const GYR_AXIS_Z_OK: u8 = 1 << 3;
}
pub struct GyrSelfTest {
pub done: bool,
pub x_ok: bool,
pub y_ok: bool,
pub z_ok: bool,
}
impl GyrSelfTest {
pub fn from_reg(reg: u8) -> GyrSelfTest {
GyrSelfTest {
done: (reg & GyrSelfTestMask::GYR_ST_AXES_DONE) != 0,
x_ok: (reg & GyrSelfTestMask::GYR_AXIS_X_OK) != 0,
y_ok: (reg & GyrSelfTestMask::GYR_AXIS_Y_OK) != 0,
z_ok: (reg & GyrSelfTestMask::GYR_AXIS_Z_OK) != 0,
}
}
}
pub struct NvConfMask;
impl NvConfMask {
pub const SPI_EN: u8 = 1;
pub const I2C_WDT_SEL: u8 = 1 << 1;
pub const I2C_WDT_EN: u8 = 1 << 2;
pub const ACC_OFF_EN: u8 = 1 << 3;
}
#[repr(u8)]
pub enum TimePedriod {
Short1_25Ms = 0x00,
Long40Ms = 0x01,
}
pub struct NvConf {
pub spi_en: bool,
pub i2c_wdt_sel: TimePedriod,
pub i2c_wdt_en: bool,
pub acc_off_en: bool,
}
impl NvConf {
pub fn from_reg(reg: u8) -> NvConf {
NvConf {
spi_en: (reg & NvConfMask::SPI_EN) != 0,
i2c_wdt_sel: match (reg & NvConfMask::I2C_WDT_SEL) >> 1 {
0x00 => TimePedriod::Short1_25Ms,
0x01 => TimePedriod::Long40Ms,
_ => panic!(), },
i2c_wdt_en: (reg & NvConfMask::I2C_WDT_EN) != 0,
acc_off_en: (reg & NvConfMask::ACC_OFF_EN) != 0,
}
}
pub fn to_reg(self) -> u8 {
let spi_en = if self.spi_en { 0x01 } else { 0x00 };
let i2c_wdt_sel = self.i2c_wdt_sel as u8;
let i2c_wdt_en = if self.i2c_wdt_en { 0x01 } else { 0x00 };
let acc_off_en = if self.acc_off_en { 0x01 } else { 0x00 };
spi_en | i2c_wdt_sel << 1 | i2c_wdt_en << 2 | acc_off_en << 3
}
}
pub struct AccOffsets {
pub x: u8,
pub y: u8,
pub z: u8,
}
pub struct GyrOffsets {
pub x: u16,
pub y: u16,
pub z: u16,
pub offset_en: bool,
pub gain_en: bool,
}
pub struct PwrConfMask;
impl PwrConfMask {
pub const ADV_PWR_SAVE: u8 = 1;
pub const FIFO_SELF_WAKE_UP: u8 = 1 << 1;
pub const FUP_EN: u8 = 1 << 2;
}
pub struct PwrConf {
pub power_save: bool,
pub fifo_self_wake_up: bool,
pub fup_en: bool,
}
impl PwrConf {
pub fn from_reg(reg: u8) -> PwrConf {
PwrConf {
power_save: (reg & PwrConfMask::ADV_PWR_SAVE) != 0,
fifo_self_wake_up: (reg & PwrConfMask::FIFO_SELF_WAKE_UP) != 0,
fup_en: (reg & PwrConfMask::FUP_EN) != 0,
}
}
pub fn to_reg(self) -> u8 {
let power_save = if self.power_save { 0x01 } else { 0x00 };
let fifo_self_wake_up = if self.fifo_self_wake_up { 0x01 } else { 0x00 };
let fup_en = if self.fup_en { 0x01 } else { 0x00 };
power_save | fifo_self_wake_up << 1 | fup_en << 2
}
}
pub struct PwrCtrlMask;
impl PwrCtrlMask {
pub const AUX_EN: u8 = 1;
pub const GYR_EN: u8 = 1 << 1;
pub const ACC_EN: u8 = 1 << 2;
pub const TEMP_EN: u8 = 1 << 3;
}
pub struct PwrCtrl {
pub aux_en: bool,
pub gyr_en: bool,
pub acc_en: bool,
pub temp_en: bool,
}
impl PwrCtrl {
pub fn from_reg(reg: u8) -> PwrCtrl {
PwrCtrl {
aux_en: (reg & PwrCtrlMask::AUX_EN) != 0,
gyr_en: (reg & PwrCtrlMask::GYR_EN) != 0,
acc_en: (reg & PwrCtrlMask::ACC_EN) != 0,
temp_en: (reg & PwrCtrlMask::TEMP_EN) != 0,
}
}
pub fn to_reg(self) -> u8 {
let aux_en = if self.aux_en { 0x01 } else { 0x00 };
let gyr_en = if self.gyr_en { 0x01 } else { 0x00 };
let acc_en = if self.acc_en { 0x01 } else { 0x00 };
let temp_en = if self.temp_en { 0x01 } else { 0x00 };
aux_en | gyr_en << 1 | acc_en << 2 | temp_en << 3
}
}
#[repr(u8)]
pub enum Cmd {
GTrigger = 0x02,
UsrGain = 0x03,
NvmProg = 0xA0,
FifoFlush = 0xB0,
SoftReset = 0xB6,
}