extern crate std;
use super::*;
use embedded_hal_mock::eh1::i2c::{Mock as I2cMock, Transaction as I2cTransaction};
use registers::{AccelMagRegisters, CtrlReg0Xm, CtrlReg1G, CtrlReg4G, CtrlReg5G, GyroRegisters};
use std::vec;
const GYRO_ADDR: u8 = registers::device_constants::gyro::I2C_ADDR_0;
const XM_ADDR: u8 = registers::device_constants::xm::I2C_ADDR_0;
#[tokio::test]
async fn test_read_gyro_raw() {
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::OUT_X_L_G.addr() | AUTO_INCREMENT],
vec![0x02, 0x01, 0x04, 0x03, 0x06, 0x05],
)];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let (x, y, z) = driver.read_gyro_raw().await.unwrap();
assert_eq!(x, 0x0102); assert_eq!(y, 0x0304); assert_eq!(z, 0x0506);
driver.release().release().done();
}
#[tokio::test]
async fn test_read_gyro_raw_negative_values() {
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::OUT_X_L_G.addr() | AUTO_INCREMENT],
vec![0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x80],
)];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let (x, y, z) = driver.read_gyro_raw().await.unwrap();
assert_eq!(x, -1i16);
assert_eq!(y, -256i16);
assert_eq!(z, -32768i16);
driver.release().release().done();
}
#[tokio::test]
async fn test_read_accel_raw() {
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OUT_X_L_A.addr() | AUTO_INCREMENT],
vec![0x64, 0x00, 0xC8, 0x00, 0x2C, 0x01],
)];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let (x, y, z) = driver.read_accel_raw().await.unwrap();
assert_eq!(x, 100);
assert_eq!(y, 200);
assert_eq!(z, 300);
driver.release().release().done();
}
#[tokio::test]
async fn test_read_accel_raw_negative_values() {
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OUT_X_L_A.addr() | AUTO_INCREMENT],
vec![0x9C, 0xFF, 0x38, 0xFF, 0xD4, 0xFE],
)];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let (x, y, z) = driver.read_accel_raw().await.unwrap();
assert_eq!(x, -100i16);
assert_eq!(y, -200i16);
assert_eq!(z, -300i16);
driver.release().release().done();
}
#[tokio::test]
async fn test_read_mag_raw() {
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OUT_X_L_M.addr() | AUTO_INCREMENT],
vec![0xE8, 0x03, 0xD0, 0x07, 0xB8, 0x0B],
)];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let (x, y, z) = driver.read_mag_raw().await.unwrap();
assert_eq!(x, 1000);
assert_eq!(y, 2000);
assert_eq!(z, 3000);
driver.release().release().done();
}
#[tokio::test]
async fn test_read_mag_raw_negative_values() {
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OUT_X_L_M.addr() | AUTO_INCREMENT],
vec![0x18, 0xFC, 0x30, 0xF8, 0x48, 0xF4],
)];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let (x, y, z) = driver.read_mag_raw().await.unwrap();
assert_eq!(x, -1000i16);
assert_eq!(y, -2000i16);
assert_eq!(z, -3000i16);
driver.release().release().done();
}
#[test]
fn assert_send() {
fn is_send<T: Send>() {}
is_send::<Lsm9ds0<I2cInterface<I2cMock>>>();
}
fn write_config_expectations(config: &Lsm9ds0Config) -> std::vec::Vec<I2cTransaction> {
vec![
I2cTransaction::write(
GYRO_ADDR,
vec![
GyroRegisters::CTRL_REG1_G.addr() | 0x80,
config.ctrl_reg1_g.into(),
config.ctrl_reg2_g.into(),
config.ctrl_reg3_g.into(),
config.ctrl_reg4_g.into(),
config.ctrl_reg5_g.into(),
],
),
I2cTransaction::write(
GYRO_ADDR,
vec![
GyroRegisters::FIFO_CTRL_REG_G.addr(),
config.fifo_ctrl_reg_g.into(),
],
),
I2cTransaction::write(
GYRO_ADDR,
vec![GyroRegisters::INT1_CFG_G.addr(), config.int1_cfg_g.into()],
),
I2cTransaction::write(
GYRO_ADDR,
vec![
GyroRegisters::INT1_THS_XH_G.addr() | 0x80,
0x00,
0x00, 0x00,
0x00, 0x00,
0x00, config.int1_duration_g.into(),
],
),
I2cTransaction::write(
XM_ADDR,
vec![
AccelMagRegisters::INT_CTRL_REG_M.addr(),
config.int_ctrl_reg_m.into(),
],
),
I2cTransaction::write(
XM_ADDR,
vec![AccelMagRegisters::INT_THS_L_M.addr() | 0x80, 0x00, 0x00],
),
I2cTransaction::write(
XM_ADDR,
vec![
AccelMagRegisters::OFFSET_X_L_M.addr() | 0x80,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
],
),
I2cTransaction::write(
XM_ADDR,
vec![
AccelMagRegisters::CTRL_REG0_XM.addr() | 0x80,
config.ctrl_reg0_xm.into(),
config.ctrl_reg1_xm.into(),
config.ctrl_reg2_xm.into(),
config.ctrl_reg3_xm.into(),
config.ctrl_reg4_xm.into(),
config.ctrl_reg5_xm.into(),
config.ctrl_reg6_xm.into(),
config.ctrl_reg7_xm.into(),
],
),
I2cTransaction::write(
XM_ADDR,
vec![
AccelMagRegisters::FIFO_CTRL_REG.addr(),
config.fifo_ctrl_reg.into(),
],
),
I2cTransaction::write(
XM_ADDR,
vec![
AccelMagRegisters::INT_GEN_1_REG.addr(),
config.int_gen_1_reg.into(),
],
),
I2cTransaction::write(
XM_ADDR,
vec![AccelMagRegisters::INT_GEN_1_THS.addr() | 0x80, 0x00, 0x00],
),
I2cTransaction::write(
XM_ADDR,
vec![
AccelMagRegisters::INT_GEN_2_REG.addr(),
config.int_gen_2_reg.into(),
],
),
I2cTransaction::write(
XM_ADDR,
vec![AccelMagRegisters::INT_GEN_2_THS.addr() | 0x80, 0x00, 0x00],
),
I2cTransaction::write(
XM_ADDR,
vec![AccelMagRegisters::CLICK_CFG.addr(), config.click_cfg.into()],
),
I2cTransaction::write(
XM_ADDR,
vec![
AccelMagRegisters::CLICK_THS.addr() | 0x80,
0x00,
0x00,
0x00,
0x00,
],
),
I2cTransaction::write(
XM_ADDR,
vec![AccelMagRegisters::ACT_THS.addr() | 0x80, 0x00, 0x00],
),
]
}
fn default_init_expectations() -> std::vec::Vec<I2cTransaction> {
let config = Lsm9ds0Config::default();
let mut expectations = vec![
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::WHO_AM_I_G.addr()],
vec![registers::device_constants::gyro::DEVICE_ID],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::WHO_AM_I_XM.addr()],
vec![registers::device_constants::xm::DEVICE_ID],
),
];
expectations.extend(write_config_expectations(&config));
expectations
}
struct MockDelay;
impl embedded_hal_async::delay::DelayNs for MockDelay {
async fn delay_ns(&mut self, _ns: u32) {}
}
#[tokio::test]
async fn test_init_sequence() {
let expectations = default_init_expectations();
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
driver.init(&mut MockDelay).await.unwrap();
driver.release().release().done();
}
#[tokio::test]
async fn test_set_gyro_scale_writes_register() {
let mut expectations = default_init_expectations();
let expected_reg4: u8 = CtrlReg4G::new().with_fs(GyroScale::Dps2000).into();
expectations.push(I2cTransaction::write(
GYRO_ADDR,
vec![GyroRegisters::CTRL_REG4_G.addr(), expected_reg4],
));
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
driver.init(&mut MockDelay).await.unwrap();
driver.set_gyro_scale(GyroScale::Dps2000).await.unwrap();
driver.release().release().done();
}
#[tokio::test]
async fn test_read_gyro_scaled() {
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::OUT_X_L_G.addr() | AUTO_INCREMENT],
vec![0xE8, 0x03, 0x0C, 0xFE, 0xFA, 0x00], )];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
driver.config.gyro_bias = (1.0, -0.5, 0.0);
let (gx, gy, gz) = driver.read_gyro().await.unwrap();
let epsilon = 0.001;
assert!((gx.as_f32() - 7.75).abs() < epsilon, "gx={}", gx.as_f32());
assert!(
(gy.as_f32() - (-3.875)).abs() < epsilon,
"gy={}",
gy.as_f32()
);
assert!((gz.as_f32() - 2.1875).abs() < epsilon, "gz={}", gz.as_f32());
driver.release().release().done();
}
#[tokio::test]
async fn test_error_propagation() {
use embedded_hal_async::i2c::ErrorKind;
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::OUT_X_L_G.addr() | AUTO_INCREMENT],
vec![0u8; 6],
)
.with_error(ErrorKind::Other)];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let result = driver.read_gyro_raw().await;
assert!(matches!(result, Err(Error::GyroBus(_))));
driver.release().release().done();
}
#[tokio::test]
async fn test_read_temp() {
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OUT_TEMP_L_XM.addr() | AUTO_INCREMENT],
vec![0xC8, 0x00], )];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let temp = driver.read_temp().await.unwrap();
let epsilon = 0.01;
assert!(
(temp.as_f32() - 50.0).abs() < epsilon,
"positive temp={}",
temp.as_f32()
);
driver.release().release().done();
}
#[tokio::test]
async fn test_read_temp_negative() {
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OUT_TEMP_L_XM.addr() | AUTO_INCREMENT],
vec![0xB0, 0x0F], )];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let temp = driver.read_temp().await.unwrap();
let epsilon = 0.01;
assert!(
(temp.as_f32() - 15.0).abs() < epsilon,
"negative temp={}",
temp.as_f32()
);
driver.release().release().done();
}
#[tokio::test]
async fn test_read_all() {
const AUTO_INCREMENT: u8 = 0x80;
let expectations = [
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::OUT_X_L_G.addr() | AUTO_INCREMENT],
vec![0xE8, 0x03, 0x0C, 0xFE, 0xFA, 0x00],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OUT_X_L_A.addr() | AUTO_INCREMENT],
vec![0x64, 0x00, 0xC8, 0x00, 0x2C, 0x01],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OUT_X_L_M.addr() | AUTO_INCREMENT],
vec![0xF4, 0x01, 0x18, 0xFC, 0xDC, 0x05],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OUT_TEMP_L_XM.addr() | AUTO_INCREMENT],
vec![0xC8, 0x00],
),
];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let data = driver.read_all().await.unwrap();
let epsilon = 0.001;
let (gx, gy, gz) = data.gyro;
assert!((gx.as_f32() - 8.75).abs() < epsilon, "gx={}", gx.as_f32());
assert!(
(gy.as_f32() - (-4.375)).abs() < epsilon,
"gy={}",
gy.as_f32()
);
assert!(
(gz.as_f32() - 2.1875).abs() < epsilon,
"gz={}",
gz.as_f32()
);
let (ax, ay, az) = data.accel;
assert!(
(ax.as_f32() - 0.0061).abs() < epsilon,
"ax={}",
ax.as_f32()
);
assert!(
(ay.as_f32() - 0.0122).abs() < epsilon,
"ay={}",
ay.as_f32()
);
assert!(
(az.as_f32() - 0.0183).abs() < epsilon,
"az={}",
az.as_f32()
);
let (mx, my, mz) = data.mag;
assert!(
(mx.as_f32() - 0.08).abs() < epsilon,
"mx={}",
mx.as_f32()
);
assert!(
(my.as_f32() - (-0.16)).abs() < epsilon,
"my={}",
my.as_f32()
);
assert!(
(mz.as_f32() - 0.24).abs() < epsilon,
"mz={}",
mz.as_f32()
);
assert!(
(data.temp.as_f32() - 50.0).abs() < epsilon,
"temp={}",
data.temp.as_f32()
);
driver.release().release().done();
}
use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction};
const SPI_READ: u8 = 0x80;
const MS_BIT: u8 = 0x40;
#[tokio::test]
async fn test_spi_read_gyro_raw() {
let gyro_expectations = [
SpiTransaction::transaction_start(),
SpiTransaction::write_vec(vec![SPI_READ | MS_BIT | GyroRegisters::OUT_X_L_G.addr()]),
SpiTransaction::read_vec(vec![0x02, 0x01, 0x04, 0x03, 0x06, 0x05]),
SpiTransaction::transaction_end(),
];
let xm_expectations: [SpiTransaction<u8>; 0] = [];
let gyro_spi = SpiMock::new(&gyro_expectations);
let xm_spi = SpiMock::new(&xm_expectations);
let interface = SpiInterface::init(gyro_spi, xm_spi);
let mut driver = Lsm9ds0::new(interface);
let (x, y, z) = driver.read_gyro_raw().await.unwrap();
assert_eq!(x, 0x0102);
assert_eq!(y, 0x0304);
assert_eq!(z, 0x0506);
let (mut gyro_spi, mut xm_spi) = driver.release().release();
gyro_spi.done();
xm_spi.done();
}
#[tokio::test]
async fn test_spi_read_accel_raw() {
let gyro_expectations: [SpiTransaction<u8>; 0] = [];
let xm_expectations = [
SpiTransaction::transaction_start(),
SpiTransaction::write_vec(vec![
SPI_READ | MS_BIT | AccelMagRegisters::OUT_X_L_A.addr(),
]),
SpiTransaction::read_vec(vec![0x64, 0x00, 0xC8, 0x00, 0x2C, 0x01]),
SpiTransaction::transaction_end(),
];
let gyro_spi = SpiMock::new(&gyro_expectations);
let xm_spi = SpiMock::new(&xm_expectations);
let interface = SpiInterface::init(gyro_spi, xm_spi);
let mut driver = Lsm9ds0::new(interface);
let (x, y, z) = driver.read_accel_raw().await.unwrap();
assert_eq!(x, 100);
assert_eq!(y, 200);
assert_eq!(z, 300);
let (mut gyro_spi, mut xm_spi) = driver.release().release();
gyro_spi.done();
xm_spi.done();
}
#[tokio::test]
async fn test_spi_read_mag_raw() {
let gyro_expectations: [SpiTransaction<u8>; 0] = [];
let xm_expectations = [
SpiTransaction::transaction_start(),
SpiTransaction::write_vec(vec![
SPI_READ | MS_BIT | AccelMagRegisters::OUT_X_L_M.addr(),
]),
SpiTransaction::read_vec(vec![0xE8, 0x03, 0xD0, 0x07, 0xB8, 0x0B]),
SpiTransaction::transaction_end(),
];
let gyro_spi = SpiMock::new(&gyro_expectations);
let xm_spi = SpiMock::new(&xm_expectations);
let interface = SpiInterface::init(gyro_spi, xm_spi);
let mut driver = Lsm9ds0::new(interface);
let (x, y, z) = driver.read_mag_raw().await.unwrap();
assert_eq!(x, 1000);
assert_eq!(y, 2000);
assert_eq!(z, 3000);
let (mut gyro_spi, mut xm_spi) = driver.release().release();
gyro_spi.done();
xm_spi.done();
}
#[tokio::test]
async fn test_i2c_multi_byte_write() {
const AUTO_INCREMENT: u8 = 0x80;
let test_addr = 0x20; let test_data: [u8; 9] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09];
let mut expected_write = vec![test_addr | AUTO_INCREMENT];
expected_write.extend_from_slice(&test_data);
let expectations = [I2cTransaction::write(GYRO_ADDR, expected_write)];
let i2c = I2cMock::new(&expectations);
let mut interface = I2cInterface::init(i2c);
interface.write_gyro(test_addr, &test_data).await.unwrap();
interface.release().done();
}
fn verify_config_expectations(config: &Lsm9ds0Config) -> std::vec::Vec<I2cTransaction> {
const AUTO_INCREMENT: u8 = 0x80;
let ctrl_reg5_xm_val: u8 = config.ctrl_reg5_xm.into();
vec![
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::CTRL_REG1_G.addr() | AUTO_INCREMENT],
vec![
config.ctrl_reg1_g.into(),
config.ctrl_reg2_g.into(),
config.ctrl_reg3_g.into(),
config.ctrl_reg4_g.into(),
config.ctrl_reg5_g.into(),
],
),
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::FIFO_CTRL_REG_G.addr()],
vec![config.fifo_ctrl_reg_g.into()],
),
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::INT1_CFG_G.addr()],
vec![config.int1_cfg_g.into()],
),
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::INT1_THS_XH_G.addr() | AUTO_INCREMENT],
vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, config.int1_duration_g.into()],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::INT_CTRL_REG_M.addr()],
vec![config.int_ctrl_reg_m.into()],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::INT_THS_L_M.addr() | AUTO_INCREMENT],
vec![0x00, 0x00],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OFFSET_X_L_M.addr() | AUTO_INCREMENT],
vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::CTRL_REG0_XM.addr() | AUTO_INCREMENT],
vec![
config.ctrl_reg0_xm.into(),
config.ctrl_reg1_xm.into(),
config.ctrl_reg2_xm.into(),
config.ctrl_reg3_xm.into(),
config.ctrl_reg4_xm.into(),
ctrl_reg5_xm_val,
config.ctrl_reg6_xm.into(),
config.ctrl_reg7_xm.into(),
],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::FIFO_CTRL_REG.addr()],
vec![config.fifo_ctrl_reg.into()],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::INT_GEN_1_REG.addr()],
vec![config.int_gen_1_reg.into()],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::INT_GEN_1_THS.addr() | AUTO_INCREMENT],
vec![0x00, 0x00],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::INT_GEN_2_REG.addr()],
vec![config.int_gen_2_reg.into()],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::INT_GEN_2_THS.addr() | AUTO_INCREMENT],
vec![0x00, 0x00],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::CLICK_CFG.addr()],
vec![config.click_cfg.into()],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::CLICK_THS.addr() | AUTO_INCREMENT],
vec![0x00, 0x00, 0x00, 0x00],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::ACT_THS.addr() | AUTO_INCREMENT],
vec![0x00, 0x00],
),
]
}
#[tokio::test]
async fn test_verify_config_pass() {
let config = Lsm9ds0Config::default();
let expectations = verify_config_expectations(&config);
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let result = driver.verify_config().await;
assert!(result.is_ok(), "verify_config should pass: {:?}", result);
driver.release().release().done();
}
#[tokio::test]
async fn test_verify_config_detects_gyro_mismatch() {
let config = Lsm9ds0Config::default();
const AUTO_INCREMENT: u8 = 0x80;
let corrupted_reg3_g: u8 = 0xFF;
let expectations = vec![
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::CTRL_REG1_G.addr() | AUTO_INCREMENT],
vec![
config.ctrl_reg1_g.into(),
config.ctrl_reg2_g.into(),
corrupted_reg3_g, config.ctrl_reg4_g.into(),
config.ctrl_reg5_g.into(),
],
),
];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let result = driver.verify_config().await;
match result {
Err(Error::ConfigMismatch {
register,
expected,
actual,
}) => {
assert_eq!(register, GyroRegisters::CTRL_REG3_G.addr());
assert_eq!(expected, config.ctrl_reg3_g.into());
assert_eq!(actual, corrupted_reg3_g);
}
other => panic!("expected ConfigMismatch, got {:?}", other),
}
driver.release().release().done();
}
#[tokio::test]
async fn test_verify_config_detects_xm_mismatch() {
let config = Lsm9ds0Config::default();
const AUTO_INCREMENT: u8 = 0x80;
let corrupted_ctrl_reg1_xm: u8 = 0xAB;
let expectations = vec![
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::CTRL_REG1_G.addr() | AUTO_INCREMENT],
vec![
config.ctrl_reg1_g.into(),
config.ctrl_reg2_g.into(),
config.ctrl_reg3_g.into(),
config.ctrl_reg4_g.into(),
config.ctrl_reg5_g.into(),
],
),
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::FIFO_CTRL_REG_G.addr()],
vec![config.fifo_ctrl_reg_g.into()],
),
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::INT1_CFG_G.addr()],
vec![config.int1_cfg_g.into()],
),
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::INT1_THS_XH_G.addr() | AUTO_INCREMENT],
vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, config.int1_duration_g.into()],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::INT_CTRL_REG_M.addr()],
vec![config.int_ctrl_reg_m.into()],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::INT_THS_L_M.addr() | AUTO_INCREMENT],
vec![0x00, 0x00],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::OFFSET_X_L_M.addr() | AUTO_INCREMENT],
vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::CTRL_REG0_XM.addr() | AUTO_INCREMENT],
vec![
config.ctrl_reg0_xm.into(),
corrupted_ctrl_reg1_xm, config.ctrl_reg2_xm.into(),
config.ctrl_reg3_xm.into(),
config.ctrl_reg4_xm.into(),
config.ctrl_reg5_xm.into(),
config.ctrl_reg6_xm.into(),
config.ctrl_reg7_xm.into(),
],
),
];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
let result = driver.verify_config().await;
match result {
Err(Error::ConfigMismatch {
register,
expected,
actual,
}) => {
assert_eq!(register, AccelMagRegisters::CTRL_REG1_XM.addr());
assert_eq!(expected, config.ctrl_reg1_xm.into());
assert_eq!(actual, corrupted_ctrl_reg1_xm);
}
other => panic!("expected ConfigMismatch, got {:?}", other),
}
driver.release().release().done();
}
#[tokio::test]
#[should_panic(expected = "exceeds MAX_WRITE_LEN")]
#[cfg(debug_assertions)]
async fn test_i2c_write_exceeds_max_length_panics_in_debug() {
let test_addr = 0x20;
let test_data: [u8; 20] = [0u8; 20];
let expectations: [I2cTransaction; 0] = [];
let i2c = I2cMock::new(&expectations);
let mut interface = I2cInterface::init(i2c);
let _ = interface.write_gyro(test_addr, &test_data).await;
}
#[tokio::test]
async fn test_reapply_config() {
let config = Lsm9ds0Config::new()
.with_gyro_scale(GyroScale::Dps2000)
.with_accel_scale(AccelScale::G8)
.with_mag_scale(MagScale::Gauss8);
let expectations = write_config_expectations(&config);
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new_with_config(interface, config);
driver.reapply_config().await.unwrap();
assert_eq!(driver.config().gyro_sensitivity(), GyroScale::Dps2000.sensitivity());
assert_eq!(driver.config().accel_sensitivity(), AccelScale::G8.sensitivity());
assert_eq!(driver.config().mag_sensitivity(), MagScale::Gauss8.sensitivity());
driver.release().release().done();
}
#[tokio::test]
async fn test_software_reset() {
let boot_val_g: u8 = CtrlReg5G::new().with_boot(Enable::Enabled).into();
let boot_val_xm: u8 = CtrlReg0Xm::new().with_boot(Enable::Enabled).into();
let expectations = vec![
I2cTransaction::write(
GYRO_ADDR,
vec![GyroRegisters::CTRL_REG5_G.addr(), boot_val_g],
),
I2cTransaction::write(
XM_ADDR,
vec![AccelMagRegisters::CTRL_REG0_XM.addr(), boot_val_xm],
),
I2cTransaction::write_read(
GYRO_ADDR,
vec![GyroRegisters::WHO_AM_I_G.addr()],
vec![registers::device_constants::gyro::DEVICE_ID],
),
I2cTransaction::write_read(
XM_ADDR,
vec![AccelMagRegisters::WHO_AM_I_XM.addr()],
vec![registers::device_constants::xm::DEVICE_ID],
),
];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
driver.software_reset(&mut MockDelay).await.unwrap();
assert_eq!(driver.config.ctrl_reg5_g.boot(), Enable::Disabled);
assert_eq!(driver.config.ctrl_reg0_xm.boot(), Enable::Disabled);
assert_eq!(driver.config().gyro_sensitivity(), GyroScale::Dps245.sensitivity());
driver.release().release().done();
}
#[tokio::test]
async fn test_set_gyro_power_mode() {
let sleep_val: u8 = CtrlReg1G::new()
.with_pd(PowerMode::Normal)
.with_xen(Enable::Disabled)
.with_yen(Enable::Disabled)
.with_zen(Enable::Disabled)
.into();
let power_down_val: u8 = CtrlReg1G::new().with_pd(PowerMode::PowerDown).into();
let expectations = vec![
I2cTransaction::write(
GYRO_ADDR,
vec![GyroRegisters::CTRL_REG1_G.addr(), sleep_val],
),
I2cTransaction::write(
GYRO_ADDR,
vec![GyroRegisters::CTRL_REG1_G.addr(), power_down_val],
),
];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
driver
.set_gyro_power_mode(GyroPowerMode::Sleep)
.await
.unwrap();
assert_eq!(driver.config.ctrl_reg1_g.pd(), PowerMode::Normal);
assert_eq!(driver.config.ctrl_reg1_g.xen(), Enable::Disabled);
assert_eq!(driver.config.ctrl_reg1_g.yen(), Enable::Disabled);
assert_eq!(driver.config.ctrl_reg1_g.zen(), Enable::Disabled);
driver
.set_gyro_power_mode(GyroPowerMode::PowerDown)
.await
.unwrap();
assert_eq!(driver.config.ctrl_reg1_g.pd(), PowerMode::PowerDown);
driver.release().release().done();
}
#[tokio::test]
async fn test_set_gyro_axes_persists_for_power_mode_restore() {
let axes_val: u8 = CtrlReg1G::new().with_zen(Enable::Enabled).into(); let sleep_val: u8 = CtrlReg1G::new()
.with_pd(PowerMode::Normal)
.with_xen(Enable::Disabled)
.with_yen(Enable::Disabled)
.with_zen(Enable::Disabled)
.into(); let normal_val: u8 = CtrlReg1G::new()
.with_pd(PowerMode::Normal)
.with_xen(Enable::Disabled)
.with_yen(Enable::Disabled)
.with_zen(Enable::Enabled)
.into();
let expectations = vec![
I2cTransaction::write(
GYRO_ADDR,
vec![GyroRegisters::CTRL_REG1_G.addr(), axes_val],
),
I2cTransaction::write(
GYRO_ADDR,
vec![GyroRegisters::CTRL_REG1_G.addr(), sleep_val],
),
I2cTransaction::write(
GYRO_ADDR,
vec![GyroRegisters::CTRL_REG1_G.addr(), normal_val],
),
];
let i2c = I2cMock::new(&expectations);
let interface = I2cInterface::init(i2c);
let mut driver = Lsm9ds0::new(interface);
driver.set_gyro_axes(false, false, true).await.unwrap();
driver
.set_gyro_power_mode(GyroPowerMode::Sleep)
.await
.unwrap();
driver
.set_gyro_power_mode(GyroPowerMode::Normal)
.await
.unwrap();
assert_eq!(driver.config.ctrl_reg1_g.xen(), Enable::Disabled);
assert_eq!(driver.config.ctrl_reg1_g.yen(), Enable::Disabled);
assert_eq!(driver.config.ctrl_reg1_g.zen(), Enable::Enabled);
assert_eq!(driver.config.gyro_axes_enabled, (false, false, true));
driver.release().release().done();
}