use bma400::{BMA400, SPIInterface, types::*};
use embedded_hal_mock::eh1::{
delay::{CheckedDelay, Transaction as DelayTransaction},
spi::{Mock as MockSPI, Transaction},
};
struct Transactions(Vec<Transaction<u8>>);
impl Transactions {
fn push_read(&mut self, addr: u8, expected: Vec<u8>) {
let inner = &mut self.0;
inner.push(Transaction::transaction_start());
inner.push(Transaction::write_vec(vec![addr, 0x00]));
inner.push(Transaction::read_vec(expected));
inner.push(Transaction::transaction_end());
}
fn push_write(&mut self, addr: u8, expected: &mut Vec<u8>) {
let inner = &mut self.0;
let mut write = Vec::with_capacity(expected.len() + 1);
write.push(addr);
write.append(expected);
inner.push(Transaction::transaction_start());
inner.push(Transaction::write_vec(write));
inner.push(Transaction::transaction_end());
}
}
fn new(expected_io: &Transactions) -> BMA400<SPIInterface<MockSPI<u8>>> {
let spi = MockSPI::new(&expected_io.0);
BMA400::new_spi(spi).unwrap()
}
fn cleanup(device: BMA400<SPIInterface<MockSPI<u8>>>) {
device.destroy().destroy().done();
}
#[test]
fn init_bad_chip_id() {
let mut expected_io = Transactions(Vec::new());
expected_io.push_read(0x80, vec![0x00]);
expected_io.push_read(0x80, vec![0x89]);
let mut spi = MockSPI::new(&expected_io.0);
let result = BMA400::new_spi(&mut spi);
assert!(matches!(result, Err(BMA400Error::ChipIdReadFailed)));
spi.done();
}
fn init(expected_io: &mut Transactions) {
expected_io.push_read(0x80, vec![0x00]);
expected_io.push_read(0x80, vec![0x90]);
}
#[test]
fn destroy() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
init(&mut expected_io);
let mut spi = MockSPI::new(&expected_io.0);
let device = BMA400::new_spi(spi).unwrap();
let iface = device.destroy();
spi = iface.destroy();
BMA400::new_spi(&mut spi).unwrap();
spi.done();
}
#[test]
fn get_chip_id() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x80, vec![0x90]);
let mut device = new(&expected_io);
let id = device.get_id().unwrap();
assert_eq!(id, 0x90);
cleanup(device);
}
#[test]
fn get_cmd_error() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x82, vec![0xFD]);
expected_io.push_read(0x82, vec![0x02]);
let mut device = new(&expected_io);
let status = device.get_cmd_error().unwrap();
assert!(!status);
let status = device.get_cmd_error().unwrap();
assert!(status);
cleanup(device);
}
#[test]
fn get_status() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x83, vec![0x80]);
expected_io.push_read(0x83, vec![0x10]);
expected_io.push_read(0x83, vec![0x02]);
expected_io.push_read(0x83, vec![0x04]);
expected_io.push_read(0x83, vec![0x01]);
let mut device = new(&expected_io);
let status = device.get_status().unwrap();
assert!(status.drdy_stat());
assert!(!status.cmd_rdy());
assert!(!status.int_active());
assert!(matches!(status.power_mode(), PowerMode::Sleep));
let status = device.get_status().unwrap();
assert!(!status.drdy_stat());
assert!(status.cmd_rdy());
assert!(!status.int_active());
assert!(matches!(status.power_mode(), PowerMode::Sleep));
let status = device.get_status().unwrap();
assert!(!status.drdy_stat());
assert!(!status.cmd_rdy());
assert!(!status.int_active());
assert!(matches!(status.power_mode(), PowerMode::LowPower));
let status = device.get_status().unwrap();
assert!(!status.drdy_stat());
assert!(!status.cmd_rdy());
assert!(!status.int_active());
assert!(matches!(status.power_mode(), PowerMode::Normal));
let status = device.get_status().unwrap();
assert!(!status.drdy_stat());
assert!(!status.cmd_rdy());
assert!(status.int_active());
assert!(matches!(status.power_mode(), PowerMode::Sleep));
cleanup(device);
}
#[test]
fn get_unscaled_data() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x84, vec![0x01, 0x08, 0xFF, 0x0F, 0xFF, 0x07]);
let mut device = new(&expected_io);
let m = device.get_unscaled_data().unwrap();
assert_eq!(m.x, -2047);
assert_eq!(m.y, -1);
assert_eq!(m.z, 2047);
cleanup(device);
}
fn get_scaled_data(scale: Scale) -> (i16, i16, i16) {
let byte = match scale {
Scale::Range2G => 0x09,
Scale::Range4G => 0x49,
Scale::Range8G => 0x89,
Scale::Range16G => 0xC9,
};
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
if let Scale::Range4G = scale {
expected_io.push_read(0x84, vec![0x01, 0x08, 0xFF, 0x0F, 0xFF, 0x07]);
} else {
expected_io.push_write(0x1A, &mut vec![byte]);
expected_io.push_read(0x84, vec![0x01, 0x08, 0xFF, 0x0F, 0xFF, 0x07]);
}
let mut device = new(&expected_io);
device.config_accel().with_scale(scale).write().unwrap();
let m = device.get_data().unwrap();
cleanup(device);
(m.x, m.y, m.z)
}
#[test]
fn get_data() {
assert_eq!((-2047, -1, 2047), get_scaled_data(Scale::Range2G));
assert_eq!((-4094, -2, 4094), get_scaled_data(Scale::Range4G));
assert_eq!((-8188, -4, 8188), get_scaled_data(Scale::Range8G));
assert_eq!((-16376, -8, 16376), get_scaled_data(Scale::Range16G));
}
#[test]
fn get_sensor_clock() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x8A, vec![0xF8, 0xFF, 0xFF]);
let mut device = new(&expected_io);
let t = device.get_sensor_clock().unwrap();
assert_eq!(t, 0xFFFFF8);
cleanup(device);
}
#[test]
fn get_reset_status() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x8D, vec![0x00]);
expected_io.push_read(0x8D, vec![0x01]);
let mut device = new(&expected_io);
let reset = device.get_reset_status().unwrap();
assert!(!reset);
let reset = device.get_reset_status().unwrap();
assert!(reset);
cleanup(device);
}
#[test]
fn get_int_status0() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x8E, vec![0x80]);
expected_io.push_read(0x8E, vec![0x40]);
expected_io.push_read(0x8E, vec![0x20]);
expected_io.push_read(0x8E, vec![0x10]);
expected_io.push_read(0x8E, vec![0x08]);
expected_io.push_read(0x8E, vec![0x04]);
expected_io.push_read(0x8E, vec![0x02]);
expected_io.push_read(0x8E, vec![0x01]);
let mut device = new(&expected_io);
let status = device.get_int_status0().unwrap();
assert!(status.drdy_stat());
assert!(!status.fwm_stat());
assert!(!status.ffull_stat());
assert!(!status.ieng_overrun_stat());
assert!(!status.gen2_stat());
assert!(!status.gen1_stat());
assert!(!status.orientch_stat());
assert!(!status.wkup_stat());
let status = device.get_int_status0().unwrap();
assert!(!status.drdy_stat());
assert!(status.fwm_stat());
assert!(!status.ffull_stat());
assert!(!status.ieng_overrun_stat());
assert!(!status.gen2_stat());
assert!(!status.gen1_stat());
assert!(!status.orientch_stat());
assert!(!status.wkup_stat());
let status = device.get_int_status0().unwrap();
assert!(!status.drdy_stat());
assert!(!status.fwm_stat());
assert!(status.ffull_stat());
assert!(!status.ieng_overrun_stat());
assert!(!status.gen2_stat());
assert!(!status.gen1_stat());
assert!(!status.orientch_stat());
assert!(!status.wkup_stat());
let status = device.get_int_status0().unwrap();
assert!(!status.drdy_stat());
assert!(!status.fwm_stat());
assert!(!status.ffull_stat());
assert!(status.ieng_overrun_stat());
assert!(!status.gen2_stat());
assert!(!status.gen1_stat());
assert!(!status.orientch_stat());
assert!(!status.wkup_stat());
let status = device.get_int_status0().unwrap();
assert!(!status.drdy_stat());
assert!(!status.fwm_stat());
assert!(!status.ffull_stat());
assert!(!status.ieng_overrun_stat());
assert!(status.gen2_stat());
assert!(!status.gen1_stat());
assert!(!status.orientch_stat());
assert!(!status.wkup_stat());
let status = device.get_int_status0().unwrap();
assert!(!status.drdy_stat());
assert!(!status.fwm_stat());
assert!(!status.ffull_stat());
assert!(!status.ieng_overrun_stat());
assert!(!status.gen2_stat());
assert!(status.gen1_stat());
assert!(!status.orientch_stat());
assert!(!status.wkup_stat());
let status = device.get_int_status0().unwrap();
assert!(!status.drdy_stat());
assert!(!status.fwm_stat());
assert!(!status.ffull_stat());
assert!(!status.ieng_overrun_stat());
assert!(!status.gen2_stat());
assert!(!status.gen1_stat());
assert!(status.orientch_stat());
assert!(!status.wkup_stat());
let status = device.get_int_status0().unwrap();
assert!(!status.drdy_stat());
assert!(!status.fwm_stat());
assert!(!status.ffull_stat());
assert!(!status.ieng_overrun_stat());
assert!(!status.gen2_stat());
assert!(!status.gen1_stat());
assert!(!status.orientch_stat());
assert!(status.wkup_stat());
cleanup(device);
}
#[test]
fn get_int_status1() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x8F, vec![0x10]);
expected_io.push_read(0x8F, vec![0x08]);
expected_io.push_read(0x8F, vec![0x04]);
expected_io.push_read(0x8F, vec![0x02]);
expected_io.push_read(0x8F, vec![0x01]);
let mut device = new(&expected_io);
let status = device.get_int_status1().unwrap();
assert!(status.ieng_overrun_stat());
assert!(!status.d_tap_stat());
assert!(!status.s_tap_stat());
assert!(matches!(status.step_int_stat(), StepIntStatus::None));
let status = device.get_int_status1().unwrap();
assert!(!status.ieng_overrun_stat());
assert!(status.d_tap_stat());
assert!(!status.s_tap_stat());
assert!(matches!(status.step_int_stat(), StepIntStatus::None));
let status = device.get_int_status1().unwrap();
assert!(!status.ieng_overrun_stat());
assert!(!status.d_tap_stat());
assert!(status.s_tap_stat());
assert!(matches!(status.step_int_stat(), StepIntStatus::None));
let status = device.get_int_status1().unwrap();
assert!(!status.ieng_overrun_stat());
assert!(!status.d_tap_stat());
assert!(!status.s_tap_stat());
assert!(matches!(
status.step_int_stat(),
StepIntStatus::ManyStepDetect
));
let status = device.get_int_status1().unwrap();
assert!(!status.ieng_overrun_stat());
assert!(!status.d_tap_stat());
assert!(!status.s_tap_stat());
assert!(matches!(
status.step_int_stat(),
StepIntStatus::OneStepDetect
));
cleanup(device);
}
#[test]
fn get_int_status2() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x90, vec![0x10]);
expected_io.push_read(0x90, vec![0x04]);
expected_io.push_read(0x90, vec![0x02]);
expected_io.push_read(0x90, vec![0x01]);
let mut device = new(&expected_io);
let status = device.get_int_status2().unwrap();
assert!(status.ieng_overrun_stat());
assert!(!status.actch_z_stat());
assert!(!status.actch_y_stat());
assert!(!status.actch_x_stat());
let status = device.get_int_status2().unwrap();
assert!(!status.ieng_overrun_stat());
assert!(status.actch_z_stat());
assert!(!status.actch_y_stat());
assert!(!status.actch_x_stat());
let status = device.get_int_status2().unwrap();
assert!(!status.ieng_overrun_stat());
assert!(!status.actch_z_stat());
assert!(status.actch_y_stat());
assert!(!status.actch_x_stat());
let status = device.get_int_status2().unwrap();
assert!(!status.ieng_overrun_stat());
assert!(!status.actch_z_stat());
assert!(!status.actch_y_stat());
assert!(status.actch_x_stat());
cleanup(device);
}
#[test]
fn get_fifo_len() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x92, vec![0x00, 0xF4]);
expected_io.push_read(0x92, vec![0x80, 0x02]);
let mut device = new(&expected_io);
let len = device.get_fifo_len().unwrap();
assert_eq!(len, 1024);
let len = device.get_fifo_len().unwrap();
assert_eq!(len, 640);
cleanup(device);
}
#[test]
fn read_fifo_frames() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(
0x94,
vec![
0x48, 0x6E, 0x9E, 0x01, 0x80, 0x0F, 0xFF, 0x0F, 0x7F, 0xA0, 0xF8, 0xFF, 0xFF, 0x80,
0x00,
],
);
let mut device = new(&expected_io);
let mut buffer = [0u8; 15];
let frames = device.read_fifo_frames(&mut buffer).unwrap();
let mut count = 0;
for frame in frames {
match frame.frame_type() {
FrameType::Data => {
assert_eq!(frame.x(), Some(-2047));
assert_eq!(frame.y(), Some(-1));
assert_eq!(frame.z(), Some(2047));
}
FrameType::Time => {
assert_eq!(frame.time(), Some(0xFFFFF8));
}
FrameType::Control => {
assert!(frame.fifo_src_chg().unwrap());
assert!(frame.filt1_bw_chg().unwrap());
assert!(frame.acc1_chg().unwrap());
}
}
count += 1;
}
assert_eq!(count, 3);
cleanup(device);
}
#[test]
fn flush_fifo() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x7E, &mut vec![0xB0]);
let mut device = new(&expected_io);
device.flush_fifo().unwrap();
cleanup(device);
}
#[test]
fn get_step_count() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x95, vec![0x00, 0xFF, 0xF0]);
let mut device = new(&expected_io);
let count = device.get_step_count().unwrap();
assert_eq!(count, 15793920);
cleanup(device);
}
#[test]
fn clear_step_count() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x7E, &mut vec![0xB1]);
let mut device = new(&expected_io);
device.clear_step_count().unwrap();
cleanup(device);
}
#[test]
fn get_step_activity() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x98, vec![0x01]);
expected_io.push_read(0x98, vec![0x02]);
expected_io.push_read(0x98, vec![0x00]);
let mut device = new(&expected_io);
let activity = device.get_step_activity().unwrap();
assert!(matches!(activity, Activity::Walk));
let activity = device.get_step_activity().unwrap();
assert!(matches!(activity, Activity::Run));
let activity = device.get_step_activity().unwrap();
assert!(matches!(activity, Activity::Still));
cleanup(device);
}
#[test]
fn get_raw_temp() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_read(0x91, vec![0xD0]);
expected_io.push_read(0x91, vec![0x7F]);
let mut device = new(&expected_io);
let temp = device.get_raw_temp().unwrap();
assert_eq!(temp, -48);
let temp = device.get_raw_temp().unwrap();
assert_eq!(temp, 127);
cleanup(device);
}
#[test]
fn config_accel() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x19, &mut vec![0xE2]);
expected_io.push_write(0x1A, &mut vec![0xFB]);
expected_io.push_write(0x1B, &mut vec![0x08]);
expected_io.push_write(0x19, &mut vec![0x00]);
expected_io.push_write(0x1A, &mut vec![0x05]);
expected_io.push_write(0x1B, &mut vec![0x00]);
let mut device = new(&expected_io);
device
.config_accel()
.with_filt1_bw(Filter1Bandwidth::Low)
.with_osr_lp(OversampleRate::OSR3)
.with_power_mode(PowerMode::Normal)
.with_scale(Scale::Range16G)
.with_osr(OversampleRate::OSR3)
.with_odr(OutputDataRate::Hz800)
.with_reg_dta_src(DataSource::AccFilt2Lp)
.write()
.unwrap();
device
.config_accel()
.with_filt1_bw(Filter1Bandwidth::High)
.with_osr_lp(OversampleRate::OSR0)
.with_power_mode(PowerMode::Sleep)
.with_scale(Scale::Range2G)
.with_osr(OversampleRate::OSR0)
.with_odr(OutputDataRate::Hz12_5)
.with_reg_dta_src(DataSource::AccFilt1)
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_interrupts() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x56, &mut vec![0x10]);
expected_io.push_write(0x3F, &mut vec![0x10]);
expected_io.push_write(0x4A, &mut vec![0x10]);
expected_io.push_write(0x1F, &mut vec![0xEE]);
expected_io.push_write(0x20, &mut vec![0x9D]);
expected_io.push_write(0x1F, &mut vec![0x00]);
expected_io.push_write(0x20, &mut vec![0x00]);
let mut device = new(&expected_io);
device
.config_actchg_int()
.with_src(DataSource::AccFilt2)
.write()
.unwrap();
device
.config_gen1_int()
.with_src(DataSource::AccFilt2)
.write()
.unwrap();
device
.config_gen2_int()
.with_src(DataSource::AccFilt2)
.write()
.unwrap();
device
.config_interrupts()
.with_actch_int(true)
.with_d_tap_int(true)
.with_dta_rdy_int(true)
.with_ffull_int(true)
.with_fwm_int(true)
.with_gen1_int(true)
.with_gen2_int(true)
.with_latch_int(true)
.with_orientch_int(true)
.with_s_tap_int(true)
.with_step_int(true)
.write()
.unwrap();
device
.config_interrupts()
.with_actch_int(false)
.with_d_tap_int(false)
.with_dta_rdy_int(false)
.with_ffull_int(false)
.with_fwm_int(false)
.with_gen1_int(false)
.with_gen2_int(false)
.with_latch_int(false)
.with_orientch_int(false)
.with_s_tap_int(false)
.with_step_int(false)
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_int_pins() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x21, &mut vec![0xFF]);
expected_io.push_write(0x22, &mut vec![0xFF]);
expected_io.push_write(0x23, &mut vec![0xDD]);
expected_io.push_write(0x24, &mut vec![0x66]);
expected_io.push_write(0x21, &mut vec![0x00]);
expected_io.push_write(0x23, &mut vec![0xD0]);
expected_io.push_write(0x24, &mut vec![0x60]);
expected_io.push_write(0x22, &mut vec![0x00]);
expected_io.push_write(0x23, &mut vec![0x00]);
expected_io.push_write(0x24, &mut vec![0x00]);
let mut device = new(&expected_io);
device
.config_int_pins()
.with_drdy(InterruptPins::Both)
.with_fifo_wm(InterruptPins::Both)
.with_ffull(InterruptPins::Both)
.with_ieng_ovrrn(InterruptPins::Both)
.with_gen2(InterruptPins::Both)
.with_gen1(InterruptPins::Both)
.with_orientch(InterruptPins::Both)
.with_wkup(InterruptPins::Both)
.with_actch(InterruptPins::Both)
.with_tap(InterruptPins::Both)
.with_step(InterruptPins::Both)
.with_int1_cfg(PinOutputConfig::OpenDrain(PinOutputLevel::ActiveHigh))
.with_int2_cfg(PinOutputConfig::OpenDrain(PinOutputLevel::ActiveHigh))
.write()
.unwrap();
device
.config_int_pins()
.with_drdy(InterruptPins::Int2)
.with_fifo_wm(InterruptPins::Int2)
.with_ffull(InterruptPins::Int2)
.with_ieng_ovrrn(InterruptPins::Int2)
.with_gen2(InterruptPins::Int2)
.with_gen1(InterruptPins::Int2)
.with_orientch(InterruptPins::Int2)
.with_wkup(InterruptPins::Int2)
.with_actch(InterruptPins::Int2)
.with_tap(InterruptPins::Int2)
.with_step(InterruptPins::Int2)
.with_int1_cfg(PinOutputConfig::PushPull(PinOutputLevel::ActiveLow))
.write()
.unwrap();
device
.config_int_pins()
.with_drdy(InterruptPins::None)
.with_fifo_wm(InterruptPins::None)
.with_ffull(InterruptPins::None)
.with_ieng_ovrrn(InterruptPins::None)
.with_gen2(InterruptPins::None)
.with_gen1(InterruptPins::None)
.with_orientch(InterruptPins::None)
.with_wkup(InterruptPins::None)
.with_actch(InterruptPins::None)
.with_tap(InterruptPins::None)
.with_step(InterruptPins::None)
.with_int2_cfg(PinOutputConfig::PushPull(PinOutputLevel::ActiveLow))
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_fifo() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x26, &mut vec![0xFF]);
expected_io.push_write(0x27, &mut vec![0xFF]);
expected_io.push_write(0x28, &mut vec![0x03]);
expected_io.push_write(0x29, &mut vec![0x01]);
expected_io.push_write(0x26, &mut vec![0x00]);
expected_io.push_write(0x27, &mut vec![0x00]);
expected_io.push_write(0x28, &mut vec![0x00]);
expected_io.push_write(0x29, &mut vec![0x00]);
let mut device = new(&expected_io);
device
.config_fifo()
.with_8bit_mode(true)
.with_axes(true, true, true)
.with_src(DataSource::AccFilt2)
.with_send_time_on_empty(true)
.with_stop_on_full(true)
.with_auto_flush(true)
.with_watermark_thresh(1023)
.with_read_disabled(true)
.write()
.unwrap();
device
.config_fifo()
.with_8bit_mode(false)
.with_axes(false, false, false)
.with_src(DataSource::AccFilt1)
.with_send_time_on_empty(false)
.with_stop_on_full(false)
.with_auto_flush(false)
.with_watermark_thresh(0)
.with_read_disabled(false)
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_auto_lp() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x2A, &mut vec![0xFF]);
expected_io.push_write(0x2B, &mut vec![0xFB]);
expected_io.push_write(0x2A, &mut vec![0x00]);
expected_io.push_write(0x2B, &mut vec![0x00]);
let mut device = new(&expected_io);
device
.config_auto_lp()
.with_timeout(0xFFF)
.with_auto_lp_trigger(AutoLPTimeoutTrigger::TimeoutEnabledGen2IntReset)
.with_drdy_trigger(true)
.with_gen1_int_trigger(true)
.write()
.unwrap();
device
.config_auto_lp()
.with_timeout(0)
.with_auto_lp_trigger(AutoLPTimeoutTrigger::TimeoutDisabled)
.with_drdy_trigger(false)
.with_gen1_int_trigger(false)
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_autowkup() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x2C, &mut vec![0xFF]);
expected_io.push_write(0x2D, &mut vec![0xF6]);
expected_io.push_write(0x2C, &mut vec![0x00]);
expected_io.push_write(0x2D, &mut vec![0x00]);
let mut device = new(&expected_io);
device
.config_autowkup()
.with_wakeup_period(0xFFF)
.with_periodic_wakeup(true)
.with_activity_int(true)
.write()
.unwrap();
device
.config_autowkup()
.with_wakeup_period(0)
.with_periodic_wakeup(false)
.with_activity_int(false)
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_wkup_int() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x30, &mut vec![0xFF]);
expected_io.push_write(0x31, &mut vec![0xFF]);
expected_io.push_write(0x32, &mut vec![0xFF]);
expected_io.push_write(0x33, &mut vec![0xFF]);
expected_io.push_write(0x2F, &mut vec![0xFE]);
expected_io.push_write(0x2F, &mut vec![0x1E]);
expected_io.push_write(0x30, &mut vec![0x00]);
expected_io.push_write(0x31, &mut vec![0x00]);
expected_io.push_write(0x32, &mut vec![0x00]);
expected_io.push_write(0x33, &mut vec![0x00]);
expected_io.push_write(0x2F, &mut vec![0x00]);
let mut device = new(&expected_io);
device
.config_wkup_int()
.with_axes(true, true, true)
.with_num_samples(8)
.with_ref_mode(WakeupIntRefMode::EveryTime)
.with_threshold(0xFF)
.with_ref_accel(-1, -1, -1)
.write()
.unwrap();
device
.config_wkup_int()
.with_axes(false, false, false)
.with_num_samples(1)
.with_ref_mode(WakeupIntRefMode::Manual)
.with_threshold(0)
.with_ref_accel(0, 0, 0)
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_orientchg_int() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
let mut write = |mut bytes: Vec<u8>| {
let (addr, expected) = bytes.split_first_mut().unwrap();
expected_io.push_write(*addr, &mut expected.into());
};
write(vec![0x35, 0xF8]);
write(vec![0x36, 0xFF]);
write(vec![0x38, 0xFF]);
write(vec![0x39, 0xFF]);
write(vec![0x3A, 0x0F]);
write(vec![0x3B, 0xFF]);
write(vec![0x3C, 0x0F]);
write(vec![0x3D, 0xFF]);
write(vec![0x3E, 0x0F]);
write(vec![0x35, 0x00]);
write(vec![0x36, 0x00]);
write(vec![0x38, 0x00]);
write(vec![0x39, 0x00]);
write(vec![0x3A, 0x00]);
write(vec![0x3B, 0x00]);
write(vec![0x3C, 0x00]);
write(vec![0x3D, 0x00]);
write(vec![0x3E, 0x00]);
let mut device = new(&expected_io);
device
.config_orientchg_int()
.with_axes(true, true, true)
.with_src(DataSource::AccFilt2Lp)
.with_ref_mode(OrientIntRefMode::AccFilt2Lp)
.with_threshold(0xFF)
.with_duration(0xFF)
.with_ref_accel(-1, -1, -1)
.write()
.unwrap();
device
.config_orientchg_int()
.with_axes(false, false, false)
.with_src(DataSource::AccFilt2)
.with_ref_mode(OrientIntRefMode::Manual)
.with_threshold(0)
.with_duration(0)
.with_ref_accel(0, 0, 0)
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_gen1_int() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
let mut write = |mut bytes: Vec<u8>| {
let (addr, expected) = bytes.split_first_mut().unwrap();
expected_io.push_write(*addr, &mut expected.into());
};
write(vec![0x3F, 0xFF]);
write(vec![0x40, 0x03]);
write(vec![0x41, 0xFF]);
write(vec![0x42, 0xFF]);
write(vec![0x43, 0xFF]);
write(vec![0x44, 0xFF]);
write(vec![0x45, 0x0F]);
write(vec![0x46, 0xFF]);
write(vec![0x47, 0x0F]);
write(vec![0x48, 0xFF]);
write(vec![0x49, 0x0F]);
write(vec![0x3F, 0x00]);
write(vec![0x40, 0x00]);
write(vec![0x41, 0x00]);
write(vec![0x42, 0x00]);
write(vec![0x43, 0x00]);
write(vec![0x44, 0x00]);
write(vec![0x45, 0x00]);
write(vec![0x46, 0x00]);
write(vec![0x47, 0x00]);
write(vec![0x48, 0x00]);
write(vec![0x49, 0x00]);
let mut device = new(&expected_io);
device
.config_gen1_int()
.with_axes(true, true, true)
.with_src(DataSource::AccFilt2)
.with_ref_mode(GenIntRefMode::EveryTimeFromLp)
.with_hysteresis(Hysteresis::Hyst96mg)
.with_criterion_mode(GenIntCriterionMode::Activity)
.with_logic_mode(GenIntLogicMode::And)
.with_threshold(0xFF)
.with_duration(0xFFFF)
.with_ref_accel(-1, -1, -1)
.write()
.unwrap();
device
.config_gen1_int()
.with_axes(false, false, false)
.with_src(DataSource::AccFilt1)
.with_ref_mode(GenIntRefMode::Manual)
.with_hysteresis(Hysteresis::None)
.with_criterion_mode(GenIntCriterionMode::Inactivity)
.with_logic_mode(GenIntLogicMode::Or)
.with_threshold(0)
.with_duration(0)
.with_ref_accel(0, 0, 0)
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_gen2_int() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
let mut write = |mut bytes: Vec<u8>| {
let (addr, expected) = bytes.split_first_mut().unwrap();
expected_io.push_write(*addr, &mut expected.into());
};
write(vec![0x4A, 0xFF]);
write(vec![0x4B, 0x03]);
write(vec![0x4C, 0xFF]);
write(vec![0x4D, 0xFF]);
write(vec![0x4E, 0xFF]);
write(vec![0x4F, 0xFF]);
write(vec![0x50, 0x0F]);
write(vec![0x51, 0xFF]);
write(vec![0x52, 0x0F]);
write(vec![0x53, 0xFF]);
write(vec![0x54, 0x0F]);
write(vec![0x4A, 0x00]);
write(vec![0x4B, 0x00]);
write(vec![0x4C, 0x00]);
write(vec![0x4D, 0x00]);
write(vec![0x4E, 0x00]);
write(vec![0x4F, 0x00]);
write(vec![0x50, 0x00]);
write(vec![0x51, 0x00]);
write(vec![0x52, 0x00]);
write(vec![0x53, 0x00]);
write(vec![0x54, 0x00]);
let mut device = new(&expected_io);
device
.config_gen2_int()
.with_axes(true, true, true)
.with_src(DataSource::AccFilt2)
.with_ref_mode(GenIntRefMode::EveryTimeFromLp)
.with_hysteresis(Hysteresis::Hyst96mg)
.with_criterion_mode(GenIntCriterionMode::Activity)
.with_logic_mode(GenIntLogicMode::And)
.with_threshold(0xFF)
.with_duration(0xFFFF)
.with_ref_accel(-1, -1, -1)
.write()
.unwrap();
device
.config_gen2_int()
.with_axes(false, false, false)
.with_src(DataSource::AccFilt1)
.with_ref_mode(GenIntRefMode::Manual)
.with_hysteresis(Hysteresis::None)
.with_criterion_mode(GenIntCriterionMode::Inactivity)
.with_logic_mode(GenIntLogicMode::Or)
.with_threshold(0)
.with_duration(0)
.with_ref_accel(0, 0, 0)
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_actchg_int() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x55, &mut vec![0xFF]);
expected_io.push_write(0x56, &mut vec![0xF4]);
expected_io.push_write(0x55, &mut vec![0x00]);
expected_io.push_write(0x56, &mut vec![0x00]);
let mut device = new(&expected_io);
device
.config_actchg_int()
.with_threshold(0xFF)
.with_axes(true, true, true)
.with_src(DataSource::AccFilt2)
.with_obs_period(ActChgObsPeriod::Samples512)
.write()
.unwrap();
device
.config_actchg_int()
.with_threshold(0)
.with_axes(false, false, false)
.with_src(DataSource::AccFilt1)
.with_obs_period(ActChgObsPeriod::Samples32)
.write()
.unwrap();
cleanup(device);
}
#[test]
fn config_tap() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x57, &mut vec![0x17]);
expected_io.push_write(0x58, &mut vec![0x3F]);
expected_io.push_write(0x57, &mut vec![0x00]);
expected_io.push_write(0x58, &mut vec![0x00]);
let mut device = new(&expected_io);
device
.config_tap()
.with_axis(Axis::X)
.with_sensitivity(TapSensitivity::SENS7)
.with_min_duration_btn_taps(MinTapDuration::Samples16)
.with_max_double_tap_window(DoubleTapDuration::Samples120)
.with_max_tap_duration(MaxTapDuration::Samples18)
.write()
.unwrap();
device
.config_tap()
.with_axis(Axis::Z)
.with_sensitivity(TapSensitivity::SENS0)
.with_min_duration_btn_taps(MinTapDuration::Samples4)
.with_max_double_tap_window(DoubleTapDuration::Samples60)
.with_max_tap_duration(MaxTapDuration::Samples6)
.write()
.unwrap();
cleanup(device);
}
fn self_test_setup(expected_io: &mut Transactions) {
expected_io.push_write(0x1F, &mut vec![0x00]);
expected_io.push_write(0x20, &mut vec![0x00]);
expected_io.push_write(0x2D, &mut vec![0xF4]);
expected_io.push_write(0x26, &mut vec![0x1F]);
expected_io.push_write(0x19, &mut vec![0xE2]);
expected_io.push_write(0x1A, &mut vec![0x78]);
}
fn restore_config(expected_io: &mut Transactions) {
expected_io.push_write(0x19, &mut vec![0xE0]);
expected_io.push_write(0x1A, &mut vec![0x09]);
expected_io.push_write(0x1F, &mut vec![0xEE]);
expected_io.push_write(0x20, &mut vec![0x9D]);
expected_io.push_write(0x2D, &mut vec![0xF6]);
expected_io.push_write(0x26, &mut vec![0xFF]);
}
fn self_test(
x_fail: bool,
y_fail: bool,
z_fail: bool,
expected_io: &mut Transactions,
expected_delay: &mut Vec<DelayTransaction>,
) {
const PASS_X_POS: i16 = 767;
const PASS_X_NEG: i16 = -734;
const PASS_Y_POS: i16 = 401;
const PASS_Y_NEG: i16 = -800;
const PASS_Z_POS: i16 = 550;
const PASS_Z_NEG: i16 = 299;
const FAIL_X_NEG: i16 = -733;
const FAIL_Y_POS: i16 = 400;
const FAIL_Z_NEG: i16 = 300;
let x_pos = PASS_X_POS;
let x_neg = if x_fail { FAIL_X_NEG } else { PASS_X_NEG };
let y_pos = if y_fail { FAIL_Y_POS } else { PASS_Y_POS };
let y_neg = PASS_Y_NEG;
let z_pos = PASS_Z_POS;
let z_neg = if z_fail { FAIL_Z_NEG } else { PASS_Z_NEG };
self_test_setup(expected_io);
expected_delay.push(DelayTransaction::delay_ms(2));
expected_io.push_write(0x7D, &mut vec![0x07]);
expected_delay.push(DelayTransaction::delay_ms(50));
expected_io.push_read(
0x84,
vec![
x_pos.to_le_bytes()[0],
x_pos.to_le_bytes()[1],
y_pos.to_le_bytes()[0],
y_pos.to_le_bytes()[1],
z_pos.to_le_bytes()[0],
z_pos.to_le_bytes()[1],
],
);
expected_io.push_write(0x7D, &mut vec![0x0F]);
expected_delay.push(DelayTransaction::delay_ms(50));
expected_io.push_read(
0x84,
vec![
x_neg.to_le_bytes()[0],
x_neg.to_le_bytes()[1],
y_neg.to_le_bytes()[0],
y_neg.to_le_bytes()[1],
z_neg.to_le_bytes()[0],
z_neg.to_le_bytes()[1],
],
);
expected_io.push_write(0x7D, &mut vec![0x00]);
expected_delay.push(DelayTransaction::delay_ms(50));
restore_config(expected_io);
}
#[test]
fn perform_self_test() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x56, &mut vec![0x10]);
expected_io.push_write(0x3F, &mut vec![0x10]);
expected_io.push_write(0x4A, &mut vec![0x10]);
expected_io.push_write(0x19, &mut vec![0xE0]);
expected_io.push_write(0x1A, &mut vec![0x09]);
expected_io.push_write(0x1F, &mut vec![0xEE]);
expected_io.push_write(0x20, &mut vec![0x9D]);
expected_io.push_write(0x2D, &mut vec![0xF6]);
expected_io.push_write(0x26, &mut vec![0xFF]);
let mut expected_delay = Vec::<DelayTransaction>::new();
self_test(false, false, false, &mut expected_io, &mut expected_delay);
self_test(true, false, false, &mut expected_io, &mut expected_delay);
self_test(false, true, false, &mut expected_io, &mut expected_delay);
self_test(false, false, true, &mut expected_io, &mut expected_delay);
let mut device = new(&expected_io);
device
.config_actchg_int()
.with_src(DataSource::AccFilt2)
.write()
.unwrap();
device
.config_gen1_int()
.with_src(DataSource::AccFilt2)
.write()
.unwrap();
device
.config_gen2_int()
.with_src(DataSource::AccFilt2)
.write()
.unwrap();
device
.config_accel()
.with_filt1_bw(Filter1Bandwidth::Low)
.with_osr_lp(OversampleRate::OSR3)
.with_scale(Scale::Range2G)
.with_osr(OversampleRate::OSR0)
.with_odr(OutputDataRate::Hz200)
.write()
.unwrap();
device
.config_interrupts()
.with_actch_int(true)
.with_d_tap_int(true)
.with_dta_rdy_int(true)
.with_ffull_int(true)
.with_fwm_int(true)
.with_gen1_int(true)
.with_gen2_int(true)
.with_latch_int(true)
.with_orientch_int(true)
.with_s_tap_int(true)
.with_step_int(true)
.write()
.unwrap();
device
.config_autowkup()
.with_periodic_wakeup(true)
.with_wakeup_period(0x0F)
.with_activity_int(true)
.write()
.unwrap();
device
.config_fifo()
.with_axes(true, true, true)
.with_8bit_mode(true)
.with_src(DataSource::AccFilt2)
.with_send_time_on_empty(true)
.with_stop_on_full(true)
.with_auto_flush(true)
.write()
.unwrap();
let mut timer = CheckedDelay::new(&expected_delay);
let result = device.perform_self_test(&mut timer);
assert!(matches!(result, Ok(())));
let result = device.perform_self_test(&mut timer);
assert!(matches!(result, Err(BMA400Error::SelfTestFailedError)));
let result = device.perform_self_test(&mut timer);
assert!(matches!(result, Err(BMA400Error::SelfTestFailedError)));
let result = device.perform_self_test(&mut timer);
assert!(matches!(result, Err(BMA400Error::SelfTestFailedError)));
timer.done();
cleanup(device);
}
#[test]
fn soft_reset() {
let mut expected_io = Transactions(Vec::new());
init(&mut expected_io);
expected_io.push_write(0x7E, &mut vec![0xB6]);
expected_io.push_read(0x8D, vec![0x01]);
let mut device = new(&expected_io);
device.soft_reset().unwrap();
cleanup(device);
}