mod bmi270;
pub use bmi270::*;
pub use embedded_hal::blocking::spi::*;
pub use linux_embedded_hal::spidev::{SpiModeFlags, SpidevOptions};
pub use linux_embedded_hal::Spidev;
use std::time::Duration;
pub struct Bmi270<C> {
communication: C,
acc_range: f64,
gyr_range: f64,
}
impl Bmi270Write for Bmi270<Spidev> {
fn bmi270_write(&mut self, addr: u8, value: &[u8]) {
let mut words = vec![addr];
words.extend_from_slice(value);
self.communication.write(&words).unwrap();
}
}
impl Bmi270ReadWrite for Bmi270<Spidev> {
fn bmi270_read_write(&mut self, addr: u8, len: usize) -> Vec<u8> {
let mut tx_buff = vec![addr | 0x80];
tx_buff.extend_from_slice(&vec![0xff; len + 1]);
self.communication.transfer(&mut tx_buff).unwrap();
tx_buff[2..].to_vec()
}
}
impl Bmi270<Spidev> {
pub fn new(spi: Spidev, config: Bmi270Config) -> Self {
let mut imu = Self {
communication: spi,
acc_range: 0.0,
gyr_range: 0.0,
};
while imu.bmi270_read_write(ADDR_CHIP_ID, 1)[0] != 0x24 {
println!("等待陀螺仪连接,检查陀螺仪连线");
}
println!("已检测到陀螺仪,尝试初始化");
imu.bmi270_write(ADDR_POWER_CNF, &[0x00]);
imu.bmi270_write(ADDR_INIT_CTRL, &[0x00]);
std::thread::sleep(Duration::from_millis(100)); imu.bmi270_write(ADDR_INIT_WRITE, &BMI270_CONFIG_FILE);
imu.bmi270_write(ADDR_INIT_CTRL, &[0x01]);
std::thread::sleep(Duration::from_secs(2));
while imu.bmi270_read_write(ADDR_INIT_CHECK, 1)[0] & 0x01 == 0 {
println!("初始化失败,继续等待可能会完成初始化,检测配置文件或者延长等待时间");
}
if config.acc_ord.is_some() {
unsafe {
let conf_value = (0_u8 | config.acc_ord.unwrap_unchecked() as u8)
| (0_u8 | ((config.acc_bwp.unwrap_unchecked() as u8) << 4)) & 0x80;
imu.bmi270_write(ADDR_ACC_CONF, &[conf_value]);
imu.bmi270_write(ADDR_ACC_RANGE, &[config.acc_range.unwrap_unchecked() as u8]);
}
}
if config.gyr_ord.is_some() {
unsafe {
let conf_value = (0_u8 | config.gyr_ord.unwrap_unchecked() as u8)
| (0_u8 | ((config.gyr_bwp.unwrap_unchecked() as u8) << 4)) & 0xc0;
imu.bmi270_write(ADDR_GYR_CONF, &[conf_value]);
imu.bmi270_write(ADDR_GYR_RANGE, &[config.gyr_range.unwrap_unchecked() as u8]);
}
}
imu.bmi270_write(ADDR_POWER_CTRL, &[0x0e]);
unsafe {
imu.acc_range = config.acc_range.unwrap_unchecked().to_sensitivity();
imu.gyr_range = config.gyr_range.unwrap_unchecked().to_sensitivity();
}
imu
}
}
impl Bmi270Data for Bmi270<Spidev> {
fn acc(&mut self) -> [f64; 3] {
unsafe {
self.bmi270_read_write(ADDR_ACC_DATA, 6)
.chunks_exact(2)
.map(|blocks| {
i16::from_le_bytes(blocks.try_into().unwrap_unchecked()) as f64 / self.acc_range
})
.collect::<Vec<f64>>()
.try_into()
.unwrap()
}
}
fn acc_gyr(&mut self) -> [f64; 6] {
unsafe {
let mut f: [f64; 6] = self
.bmi270_read_write(ADDR_ACC_DATA, 12)
.chunks_exact(2)
.map(|blocks| i16::from_le_bytes(blocks.try_into().unwrap_unchecked()) as f64)
.collect::<Vec<f64>>()
.try_into()
.unwrap();
f[0] = f[0] / self.acc_range;
f[1] = f[1] / self.acc_range;
f[2] = f[2] / self.acc_range;
f[3] = f[3] / self.gyr_range;
f[4] = f[4] / self.gyr_range;
f[5] = f[5] / self.gyr_range;
f
}
}
fn gyr(&mut self) -> [f64; 3] {
unsafe {
self.bmi270_read_write(ADDR_GYR_DATA, 6)
.chunks_exact(2)
.map(|blocks| {
i16::from_le_bytes(blocks.try_into().unwrap_unchecked()) as f64 / self.gyr_range
})
.collect::<Vec<f64>>()
.try_into()
.unwrap()
}
}
fn temperature(&mut self) -> f64 {
todo!()
}
}