Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,12 @@ jobs:
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose

keep-in-sync:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Check that and async versions are in sync
run: make check-async-sync
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ exclude = ["examples/nrf52840/.cargo"]
[dependencies]
embedded-hal = "1.0.0"
fixedvec = "0.2.4"
embedded-hal-async = {version = "1.0.0", optional = true }


[features]
async = ["dep:embedded-hal-async"]
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

# When you've made changes to the async version, updating the sync version is trivial
.PHONY: async-to-sync
async-to-sync:
cat src/interface_async.rs | sed -e 's/[.]await//' -e 's/async //' -e 's/_async//' | grep -vF '#[allow(async_fn_in_trait)]' | rustfmt > src/interface.rs
cat src/bmi2_async.rs | sed -e 's/[.]await//' -e 's/async //' -e 's/_async//' | grep -vF '#[allow(async_fn_in_trait)]' | rustfmt > src/bmi2.rs

# When you've made changes to the sync version, updating the async version is not always as clear
# because there are many possible places to insert async and await, so the best we can do is check.
.PHONY: check-async-sync
check-async-sync:
# Everything must be formatted before we start, because the code might reflow differently in
# sync vs async versions. For local dev we do it automatically. For CI we just check it.
if [ "${CI}" = "" ]; then cargo fmt; fi
cargo fmt --check
# Strip out the async-related keywords, then format, then diff against the sync version.
cat src/interface_async.rs | sed -e 's/[.]await//' -e 's/async //' -e 's/_async//' | grep -vF '#[allow(async_fn_in_trait)]' | rustfmt > /tmp/stripped-interface_async.rs
diff -u /tmp/stripped-interface_async.rs src/interface.rs
cat src/bmi2_async.rs | sed -e 's/[.]await//' -e 's/async //' -e 's/_async//' | grep -vF '#[allow(async_fn_in_trait)]' | rustfmt > /tmp/stripped-bmi2_async.rs
diff -u /tmp/stripped-bmi2_async.rs src/bmi2.rs
# Make sure everything actually compiles once we're done.
cargo check --all-features
69 changes: 32 additions & 37 deletions src/bmi2.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
use fixedvec::FixedVec;
use embedded_hal::delay::DelayNs;
use fixedvec::FixedVec;

use crate::interface::{I2cAddr, I2cInterface, ReadData, SpiInterface, WriteData};
use crate::registers::Registers;
use crate::{
interface::{I2cInterface, ReadData, SpiInterface, WriteData},
interface_common::I2cAddr,
};

use crate::types::{
AccConf, AccOffsets, AccRange, AccSelfTest, AuxConf, AuxData, AuxIfConf, AxisData, Burst, Cmd, Data, Drv, Error, ErrorReg, ErrorRegMsk, Event, FifoConf, FifoDowns, GyrConf, GyrCrtConf, GyrOffsets, GyrRange, GyrSelfTest, IfConf, IntIoCtrl, IntLatch, IntMapData, IntMapFeat, InternalError, InternalStatus, InterruptStatus, NvConf, PullUpConf, PwrConf, PwrCtrl, Saturation, Status, WristGestureActivity, BMI160_CHIP_ID, BMI260_CHIP_ID, BMI270_CHIP_ID, FIFO_LENGTH_1_MASK,
AccConf, AccOffsets, AccRange, AccSelfTest, AuxConf, AuxData, AuxIfConf, AxisData, Burst, Cmd,
Data, Drv, Error, ErrorReg, ErrorRegMsk, Event, FifoConf, FifoDowns, GyrConf, GyrCrtConf,
GyrOffsets, GyrRange, GyrSelfTest, IfConf, IntIoCtrl, IntLatch, IntMapData, IntMapFeat,
InternalError, InternalStatus, InterruptStatus, NvConf, PullUpConf, PwrConf, PwrCtrl,
Saturation, Status, WristGestureActivity, BMI160_CHIP_ID, BMI260_CHIP_ID, BMI270_CHIP_ID,
FIFO_LENGTH_1_MASK,
};

pub struct Bmi2<I, D, const N: usize> {
Expand Down Expand Up @@ -33,9 +41,9 @@ impl<I2C, D, const N: usize> Bmi2<I2cInterface<I2C>, D, N> {
}
}

impl<SPI, D, const N: usize> Bmi2<SpiInterface<SPI>, D, N>
where
D: DelayNs
impl<SPI, D, const N: usize> Bmi2<SpiInterface<SPI>, D, N>
where
D: DelayNs,
{
/// Create a new Bmi270 device with SPI communication.
pub fn new_spi(spi: SPI, delay: D, burst: Burst) -> Self {
Expand Down Expand Up @@ -153,9 +161,7 @@ where
}

/// Get the detected wrist gesture and activity type.
pub fn get_wrist_gesture_activity(
&mut self,
) -> Result<WristGestureActivity, Error<CommE>> {
pub fn get_wrist_gesture_activity(&mut self) -> Result<WristGestureActivity, Error<CommE>> {
let wr_gest_acc = self.iface.read_reg(Registers::WR_GEST_ACT)?;

Ok(WristGestureActivity::from_reg(wr_gest_acc))
Expand Down Expand Up @@ -430,10 +436,7 @@ where
}

/// Set interrupt 1 feature mapping.
pub fn set_int1_map_feat(
&mut self,
int1_map_feat: IntMapFeat,
) -> Result<(), Error<CommE>> {
pub fn set_int1_map_feat(&mut self, int1_map_feat: IntMapFeat) -> Result<(), Error<CommE>> {
let reg = int1_map_feat.to_reg();
self.iface.write_reg(Registers::INT1_MAP_FEAT, reg)?;
Ok(())
Expand All @@ -446,10 +449,7 @@ where
}

/// Set interrupt 2 feature mapping.
pub fn set_int2_map_feat(
&mut self,
int2_map_feat: IntMapFeat,
) -> Result<(), Error<CommE>> {
pub fn set_int2_map_feat(&mut self, int2_map_feat: IntMapFeat) -> Result<(), Error<CommE>> {
let reg = int2_map_feat.to_reg();
self.iface.write_reg(Registers::INT2_MAP_FEAT, reg)?;
Ok(())
Expand Down Expand Up @@ -585,10 +585,7 @@ where
}

/// Set the accelerometer self test configuration.
pub fn set_acc_self_test(
&mut self,
acc_self_test: AccSelfTest,
) -> Result<(), Error<CommE>> {
pub fn set_acc_self_test(&mut self, acc_self_test: AccSelfTest) -> Result<(), Error<CommE>> {
self.iface
.write_reg(Registers::ACC_SELF_TEST, acc_self_test.to_reg())?;
Ok(())
Expand Down Expand Up @@ -727,13 +724,12 @@ where
Ok(())
}


/// Initialize sensor.
pub fn init(&mut self, config_file: &[u8]) -> Result<(), Error<CommE>> {
// Verify chip ID first
let chip_id = self.iface.read_reg(Registers::CHIP_ID)?;
if !(chip_id == BMI160_CHIP_ID || chip_id == BMI260_CHIP_ID || chip_id == BMI270_CHIP_ID) {
return Err(Error::InvalidChipId);
return Err(Error::InvalidChipId);
}

// Reset Chip, mandatory per datasheet
Expand All @@ -755,43 +751,42 @@ where
let mut offset = 0u16;
let max_len = config_file.len() as u16;
let burst = if self.max_burst % 2 == 0 {
self.max_burst - 1 // Address byte + even number of data bytes
self.max_burst - 1 // Address byte + even number of data bytes
} else {
self.max_burst - 2 // Make sure we have even data bytes
self.max_burst - 2 // Make sure we have even data bytes
};
let init_ctrl= self.get_init_ctrl()?;

let init_ctrl = self.get_init_ctrl()?;
self.set_init_ctrl(init_ctrl & 0b1111_1110)?;
self.delay.delay_us(450);
self.delay.delay_us(450);

while offset < max_len {
// INIT_ADDR should point to 16-bit words
self.set_init_addr(offset / 2)?; // needs to be divided by 2 because offset is in bytes
self.set_init_addr(offset / 2)?; // needs to be divided by 2 because offset is in bytes

// Ensure we're writing complete 16-bit words
let mut chunk_size = burst;
if (chunk_size % 2) != 0 {
// If burst size would result in odd number of bytes, reduce by 1
chunk_size -= 1;
}

let end = if (offset + chunk_size) > max_len {
// For the last chunk, ensure we still write complete 16-bit words
let remaining = max_len - offset;
offset + (remaining - (remaining % 2))
} else {
offset + chunk_size
};

vec.clear();
vec.push(Registers::INIT_DATA)
.map_err(|_| Error::Alloc)?;

vec.push(Registers::INIT_DATA).map_err(|_| Error::Alloc)?;

vec.push_all(&config_file[offset as usize..end as usize])
.map_err(|_| Error::Alloc)?;

self.iface.write(vec.as_mut_slice())?;

offset += chunk_size;
self.delay.delay_us(2);
}
Expand Down
Loading