#![warn(missing_docs, unsafe_code)]
#![no_std]
pub(crate) use embedded_hal as hal;
use hal::blocking::delay::DelayMs;
pub mod types;
pub use types::*;
pub(crate) mod registers;
use registers::*;
mod interface;
use interface::{
ReadFromRegister,
WriteToRegister,
};
mod config;
use config::{
Config,
};
pub use config::ActChgConfigBuilder;
pub use config::GenIntConfigBuilder;
pub use config::OrientChgConfigBuilder;
pub use config::TapConfigBuilder;
pub use config::{
AccConfigBuilder,
AutoLpConfigBuilder,
AutoWakeupConfigBuilder,
FifoConfigBuilder,
IntConfigBuilder,
IntPinConfigBuilder,
WakeupIntConfigBuilder,
};
#[cfg(any(feature = "i2c", test))]
mod i2c;
#[cfg(any(feature = "i2c", test))]
pub use i2c::I2CInterface;
#[cfg(any(feature = "spi", test))]
mod spi;
#[cfg(any(feature = "spi", test))]
pub use spi::SPIInterface;
pub struct BMA400<T> {
interface: T,
config: Config,
}
impl<T, InterfaceError, PinError> BMA400<T>
where
T: ReadFromRegister<Error = BMA400Error<InterfaceError, PinError>>
+ WriteToRegister<Error = BMA400Error<InterfaceError, PinError>>,
{
pub fn get_id(&mut self) -> Result<u8, BMA400Error<InterfaceError, PinError>> {
let mut id = [0u8; 1];
self.interface.read_register(ChipId, &mut id)?;
Ok(id[0])
}
pub fn get_cmd_error(&mut self) -> Result<bool, BMA400Error<InterfaceError, PinError>> {
let mut err_byte = [0u8; 1];
self.interface.read_register(ErrReg, &mut err_byte)?;
Ok(err_byte[0] & 0b00000010 != 0)
}
pub fn get_status(&mut self) -> Result<Status, BMA400Error<InterfaceError, PinError>> {
let mut status_byte = [0u8; 1];
self.interface.read_register(StatusReg, &mut status_byte)?;
Ok(Status::new(status_byte[0]))
}
pub fn get_unscaled_data(&mut self) -> Result<Measurement, BMA400Error<InterfaceError, PinError>> {
let mut bytes = [0u8; 6];
self.interface.read_register(AccXLSB, &mut bytes)?;
Ok(Measurement::from_bytes_unscaled(&bytes))
}
pub fn get_data(&mut self) -> Result<Measurement, BMA400Error<InterfaceError, PinError>> {
let mut bytes = [0u8; 6];
self.interface.read_register(AccXLSB, &mut bytes)?;
Ok(Measurement::from_bytes_scaled(self.config.scale(), &bytes))
}
pub fn get_sensor_clock(&mut self) -> Result<u32, BMA400Error<InterfaceError, PinError>> {
let mut buffer = [0u8; 3];
self.interface.read_register(SensorTime0, &mut buffer)?;
let bytes = [buffer[0], buffer[1], buffer[2], 0];
Ok(u32::from_le_bytes(bytes))
}
pub fn get_reset_status(&mut self) -> Result<bool, BMA400Error<InterfaceError, PinError>> {
let mut buffer = [0u8; 1];
self.interface.read_register(Event, &mut buffer)?;
Ok(buffer[0] & 0x01 != 0)
}
pub fn get_int_status0(&mut self) -> Result<IntStatus0, BMA400Error<InterfaceError, PinError>> {
let mut status_byte = [0u8; 1];
self.interface.read_register(InterruptStatus0, &mut status_byte)?;
Ok(IntStatus0::new(status_byte[0]))
}
pub fn get_int_status1(&mut self) -> Result<IntStatus1, BMA400Error<InterfaceError, PinError>> {
let mut status_byte = [0u8; 1];
self.interface.read_register(InterruptStatus1, &mut status_byte)?;
Ok(IntStatus1::new(status_byte[0]))
}
pub fn get_int_status2(&mut self) -> Result<IntStatus2, BMA400Error<InterfaceError, PinError>> {
let mut status_byte = [0u8; 1];
self.interface.read_register(InterruptStatus2, &mut status_byte)?;
Ok(IntStatus2::new(status_byte[0]))
}
pub fn get_fifo_len(&mut self) -> Result<u16, BMA400Error<InterfaceError, PinError>> {
let mut buffer = [0u8; 2];
self.interface.read_register(FifoLength0, &mut buffer)?;
let bytes = [buffer[0], buffer[1] & 0b0000_0111];
Ok(u16::from_le_bytes(bytes))
}
pub fn read_fifo_frames<'a>(&mut self, buffer: &'a mut [u8]) -> Result<FifoFrames<'a>, BMA400Error<InterfaceError, PinError>> {
if self.config.is_fifo_read_disabled() {
return Err(ConfigError::FifoReadWhilePwrDisable.into());
}
self.interface.read_register(FifoData, buffer)?;
Ok(FifoFrames::new(buffer))
}
pub fn flush_fifo(&mut self) -> Result<(), BMA400Error<InterfaceError, PinError>> {
self.interface.write_register(Command::FlushFifo)?;
Ok(())
}
pub fn get_step_count(&mut self) -> Result<u32, BMA400Error<InterfaceError, PinError>> {
let mut buffer = [0u8; 3];
self.interface.read_register(StepCount0, &mut buffer)?;
Ok(u32::from_le_bytes([buffer[0], buffer[1], buffer[2], 0]))
}
pub fn clear_step_count(&mut self) -> Result<(), BMA400Error<InterfaceError, PinError>> {
self.interface.write_register(Command::ClearStepCount)?;
Ok(())
}
pub fn get_step_activity(&mut self) -> Result<Activity, BMA400Error<InterfaceError, PinError>> {
let mut buffer = [0u8; 1];
self.interface.read_register(StepStatus, &mut buffer)?;
let activity = match buffer[0] & 0b11 {
0x00 => Activity::Still,
0x01 => Activity::Walk,
_ => Activity::Run,
};
Ok(activity)
}
pub fn get_raw_temp(&mut self) -> Result<i8, BMA400Error<InterfaceError, PinError>> {
let mut temp = [0u8; 1];
self.interface.read_register(TempData, &mut temp)?;
let t = i8::from_le_bytes(temp);
Ok(t)
}
#[cfg(feature = "float")]
pub fn get_temp_celsius(&mut self) -> Result<f32, BMA400Error<InterfaceError, PinError>> {
Ok(f32::from(self.get_raw_temp()?) * 0.5 + 23.0)
}
pub fn config_accel(&mut self) -> AccConfigBuilder<T> {
AccConfigBuilder::new(self)
}
pub fn config_interrupts(&mut self) -> IntConfigBuilder<T> {
IntConfigBuilder::new(self)
}
pub fn config_int_pins(&mut self) -> IntPinConfigBuilder<T> {
IntPinConfigBuilder::new(self)
}
pub fn config_fifo(&mut self) -> FifoConfigBuilder<T> {
FifoConfigBuilder::new(self)
}
pub fn config_auto_lp(&mut self) -> AutoLpConfigBuilder<T> {
AutoLpConfigBuilder::new(self)
}
pub fn config_autowkup(&mut self) -> AutoWakeupConfigBuilder<T> {
AutoWakeupConfigBuilder::new(self)
}
pub fn config_wkup_int(&mut self) -> WakeupIntConfigBuilder<T> {
WakeupIntConfigBuilder::new(self)
}
pub fn config_orientchg_int(&mut self) -> OrientChgConfigBuilder<T> {
OrientChgConfigBuilder::new(self)
}
pub fn config_gen1_int(&mut self) -> GenIntConfigBuilder<T> {
GenIntConfigBuilder::new_gen1(self)
}
pub fn config_gen2_int(&mut self) -> GenIntConfigBuilder<T> {
GenIntConfigBuilder::new_gen2(self)
}
pub fn config_actchg_int(&mut self) -> ActChgConfigBuilder<T> {
ActChgConfigBuilder::new(self)
}
pub fn config_tap(&mut self) -> TapConfigBuilder<T> {
TapConfigBuilder::new(self)
}
pub fn perform_self_test<Timer: DelayMs<u8>>(&mut self, timer: &mut Timer) -> Result<(), BMA400Error<InterfaceError, PinError>> {
self.config.setup_self_test(&mut self.interface)?;
timer.delay_ms(2);
self.interface.write_register(SelfTest::from_bits_truncate(0x07))?;
timer.delay_ms(50);
let m_pos = self.get_unscaled_data()?;
self.interface.write_register(SelfTest::from_bits_truncate(0x0F))?;
timer.delay_ms(50);
let m_neg = self.get_unscaled_data()?;
let (x, y, z) = (m_pos.x - m_neg.x, m_pos.y - m_neg.y, m_pos.z - m_neg.z);
self.interface.write_register(SelfTest::default())?;
timer.delay_ms(50);
self.config.cleanup_self_test(&mut self.interface)?;
if x > 1500 && y > 1200 && z > 250 {
Ok(())
} else {
Err(BMA400Error::SelfTestFailedError)
}
}
pub fn soft_reset(&mut self) -> Result<(), BMA400Error<InterfaceError, PinError>> {
self.interface.write_register(Command::SoftReset)?;
self.config = Config::default();
let mut buffer = [0u8; 1];
self.interface.read_register(Event, &mut buffer)?;
Ok(())
}
pub fn destroy(self) -> T {
self.interface
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
interface::{
ReadFromRegister,
WriteToRegister,
},
registers::{
ReadReg,
ConfigReg,
},
BMA400,
};
pub struct NoOpInterface;
#[derive(Debug)]
pub struct NoOpError;
impl ReadFromRegister for NoOpInterface {
type Error = BMA400Error<NoOpError, ()>;
fn read_register<T: ReadReg>(&mut self, _register: T, _buffer: &mut [u8]) -> Result<(), Self::Error> {
Ok(())
}
}
impl WriteToRegister for NoOpInterface {
type Error = BMA400Error<NoOpError, ()>;
fn write_register<T: ConfigReg>(&mut self, _register: T) -> Result<(), Self::Error> {
Ok(())
}
}
pub fn get_test_device() -> BMA400<NoOpInterface> {
BMA400 {
interface: NoOpInterface,
config: Config::default(),
}
}
}