From fa4cc738e02e30b685906da782b0a98ae90067c7 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Mon, 26 Feb 2024 19:44:08 +0200 Subject: [PATCH 01/18] simplify error handling --- examples/read_sensor_data.rs | 7 ++- src/lib.rs | 93 ++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 56 deletions(-) diff --git a/examples/read_sensor_data.rs b/examples/read_sensor_data.rs index 9fb14da..fd4035c 100644 --- a/examples/read_sensor_data.rs +++ b/examples/read_sensor_data.rs @@ -1,16 +1,15 @@ #![no_std] -use bme680::{Bme680, Error, I2CAddress, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; -use core::result; +use bme680::{Bme680, Bme680Error, I2CAddress, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; use core::time::Duration; use embedded_hal::delay::DelayNs; use linux_embedded_hal as hal; -use linux_embedded_hal::{Delay, I2CError}; +use linux_embedded_hal::{Delay}; use log::info; // Please export RUST_LOG=info in order to see logs in the console. -fn main() -> result::Result<(), Error> +fn main() -> Result<(), Bme680Error> { env_logger::init(); diff --git a/src/lib.rs b/src/lib.rs index ec4685c..480efcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,13 +77,13 @@ use crate::hal::delay::DelayNs; use crate::hal::i2c::I2c; use core::time::Duration; -use core::{marker::PhantomData, result}; +use core::{marker::PhantomData}; use embedded_hal as hal; -use embedded_hal::i2c::ErrorType; use log::{debug, error, info}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use crate::Bme680Error::{I2CRead, I2CWrite}; /// BME680 General config pub const BME680_POLL_PERIOD_MS: u8 = 10; @@ -150,12 +150,12 @@ const BME680_REG_BUFFER_LENGTH: usize = 6; /// All possible errors in this crate #[derive(Debug)] -pub enum Error { +pub enum Bme680Error { /// /// aka BME680_E_COM_FAIL /// - I2CWrite(E), - I2CRead(E), + I2CWrite, + I2CRead, Delay, /// /// aka BME680_E_DEV_NOT_FOUND @@ -179,9 +179,6 @@ pub enum Error { BoundaryCheckFailure(&'static str), } -/// Abbreviates `std::result::Result` type -pub type Result = result::Result>; - /// /// Power mode settings /// @@ -192,7 +189,6 @@ pub enum PowerMode { } impl PowerMode { - // TODO replace with TryFrom once stabilized fn from(power_mode: u8) -> Self { match power_mode { BME680_SLEEP_MODE => PowerMode::SleepMode, @@ -243,7 +239,7 @@ impl Default for I2CAddress { } } -/// Calibration data used during initalization +/// Calibration data used during initialization #[derive(Debug, Default, Copy)] #[repr(C)] pub struct CalibrationData { @@ -358,17 +354,17 @@ impl I2CUtil { i2c: &mut I2C, dev_id: u8, reg_addr: u8, - ) -> Result::Error> + ) -> Result where I2C: I2c { let mut buf = [0; 1]; - i2c.write(dev_id, &[reg_addr]).map_err(Error::I2CWrite)?; + i2c.write(dev_id, &[reg_addr]).map_err(|_e| { I2CWrite })?; match i2c.read(dev_id, &mut buf) { Ok(()) => Ok(buf[0]), - Err(e) => Err(Error::I2CRead(e)), + Err(_e) => Err(I2CRead), } } @@ -377,15 +373,15 @@ impl I2CUtil { dev_id: u8, reg_addr: u8, buf: &mut [u8], - ) -> Result<(), ::Error> + ) -> Result<(), Bme680Error> where I2C: I2c, { - i2c.write(dev_id, &[reg_addr]).map_err(Error::I2CWrite)?; + i2c.write(dev_id, &[reg_addr]).map_err(|_e| { Bme680Error::I2CWrite })?; match i2c.read(dev_id, buf) { Ok(()) => Ok(()), - Err(e) => Err(Error::I2CRead(e)), + Err(_e) => Err(I2CRead), } } } @@ -410,22 +406,22 @@ fn boundary_check( value_name: &'static str, min: u8, max: u8, -) -> Result::Error> +) -> Result> where I2C: I2c, { - let value = value.ok_or(Error::BoundaryCheckFailure(value_name))?; + let value = value.ok_or(Bme680Error::BoundaryCheckFailure(value_name))?; if value < min { const MIN: &str = "Boundary check failure, value exceeds maximum"; error!("{}, value name: {}", MIN, value_name); - return Err(Error::BoundaryCheckFailure(MIN)); + return Err(Bme680Error::BoundaryCheckFailure(MIN)); } if value > max { const MAX: &str = "Boundary check, value exceeds minimum"; error!("{}, value name: {}", MAX, value_name); - return Err(Error::BoundaryCheckFailure(MAX)); + return Err(Bme680Error::BoundaryCheckFailure(MAX)); } Ok(value) } @@ -439,11 +435,10 @@ impl Bme680 i2c: &mut I2C, delay: &mut D, dev_id: I2CAddress, - ) -> Result<(), ::Error> { + ) -> Result<(), Bme680Error> { let tmp_buff: [u8; 2] = [BME680_SOFT_RESET_ADDR, BME680_SOFT_RESET_CMD]; - i2c.write(dev_id.addr(), &tmp_buff) - .map_err(Error::I2CWrite)?; + i2c.write(dev_id.addr(), &tmp_buff).map_err(|_e| { Bme680Error::I2CWrite })?; delay.delay_ms(BME680_RESET_PERIOD as u32); Ok(()) @@ -453,7 +448,7 @@ impl Bme680 mut i2c: I2C, delay: &mut D, dev_id: I2CAddress, - ) -> Result, ::Error> { + ) -> Result, Bme680Error> { Bme680::soft_reset(&mut i2c, delay, dev_id)?; debug!("Reading chip id"); @@ -478,16 +473,16 @@ impl Bme680 Ok(dev) } else { error!("Device does not match chip id {}", BME680_CHIP_ID); - Err(Error::DeviceNotFound) + Err(Bme680Error::DeviceNotFound) } } fn bme680_set_regs( &mut self, reg: &[(u8, u8)], - ) -> Result<(), ::Error> { + ) -> Result<(), Bme680Error> { if reg.is_empty() || reg.len() > (BME680_TMP_BUFFER_LENGTH / 2) as usize { - return Err(Error::InvalidLength); + return Err(Bme680Error::InvalidLength); } for (reg_addr, reg_data) in reg { @@ -498,7 +493,7 @@ impl Bme680 ); self.i2c .write(self.dev_id.addr(), &tmp_buff) - .map_err(Error::I2CWrite)?; + .map_err(|_e| { I2CWrite })?; } Ok(()) @@ -509,7 +504,7 @@ impl Bme680 &mut self, delay: &mut D, settings: Settings, - ) -> Result<(), ::Error> { + ) -> Result<(), Bme680Error> { let (sensor_settings, desired_settings) = settings; let tph_sett = sensor_settings.tph_sett; let gas_sett = sensor_settings.gas_sett; @@ -636,7 +631,7 @@ impl Bme680 pub fn get_sensor_settings( &mut self, desired_settings: DesiredSensorSettings, - ) -> Result::Error> { + ) -> Result { let reg_addr: u8 = 0x70u8; let mut data_array: [u8; BME680_REG_BUFFER_LENGTH] = [0; BME680_REG_BUFFER_LENGTH]; let mut sensor_settings: SensorSettings = Default::default(); @@ -692,7 +687,7 @@ impl Bme680 &mut self, delay: &mut D, target_power_mode: PowerMode, - ) -> Result<(), ::Error> { + ) -> Result<(), Bme680Error> { let mut tmp_pow_mode: u8; let mut current_power_mode: PowerMode; @@ -714,7 +709,6 @@ impl Bme680 delay .delay_ms(BME680_POLL_PERIOD_MS as u32); } else { - // TODO do while in Rust? break; } } @@ -731,7 +725,7 @@ impl Bme680 /// Retrieve current sensor power mode via registers pub fn get_sensor_mode( &mut self, - ) -> Result::Error> { + ) -> Result { let regs = I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_T_P_MODE_ADDR)?; let mode = regs & BME680_MODE_MSK; @@ -740,8 +734,6 @@ impl Bme680 pub fn bme680_set_profile_dur(&mut self, tph_sett: TphSett, duration: Duration) { let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; - // TODO check if the following unwrap_ors do not change behaviour - // TODO replace once https://github.com/rust-lang/rust/pull/50167 has been merged const MILLIS_PER_SEC: u64 = 1_000; const NANOS_PER_MILLI: u64 = 1_000_000; let millis = (duration.as_secs() as u64 * MILLIS_PER_SEC) @@ -770,9 +762,8 @@ impl Bme680 pub fn get_profile_dur( &self, sensor_settings: &SensorSettings, - ) -> Result::Error> { + ) -> Result { let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; - // TODO check if the following unwrap_ors do not change behaviour let mut meas_cycles = os_to_meas_cycles[sensor_settings .tph_sett .os_temp @@ -806,7 +797,7 @@ impl Bme680 fn get_calib_data( i2c: &mut I2CX, dev_id: I2CAddress, - ) -> Result::Error> + ) -> Result where I2CX: I2c, { @@ -820,7 +811,7 @@ impl Bme680 dev_id.addr(), BME680_COEFF_ADDR1, &mut coeff_array[0..(BME680_COEFF_ADDR1_LEN - 1)], - ).unwrap(); + ).map_err(|_e| { I2CRead })?; I2CUtil::read_bytes::( i2c, @@ -828,7 +819,7 @@ impl Bme680 BME680_COEFF_ADDR2, &mut coeff_array [BME680_COEFF_ADDR1_LEN..(BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN - 1)], - ).unwrap(); + ).map_err(|_e| { I2CRead })?; calib.par_t1 = ((coeff_array[34usize] as i32) << 8i32 | coeff_array[33usize] as i32) as u16; calib.par_t2 = ((coeff_array[2usize] as i32) << 8i32 | coeff_array[1usize] as i32) as i16; @@ -858,17 +849,16 @@ impl Bme680 calib.par_gh3 = coeff_array[38usize] as i8; calib.res_heat_range = - (I2CUtil::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_RANGE_ADDR).unwrap() - & 0x30) - / 16; + (I2CUtil::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_RANGE_ADDR) + .map_err(|_e| { I2CRead })? & 0x30) / 16; calib.res_heat_val = - I2CUtil::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_VAL_ADDR).unwrap() as i8; + I2CUtil::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_VAL_ADDR) + .map_err(|_e| { I2CRead })? as i8; calib.range_sw_err = - (I2CUtil::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RANGE_SW_ERR_ADDR).unwrap() - & BME680_RSERROR_MSK) - / 16; + (I2CUtil::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RANGE_SW_ERR_ADDR) + .map_err(|_e| { I2CRead })? & BME680_RSERROR_MSK) / 16; Ok(calib) } @@ -876,12 +866,11 @@ impl Bme680 fn set_gas_config( &mut self, gas_sett: GasSett, - ) -> Result<(), ::Error> { + ) -> Result<(), Bme680Error> { if self.power_mode != PowerMode::ForcedMode { - return Err(Error::DefinePwrMode); + return Err(Bme680Error::DefinePwrMode); } - // TODO check whether unwrap_or changes behaviour let reg: [(u8, u8); 2] = [ ( BME680_RES_HEAT0_ADDR, @@ -901,7 +890,7 @@ impl Bme680 self.bme680_set_regs(®) } - fn get_gas_config(&mut self) -> Result::Error> { + fn get_gas_config(&mut self) -> Result { let heatr_temp = Some(I2CUtil::read_byte( &mut self.i2c, self.dev_id.addr(), @@ -927,7 +916,7 @@ impl Bme680 pub fn get_sensor_data( &mut self, delay: &mut D, - ) -> Result<(FieldData, FieldDataCondition), ::Error> { + ) -> Result<(FieldData, FieldDataCondition), Bme680Error> { let mut buff: [u8; BME680_FIELD_LENGTH] = [0; BME680_FIELD_LENGTH]; debug!("Buf {:?}, len: {}", buff, buff.len()); From 30b60b20f3e99914214b94e799c78bd91dff4823 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Mon, 26 Feb 2024 20:13:10 +0200 Subject: [PATCH 02/18] fix lib.rs doc test --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 480efcc..711a8d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ //! ```no_run -//! use bme680::{Bme680, Error, I2CAddress, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; +//! use bme680::{Bme680, Bme680Error, I2CAddress, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; //! use core::result; //! use core::time::Duration; //! use embedded_hal::delay::DelayNs; @@ -15,7 +15,7 @@ //! use log::info; //! //! // Please export RUST_LOG=info in order to see logs in the console. -//! fn main() -> result::Result<(), Error> +//! fn main() -> result::Result<(), Bme680Error> //! { //! env_logger::init(); //! From 6eee3c16425f30d13fa0f80c58fbd4d0544a699b Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Mon, 26 Feb 2024 20:40:23 +0200 Subject: [PATCH 03/18] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 927b4d4..461a878 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ To use this library, create a new project and add it as a dependency: ```toml [dependencies] -bme680 = {git = "https://github.com/dnutiu/bme680-rust.git", version = "0.7.0"} +bme680 = {git = "https://github.com/dnutiu/bme680-rust.git", version = "0.8.0"} ``` # Alternative From 99923f31e5a8d6cb04b7700e76cc3dee31c62a03 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Mon, 26 Feb 2024 21:06:36 +0200 Subject: [PATCH 04/18] refactor: rename struct fields --- src/lib.rs | 144 ++++++++++++++++++++--------------------------------- 1 file changed, 54 insertions(+), 90 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 711a8d0..8033c3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -206,18 +206,13 @@ impl PowerMode { } /// -/// I2C Slave Address -/// To determine the slave address of your device you can use `i2cdetect -y 1` on linux. -/// The 7-bit device address is 111011x. The 6 MSB bits are fixed. -/// The last bit is changeable by SDO value and can be changed during operation. -/// Connecting SDO to GND results in slave address 1110110 (0x76); connecting it to V DDIO results in slave -/// address 1110111 (0x77), which is the same as BMP280’s I2C address. +/// I2C Address represents the I2C address of the BME680 Sensor. /// #[derive(Debug, Clone, Copy)] pub enum I2CAddress { - /// Primary Slave Address 0x76 + /// Primary Address 0x76 Primary, - /// Secondary Slave Address 0x77 + /// Secondary Address 0x77 Secondary, /// Alternative address Other(u8), @@ -287,7 +282,7 @@ pub struct FieldData { /// Index of heater profile used gas_index: u8, /// Measurement index - meas_index: u8, + measurement_index: u8, temperature: i16, pressure: u32, humidity: u32, @@ -347,9 +342,10 @@ pub enum FieldDataCondition { Unchanged, } -struct I2CUtil {} +/// I2CUtility is a simple wrapper over the I2c trait to make reading and writing data easier. +struct I2CUtility {} -impl I2CUtil { +impl I2CUtility { pub fn read_byte( i2c: &mut I2C, dev_id: u8, @@ -377,7 +373,7 @@ impl I2CUtil { where I2C: I2c, { - i2c.write(dev_id, &[reg_addr]).map_err(|_e| { Bme680Error::I2CWrite })?; + i2c.write(dev_id, &[reg_addr]).map_err(|_e| { I2CWrite })?; match i2c.read(dev_id, buf) { Ok(()) => Ok(()), @@ -389,14 +385,11 @@ impl I2CUtil { /// Driver for the BME680 environmental sensor #[repr(C)] pub struct Bme680 { - i2c: I2C, + i2c_bus_handle: I2C, delay: PhantomData, - dev_id: I2CAddress, - calib: CalibrationData, - // TODO remove ? as it may not reflect the state of the device - tph_sett: TphSett, - // TODO remove ? as it may not reflect the state of the device - gas_sett: GasSett, + device_address: I2CAddress, + calibration_data: CalibrationData, + temperature_offset: f32, // TODO remove ? as it may not reflect the state of the device power_mode: PowerMode, } @@ -438,7 +431,7 @@ impl Bme680 ) -> Result<(), Bme680Error> { let tmp_buff: [u8; 2] = [BME680_SOFT_RESET_ADDR, BME680_SOFT_RESET_CMD]; - i2c.write(dev_id.addr(), &tmp_buff).map_err(|_e| { Bme680Error::I2CWrite })?; + i2c.write(dev_id.addr(), &tmp_buff).map_err(|_e| { I2CWrite })?; delay.delay_ms(BME680_RESET_PERIOD as u32); Ok(()) @@ -453,7 +446,7 @@ impl Bme680 debug!("Reading chip id"); /* Soft reset to restore it to default values*/ - let chip_id = I2CUtil::read_byte::(&mut i2c, dev_id.addr(), BME680_CHIP_ID_ADDR)?; + let chip_id = I2CUtility::read_byte::(&mut i2c, dev_id.addr(), BME680_CHIP_ID_ADDR)?; debug!("Chip id: {}", chip_id); if chip_id == BME680_CHIP_ID { @@ -461,13 +454,12 @@ impl Bme680 let calibration = Bme680::::get_calib_data::(&mut i2c, dev_id)?; debug!("Calibration data {:?}", calibration); let dev = Bme680 { - i2c, + i2c_bus_handle: i2c, delay: PhantomData, - dev_id, - calib: calibration, + device_address: dev_id, + calibration_data: calibration, + temperature_offset: 0.0, power_mode: PowerMode::ForcedMode, - tph_sett: Default::default(), - gas_sett: Default::default(), }; info!("Finished device init"); Ok(dev) @@ -491,8 +483,8 @@ impl Bme680 "Setting register reg: {:?} tmp_buf: {:?}", reg_addr, tmp_buff ); - self.i2c - .write(self.dev_id.addr(), &tmp_buff) + self.i2c_bus_handle + .write(self.device_address.addr(), &tmp_buff) .map_err(|_e| { I2CWrite })?; } @@ -509,6 +501,8 @@ impl Bme680 let tph_sett = sensor_settings.tph_sett; let gas_sett = sensor_settings.gas_sett; + self.temperature_offset = sensor_settings.tph_sett.temperature_offset.unwrap_or(0f32); + let mut reg: [(u8, u8); BME680_REG_BUFFER_LENGTH] = [(0, 0); BME680_REG_BUFFER_LENGTH]; let intended_power_mode = self.power_mode; @@ -524,7 +518,7 @@ impl Bme680 // Selecting the filter if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) { let mut data = - I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_ODR_FILT_ADDR)?; + I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_ODR_FILT_ADDR)?; debug!("FILTER_SEL: true"); data = (data as i32 & !0x1ci32 @@ -538,9 +532,9 @@ impl Bme680 debug!("HCNTRL_SEL: true"); let gas_sett_heatr_ctrl = boundary_check::(gas_sett.heatr_ctrl, "GasSett.heatr_ctrl", 0x0u8, 0x8u8)?; - let mut data = I2CUtil::read_byte( - &mut self.i2c, - self.dev_id.addr(), + let mut data = I2CUtility::read_byte( + &mut self.i2c_bus_handle, + self.device_address.addr(), BME680_CONF_HEAT_CTRL_ADDR, )?; data = (data as i32 & !0x8i32 | gas_sett_heatr_ctrl as i32 & 0x8) as u8; @@ -553,7 +547,7 @@ impl Bme680 .contains(DesiredSensorSettings::OST_SEL | DesiredSensorSettings::OSP_SEL) { let mut data = - I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_T_P_MODE_ADDR)?; + I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR)?; if desired_settings.contains(DesiredSensorSettings::OST_SEL) { debug!("OST_SEL: true"); @@ -581,7 +575,7 @@ impl Bme680 let tph_sett_os_hum = boundary_check::(tph_sett.os_hum.map(|x| x as u8), "TphSett.os_hum", 0, 5)?; let mut data = - I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_OS_H_ADDR)?; + I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_OS_H_ADDR)?; data = (data as i32 & !0x7i32 | tph_sett_os_hum as i32 & 0x7i32) as u8; reg[element_index] = (BME680_CONF_OS_H_ADDR, data); element_index += 1; @@ -591,9 +585,9 @@ impl Bme680 if desired_settings .contains(DesiredSensorSettings::RUN_GAS_SEL | DesiredSensorSettings::NBCONV_SEL) { - let mut data = I2CUtil::read_byte( - &mut self.i2c, - self.dev_id.addr(), + let mut data = I2CUtility::read_byte( + &mut self.i2c_bus_handle, + self.device_address.addr(), BME680_CONF_ODR_RUN_GAS_NBC_ADDR, )?; @@ -619,7 +613,6 @@ impl Bme680 // Restore previous intended power mode self.power_mode = intended_power_mode; - self.tph_sett = tph_sett; Ok(()) } @@ -635,9 +628,8 @@ impl Bme680 let reg_addr: u8 = 0x70u8; let mut data_array: [u8; BME680_REG_BUFFER_LENGTH] = [0; BME680_REG_BUFFER_LENGTH]; let mut sensor_settings: SensorSettings = Default::default(); - sensor_settings.tph_sett.temperature_offset = self.tph_sett.temperature_offset; - I2CUtil::read_bytes(&mut self.i2c, self.dev_id.addr(), reg_addr, &mut data_array)?; + I2CUtility::read_bytes(&mut self.i2c_bus_handle, self.device_address.addr(), reg_addr, &mut data_array)?; if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL) { sensor_settings.gas_sett = self.get_gas_config()?; @@ -694,7 +686,7 @@ impl Bme680 // Call repeatedly until in sleep loop { tmp_pow_mode = - I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_T_P_MODE_ADDR)?; + I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR)?; // Put to sleep before changing mode current_power_mode = PowerMode::from(tmp_pow_mode & BME680_MODE_MSK); @@ -727,38 +719,11 @@ impl Bme680 &mut self, ) -> Result { let regs = - I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_T_P_MODE_ADDR)?; + I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR)?; let mode = regs & BME680_MODE_MSK; Ok(PowerMode::from(mode)) } - pub fn bme680_set_profile_dur(&mut self, tph_sett: TphSett, duration: Duration) { - let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; - const MILLIS_PER_SEC: u64 = 1_000; - const NANOS_PER_MILLI: u64 = 1_000_000; - let millis = (duration.as_secs() as u64 * MILLIS_PER_SEC) - + (duration.subsec_nanos() as u64 / NANOS_PER_MILLI); - - let mut meas_cycles = os_to_meas_cycles - [tph_sett.os_temp.unwrap_or(OversamplingSetting::OSNone) as usize] - as u64; - meas_cycles = meas_cycles.wrapping_add( - os_to_meas_cycles[tph_sett.os_pres.unwrap_or(OversamplingSetting::OSNone) as usize] - as u64, - ); - meas_cycles = meas_cycles.wrapping_add( - os_to_meas_cycles[tph_sett.os_hum.unwrap_or(OversamplingSetting::OSNone) as usize] - as u64, - ); - let mut tph_dur = meas_cycles.wrapping_mul(1963u64); - tph_dur = tph_dur.wrapping_add(477u64.wrapping_mul(4u64)); - tph_dur = tph_dur.wrapping_add(477u64.wrapping_mul(5u64)); - tph_dur = tph_dur.wrapping_add(500u64); - tph_dur = tph_dur.wrapping_div(1000u64); - tph_dur = tph_dur.wrapping_add(1u64); - self.gas_sett.heatr_dur = Some(Duration::from_millis(millis - tph_dur)); - } - pub fn get_profile_dur( &self, sensor_settings: &SensorSettings, @@ -806,14 +771,14 @@ impl Bme680 let mut coeff_array: [u8; BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN] = [0; BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN]; - I2CUtil::read_bytes::( + I2CUtility::read_bytes::( i2c, dev_id.addr(), BME680_COEFF_ADDR1, &mut coeff_array[0..(BME680_COEFF_ADDR1_LEN - 1)], ).map_err(|_e| { I2CRead })?; - I2CUtil::read_bytes::( + I2CUtility::read_bytes::( i2c, dev_id.addr(), BME680_COEFF_ADDR2, @@ -849,15 +814,15 @@ impl Bme680 calib.par_gh3 = coeff_array[38usize] as i8; calib.res_heat_range = - (I2CUtil::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_RANGE_ADDR) + (I2CUtility::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_RANGE_ADDR) .map_err(|_e| { I2CRead })? & 0x30) / 16; calib.res_heat_val = - I2CUtil::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_VAL_ADDR) + I2CUtility::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_VAL_ADDR) .map_err(|_e| { I2CRead })? as i8; calib.range_sw_err = - (I2CUtil::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RANGE_SW_ERR_ADDR) + (I2CUtility::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RANGE_SW_ERR_ADDR) .map_err(|_e| { I2CRead })? & BME680_RSERROR_MSK) / 16; Ok(calib) @@ -875,7 +840,7 @@ impl Bme680 ( BME680_RES_HEAT0_ADDR, Calculation::heater_resistance( - &self.calib, + &self.calibration_data, gas_sett.ambient_temperature, gas_sett.heatr_temp.unwrap_or(0), ), @@ -886,20 +851,19 @@ impl Bme680 ), ]; - self.gas_sett.nb_conv = 0; self.bme680_set_regs(®) } fn get_gas_config(&mut self) -> Result { - let heatr_temp = Some(I2CUtil::read_byte( - &mut self.i2c, - self.dev_id.addr(), + let heatr_temp = Some(I2CUtility::read_byte( + &mut self.i2c_bus_handle, + self.device_address.addr(), BME680_ADDR_SENS_CONF_START, )? as u16); - let heatr_dur_ms = I2CUtil::read_byte( - &mut self.i2c, - self.dev_id.addr(), + let heatr_dur_ms = I2CUtility::read_byte( + &mut self.i2c_bus_handle, + self.device_address.addr(), BME680_ADDR_GAS_CONF_START, )? as u64; @@ -924,9 +888,9 @@ impl Bme680 const TRIES: u8 = 10; for _ in 0..TRIES { - I2CUtil::read_bytes( - &mut self.i2c, - self.dev_id.addr(), + I2CUtility::read_bytes( + &mut self.i2c_bus_handle, + self.device_address.addr(), BME680_FIELD0_ADDR, &mut buff, )?; @@ -935,7 +899,7 @@ impl Bme680 data.status = buff[0] & BME680_NEW_DATA_MSK; data.gas_index = buff[0] & BME680_GAS_INDEX_MSK; - data.meas_index = buff[1]; + data.measurement_index = buff[1]; let adc_pres = (buff[2] as u32).wrapping_mul(4096) | (buff[3] as u32).wrapping_mul(16) @@ -953,16 +917,16 @@ impl Bme680 if data.status & BME680_NEW_DATA_MSK != 0 { let (temp, t_fine) = - Calculation::temperature(&self.calib, adc_temp, self.tph_sett.temperature_offset); + Calculation::temperature(&self.calibration_data, adc_temp, Some(self.temperature_offset)); debug!( "adc_temp: {} adc_pres: {} adc_hum: {} adc_gas_res: {}, t_fine: {}", adc_temp, adc_pres, adc_hum, adc_gas_res, t_fine ); data.temperature = temp; - data.pressure = Calculation::pressure(&self.calib, t_fine, adc_pres); - data.humidity = Calculation::humidity(&self.calib, t_fine, adc_hum); + data.pressure = Calculation::pressure(&self.calibration_data, t_fine, adc_pres); + data.humidity = Calculation::humidity(&self.calibration_data, t_fine, adc_hum); data.gas_resistance = - Calculation::gas_resistance(&self.calib, adc_gas_res, gas_range); + Calculation::gas_resistance(&self.calibration_data, adc_gas_res, gas_range); return Ok((data, FieldDataCondition::NewData)); } From cb90ea40e406d067406c7ed630e0ab38d980c6b3 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Mon, 26 Feb 2024 21:25:31 +0200 Subject: [PATCH 05/18] refactor: remove generic type from boundary_check_u8 --- src/lib.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8033c3a..5d0b8a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -180,7 +180,7 @@ pub enum Bme680Error { } /// -/// Power mode settings +/// Power mode settings of the sensor. /// #[derive(Debug, PartialEq, Clone, Copy)] pub enum PowerMode { @@ -390,18 +390,22 @@ pub struct Bme680 { device_address: I2CAddress, calibration_data: CalibrationData, temperature_offset: f32, - // TODO remove ? as it may not reflect the state of the device power_mode: PowerMode, } -fn boundary_check( +/// Checks if an u8 value is within the boundary and returns a Result containing an error +/// if the value is not within the boundary. +/// +/// * `value` - The value to check for +/// * `value_name` - The name of the value +/// * `min` - The minimum boundary. +/// * `max` - The maximum boundary. +fn boundary_check_u8( value: Option, value_name: &'static str, min: u8, max: u8, ) -> Result> - where - I2C: I2c, { let value = value.ok_or(Bme680Error::BoundaryCheckFailure(value_name))?; @@ -531,7 +535,7 @@ impl Bme680 if desired_settings.contains(DesiredSensorSettings::HCNTRL_SEL) { debug!("HCNTRL_SEL: true"); let gas_sett_heatr_ctrl = - boundary_check::(gas_sett.heatr_ctrl, "GasSett.heatr_ctrl", 0x0u8, 0x8u8)?; + boundary_check_u8(gas_sett.heatr_ctrl, "GasSett.heatr_ctrl", 0x0u8, 0x8u8)?; let mut data = I2CUtility::read_byte( &mut self.i2c_bus_handle, self.device_address.addr(), @@ -551,7 +555,7 @@ impl Bme680 if desired_settings.contains(DesiredSensorSettings::OST_SEL) { debug!("OST_SEL: true"); - let tph_sett_os_temp = boundary_check::( + let tph_sett_os_temp = boundary_check_u8( tph_sett.os_temp.map(|x| x as u8), "TphSett.os_temp", 0, @@ -573,7 +577,7 @@ impl Bme680 if desired_settings.contains(DesiredSensorSettings::OSH_SEL) { debug!("OSH_SEL: true"); let tph_sett_os_hum = - boundary_check::(tph_sett.os_hum.map(|x| x as u8), "TphSett.os_hum", 0, 5)?; + boundary_check_u8(tph_sett.os_hum.map(|x| x as u8), "TphSett.os_hum", 0, 5)?; let mut data = I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_OS_H_ADDR)?; data = (data as i32 & !0x7i32 | tph_sett_os_hum as i32 & 0x7i32) as u8; @@ -601,7 +605,7 @@ impl Bme680 if desired_settings.contains(DesiredSensorSettings::NBCONV_SEL) { debug!("NBCONV_SEL: true"); let gas_sett_nb_conv = - boundary_check::(Some(gas_sett.nb_conv), "GasSett.nb_conv", 0, 10)?; + boundary_check_u8(Some(gas_sett.nb_conv), "GasSett.nb_conv", 0, 10)?; data = (data as i32 & !0xfi32 | gas_sett_nb_conv as i32 & 0xfi32) as u8; } From 43991b5e24dcd7d80a3aaef601805dc892ee2307 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Mon, 26 Feb 2024 21:34:57 +0200 Subject: [PATCH 06/18] refactor: add docstrings to calculation --- src/calculation.rs | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/calculation.rs b/src/calculation.rs index 14c3e1c..43ee7bf 100644 --- a/src/calculation.rs +++ b/src/calculation.rs @@ -5,9 +5,13 @@ use core::time::Duration; pub struct Calculation {} impl Calculation { - pub fn heater_resistance(calibration_data: &CalibrationData, ambient_temperature: i8, temperature: u16) -> u8 { + /// Calculates and returns the sensor's heater resistance. + /// * `calibration_data` - The calibration data of the sensor. + /// * `ambient_temperature` - The ambient temperature. + /// * `heater_temperature` - The heater temperature. + pub fn heater_resistance(calibration_data: &CalibrationData, ambient_temperature: i8, heater_temperature: u16) -> u8 { // cap temperature - let temp = if temperature <= 400 { temperature } else { 400 }; + let temp = if heater_temperature <= 400 { heater_temperature } else { 400 }; let var1 = ambient_temperature as i32 * calibration_data.par_gh3 as i32 / 1000i32 * 256i32; let var2 = (calibration_data.par_gh1 as i32 + 784i32) @@ -20,9 +24,10 @@ impl Calculation { ((heatr_res_x100 + 50i32) / 100i32) as u8 } + /// Calculates and returns the heater duration. + /// * `duration` The duration time pub fn heater_duration(duration: Duration) -> u8 { let mut factor: u8 = 0u8; - // TODO replace once https://github.com/rust-lang/rust/pull/50167 has been merged const MILLIS_PER_SEC: u64 = 1_000; const NANOS_PER_MILLI: u64 = 1_000_000; let mut dur = (duration.as_secs() as u64 * MILLIS_PER_SEC) @@ -41,9 +46,9 @@ impl Calculation { } } - /// - /// * `calib` - Calibration data used during initalization - /// * `temp_adc` + /// Calculates and returns the sensor temperature. + /// * `calibration_data` - Calibration data used during initialization + /// * `temp_adc` - The temperature reading of the analog to digital converter. /// * `temp_offset` - If set, the temperature t_fine will be increased by given /// value in celsius. Temperature offset in Celsius, e.g. 4, -8, 1.25 pub fn temperature( @@ -70,7 +75,11 @@ impl Calculation { (calc_temp, t_fine) } - pub fn pressure(calibration_data: &CalibrationData, t_fine: i32, pres_adc: u32) -> u32 { + /// Calculates and returns the pressure of the sensor. + /// + /// * `t_fine` - The resolution temperature obtained after applying calibration data. + /// * `pressure_adc` - The pressure value as returned by the analog to digital converter. + pub fn pressure(calibration_data: &CalibrationData, t_fine: i32, pressure_adc: u32) -> u32 { let mut var1: i32 = (t_fine >> 1) - 64000; let mut var2: i32 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * calibration_data.par_p6 as i32) >> 2; var2 += (var1 * (calibration_data.par_p5 as i32)) << 1; @@ -80,7 +89,7 @@ impl Calculation { + ((calibration_data.par_p2 as i32 * var1) >> 1i32); var1 >>= 18i32; var1 = ((32768i32 + var1) * calibration_data.par_p1 as i32) >> 15i32; - let mut pressure_comp: i32 = 1048576u32.wrapping_sub(pres_adc) as i32; + let mut pressure_comp: i32 = 1048576u32.wrapping_sub(pressure_adc) as i32; pressure_comp = ((pressure_comp - (var2 >> 12i32)) as u32).wrapping_mul(3125u32) as i32; if pressure_comp >= 0x40000000i32 { pressure_comp = ((pressure_comp as u32).wrapping_div(var1 as u32) << 1i32) as i32; @@ -100,9 +109,13 @@ impl Calculation { pressure_comp as u32 } - pub fn humidity(calibration_data: &CalibrationData, t_fine: i32, hum_adc: u16) -> u32 { + /// Calculates and returns the humidity of the sensor. + /// + /// * `t_fine` - The resolution temperature obtained after applying calibration data. + /// * `humidity_adc` - The humidity value as returned by the analog to digital converter. + pub fn humidity(calibration_data: &CalibrationData, t_fine: i32, humidity_adc: u16) -> u32 { let temp_scaled: i32 = (t_fine * 5i32 + 128i32) >> 8i32; - let var1: i32 = hum_adc as i32 + let var1: i32 = humidity_adc as i32 - calibration_data.par_h1 as i32 * 16i32 - ((temp_scaled * calibration_data.par_h3 as i32 / 100i32) >> 1i32); let var2: i32 = (calibration_data.par_h2 as i32 @@ -124,7 +137,11 @@ impl Calculation { calc_hum as u32 } - pub fn gas_resistance(calibration_data: &CalibrationData, gas_res_adc: u16, gas_range: u8) -> u32 { + /// Calculates and returns the gas resistance. + /// + /// * `gas_resistance_adc` - The gas resistance reading from the analog to digital converter. + /// * `gas_range` - The lookup table gas range. + pub fn gas_resistance(calibration_data: &CalibrationData, gas_resistance_adc: u16, gas_range: u8) -> u32 { let lookup_table1: [u32; 16] = [ 2147483647u32, 2147483647u32, @@ -164,7 +181,7 @@ impl Calculation { let var1: i64 = ((1340 + 5 * calibration_data.range_sw_err as i64) * lookup_table1[gas_range as usize] as i64) >> 16; - let var2: u64 = (((gas_res_adc as i64) << 15) - 16777216 + var1) as u64; + let var2: u64 = (((gas_resistance_adc as i64) << 15) - 16777216 + var1) as u64; let var3: i64 = (lookup_table2[gas_range as usize] as i64 * var1) >> 9; let calc_gas_res: u32 = ((var3 + ((var2 as i64) >> 1i64)) / var2 as i64) as u32; calc_gas_res From 43ca1506154a29b40827b72aa0f630e63608ddd8 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Mon, 26 Feb 2024 22:01:42 +0200 Subject: [PATCH 07/18] refactor: extract i2c utility in its own file --- examples/read_sensor_data.rs | 7 +-- src/i2c.rs | 75 ++++++++++++++++++++++++++++ src/lib.rs | 97 ++++++------------------------------ 3 files changed, 93 insertions(+), 86 deletions(-) create mode 100644 src/i2c.rs diff --git a/examples/read_sensor_data.rs b/examples/read_sensor_data.rs index fd4035c..7202f86 100644 --- a/examples/read_sensor_data.rs +++ b/examples/read_sensor_data.rs @@ -1,11 +1,12 @@ #![no_std] -use bme680::{Bme680, Bme680Error, I2CAddress, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; +use bme680::{Bme680, Bme680Error, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; use core::time::Duration; use embedded_hal::delay::DelayNs; use linux_embedded_hal as hal; -use linux_embedded_hal::{Delay}; +use linux_embedded_hal::Delay; use log::info; +use bme680::i2c::Address; // Please export RUST_LOG=info in order to see logs in the console. @@ -16,7 +17,7 @@ fn main() -> Result<(), Bme680Error> let i2c = hal::I2cdev::new("/dev/i2c-1").unwrap(); let mut delayer = Delay {}; - let mut dev = Bme680::init(i2c, &mut delayer, I2CAddress::Primary)?; + let mut dev = Bme680::init(i2c, &mut delayer, Address::Primary)?; let mut delay = Delay {}; let settings = SettingsBuilder::new() diff --git a/src/i2c.rs b/src/i2c.rs new file mode 100644 index 0000000..9f5f12a --- /dev/null +++ b/src/i2c.rs @@ -0,0 +1,75 @@ +use embedded_hal::i2c::I2c; +use crate::Bme680Error; +use crate::Bme680Error::{I2CRead, I2CWrite}; + +/// +/// Represents the I2C address of the BME680 Sensor. +/// +#[derive(Debug, Clone, Copy)] +pub enum Address { + /// Primary Address 0x76 + Primary, + /// Secondary Address 0x77 + Secondary, + /// Alternative address + Other(u8), +} + +impl Address { + pub fn addr(&self) -> u8 { + match &self { + Address::Primary => 0x76u8, + Address::Secondary => 0x77u8, + Address::Other(addr) => *addr, + } + } +} + +impl Default for Address { + fn default() -> Address { + Address::Primary + } +} + +/// I2CUtility is a simple wrapper over the I2c trait to make reading and writing data easier. +pub(crate) struct I2CUtility {} + +impl I2CUtility { + /// Reads a byte from the I2C bus. + pub fn read_byte( + i2c_handle: &mut I2C, + device_address: u8, + register_address: u8, + ) -> Result + { + let mut buf = [0; 1]; + + i2c_handle.write(device_address, &[register_address]).map_err(|_e| { I2CWrite })?; + + match i2c_handle.read(device_address, &mut buf) { + Ok(()) => Ok(buf[0]), + Err(_e) => Err(I2CRead), + } + } + + /// Reads bytes from the I2C bus. + pub fn read_bytes( + i2c_handle: &mut I2C, + device_address: u8, + register_address: u8, + buffer: &mut [u8], + ) -> Result<(), Bme680Error> + { + i2c_handle.write(device_address, &[register_address]).map_err(|_e| { I2CWrite })?; + + match i2c_handle.read(device_address, buffer) { + Ok(()) => Ok(()), + Err(_e) => Err(I2CRead), + } + } + + /// Writes bytes to the I2C bus. + pub fn write_bytes(i2c_handle: &mut I2C, device_address: u8, buffer: &[u8]) -> Result<(), Bme680Error> { + i2c_handle.write(device_address, &buffer).map_err(|_e| { I2CWrite }) + } +} diff --git a/src/lib.rs b/src/lib.rs index 5d0b8a0..04b02dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,23 +6,23 @@ //! ```no_run -//! use bme680::{Bme680, Bme680Error, I2CAddress, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; -//! use core::result; +//! use bme680::{Bme680, Bme680Error, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; //! use core::time::Duration; //! use embedded_hal::delay::DelayNs; //! use linux_embedded_hal as hal; -//! use linux_embedded_hal::{Delay, I2CError}; +//! use linux_embedded_hal::Delay; //! use log::info; +//! use bme680::i2c::Address; //! //! // Please export RUST_LOG=info in order to see logs in the console. -//! fn main() -> result::Result<(), Bme680Error> +//! fn main() -> Result<(), Bme680Error> //! { //! env_logger::init(); //! //! let i2c = hal::I2cdev::new("/dev/i2c-1").unwrap(); //! let mut delayer = Delay {}; //! -//! let mut dev = Bme680::init(i2c, &mut delayer, I2CAddress::Primary)?; +//! let mut dev = Bme680::init(i2c, &mut delayer, Address::Primary)?; //! let mut delay = Delay {}; //! //! let settings = SettingsBuilder::new() @@ -71,18 +71,20 @@ pub use self::settings::{ mod calculation; mod settings; +pub mod i2c; use crate::calculation::Calculation; use crate::hal::delay::DelayNs; use crate::hal::i2c::I2c; use core::time::Duration; -use core::{marker::PhantomData}; +use core::marker::PhantomData; use embedded_hal as hal; use log::{debug, error, info}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use i2c::{Address, I2CUtility}; use crate::Bme680Error::{I2CRead, I2CWrite}; /// BME680 General config @@ -205,35 +207,6 @@ impl PowerMode { } } -/// -/// I2C Address represents the I2C address of the BME680 Sensor. -/// -#[derive(Debug, Clone, Copy)] -pub enum I2CAddress { - /// Primary Address 0x76 - Primary, - /// Secondary Address 0x77 - Secondary, - /// Alternative address - Other(u8), -} - -impl I2CAddress { - pub fn addr(&self) -> u8 { - match &self { - I2CAddress::Primary => 0x76u8, - I2CAddress::Secondary => 0x77u8, - I2CAddress::Other(addr) => *addr, - } - } -} - -impl Default for I2CAddress { - fn default() -> I2CAddress { - I2CAddress::Primary - } -} - /// Calibration data used during initialization #[derive(Debug, Default, Copy)] #[repr(C)] @@ -342,52 +315,12 @@ pub enum FieldDataCondition { Unchanged, } -/// I2CUtility is a simple wrapper over the I2c trait to make reading and writing data easier. -struct I2CUtility {} - -impl I2CUtility { - pub fn read_byte( - i2c: &mut I2C, - dev_id: u8, - reg_addr: u8, - ) -> Result - where - I2C: I2c - { - let mut buf = [0; 1]; - - i2c.write(dev_id, &[reg_addr]).map_err(|_e| { I2CWrite })?; - - match i2c.read(dev_id, &mut buf) { - Ok(()) => Ok(buf[0]), - Err(_e) => Err(I2CRead), - } - } - - pub fn read_bytes( - i2c: &mut I2C, - dev_id: u8, - reg_addr: u8, - buf: &mut [u8], - ) -> Result<(), Bme680Error> - where - I2C: I2c, - { - i2c.write(dev_id, &[reg_addr]).map_err(|_e| { I2CWrite })?; - - match i2c.read(dev_id, buf) { - Ok(()) => Ok(()), - Err(_e) => Err(I2CRead), - } - } -} - /// Driver for the BME680 environmental sensor #[repr(C)] pub struct Bme680 { i2c_bus_handle: I2C, delay: PhantomData, - device_address: I2CAddress, + device_address: Address, calibration_data: CalibrationData, temperature_offset: f32, power_mode: PowerMode, @@ -423,7 +356,7 @@ fn boundary_check_u8( Ok(value) } -impl Bme680 +impl Bme680 where D: DelayNs, I2C: I2c, @@ -431,12 +364,10 @@ impl Bme680 pub fn soft_reset( i2c: &mut I2C, delay: &mut D, - dev_id: I2CAddress, + dev_id: Address, ) -> Result<(), Bme680Error> { let tmp_buff: [u8; 2] = [BME680_SOFT_RESET_ADDR, BME680_SOFT_RESET_CMD]; - - i2c.write(dev_id.addr(), &tmp_buff).map_err(|_e| { I2CWrite })?; - + I2CUtility::write_bytes(i2c, dev_id.addr(), &tmp_buff)?; delay.delay_ms(BME680_RESET_PERIOD as u32); Ok(()) } @@ -444,7 +375,7 @@ impl Bme680 pub fn init( mut i2c: I2C, delay: &mut D, - dev_id: I2CAddress, + dev_id: Address, ) -> Result, Bme680Error> { Bme680::soft_reset(&mut i2c, delay, dev_id)?; @@ -765,7 +696,7 @@ impl Bme680 fn get_calib_data( i2c: &mut I2CX, - dev_id: I2CAddress, + dev_id: Address, ) -> Result where I2CX: I2c, From b5d2f80e150344a9f21e38251e072df45fb8df7f Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Tue, 27 Feb 2024 20:41:00 +0200 Subject: [PATCH 08/18] refactor: fix settings variable names --- src/lib.rs | 76 +++++++++++++++++------------------ src/settings.rs | 104 ++++++++++++++++++++++++++---------------------- 2 files changed, 95 insertions(+), 85 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 04b02dd..c392778 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,8 +65,8 @@ #![forbid(unsafe_code)] pub use self::settings::{ - DesiredSensorSettings, GasSett, IIRFilterSize, OversamplingSetting, SensorSettings, Settings, - SettingsBuilder, TphSett, + DesiredSensorSettings, GasSettings, IIRFilterSize, OversamplingSetting, SensorSettings, Settings, + SettingsBuilder, TemperatureSettings, }; mod calculation; @@ -433,10 +433,10 @@ impl Bme680 settings: Settings, ) -> Result<(), Bme680Error> { let (sensor_settings, desired_settings) = settings; - let tph_sett = sensor_settings.tph_sett; - let gas_sett = sensor_settings.gas_sett; + let tph_sett = sensor_settings.temperature_settings; + let gas_sett = sensor_settings.gas_settings; - self.temperature_offset = sensor_settings.tph_sett.temperature_offset.unwrap_or(0f32); + self.temperature_offset = sensor_settings.temperature_settings.temperature_offset.unwrap_or(0f32); let mut reg: [(u8, u8); BME680_REG_BUFFER_LENGTH] = [(0, 0); BME680_REG_BUFFER_LENGTH]; let intended_power_mode = self.power_mode; @@ -451,22 +451,22 @@ impl Bme680 let mut element_index = 0; // Selecting the filter - if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) { + if desired_settings.contains(DesiredSensorSettings::FILTER_SIZE_SEL) { let mut data = I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_ODR_FILT_ADDR)?; debug!("FILTER_SEL: true"); data = (data as i32 & !0x1ci32 - | (tph_sett.filter.unwrap_or(IIRFilterSize::Size0) as i32) << 2i32 & 0x1ci32) + | (tph_sett.filter_size.unwrap_or(IIRFilterSize::Size0) as i32) << 2i32 & 0x1ci32) as u8; reg[element_index] = (BME680_CONF_ODR_FILT_ADDR, data); element_index += 1; } - if desired_settings.contains(DesiredSensorSettings::HCNTRL_SEL) { + if desired_settings.contains(DesiredSensorSettings::HUMIDITY_CONTROL_SEL) { debug!("HCNTRL_SEL: true"); let gas_sett_heatr_ctrl = - boundary_check_u8(gas_sett.heatr_ctrl, "GasSett.heatr_ctrl", 0x0u8, 0x8u8)?; + boundary_check_u8(gas_sett.heater_control, "GasSett.heatr_ctrl", 0x0u8, 0x8u8)?; let mut data = I2CUtility::read_byte( &mut self.i2c_bus_handle, self.device_address.addr(), @@ -487,7 +487,7 @@ impl Bme680 if desired_settings.contains(DesiredSensorSettings::OST_SEL) { debug!("OST_SEL: true"); let tph_sett_os_temp = boundary_check_u8( - tph_sett.os_temp.map(|x| x as u8), + tph_sett.temperature_oversampling.map(|x| x as u8), "TphSett.os_temp", 0, 5, @@ -497,7 +497,7 @@ impl Bme680 if desired_settings.contains(DesiredSensorSettings::OSP_SEL) { debug!("OSP_SEL: true"); - let tph_sett_os_pres = tph_sett.os_temp.unwrap_or(OversamplingSetting::OS1x); + let tph_sett_os_pres = tph_sett.temperature_oversampling.unwrap_or(OversamplingSetting::OS1x); data = (data as i32 & !0x1ci32 | (tph_sett_os_pres as i32) << 2i32 & 0x1ci32) as u8; } reg[element_index] = (BME680_CONF_T_P_MODE_ADDR, data); @@ -508,7 +508,7 @@ impl Bme680 if desired_settings.contains(DesiredSensorSettings::OSH_SEL) { debug!("OSH_SEL: true"); let tph_sett_os_hum = - boundary_check_u8(tph_sett.os_hum.map(|x| x as u8), "TphSett.os_hum", 0, 5)?; + boundary_check_u8(tph_sett.humidity_oversampling.map(|x| x as u8), "TphSett.os_hum", 0, 5)?; let mut data = I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_OS_H_ADDR)?; data = (data as i32 & !0x7i32 | tph_sett_os_hum as i32 & 0x7i32) as u8; @@ -529,7 +529,7 @@ impl Bme680 if desired_settings.contains(DesiredSensorSettings::RUN_GAS_SEL) { debug!("RUN_GAS_SEL: true"); data = (data as i32 & !0x10i32 - | (gas_sett.run_gas_measurement as i32) << 4i32 & 0x10i32) + | (gas_sett.enable_gas_measurement as i32) << 4i32 & 0x10i32) as u8; } @@ -567,11 +567,11 @@ impl Bme680 I2CUtility::read_bytes(&mut self.i2c_bus_handle, self.device_address.addr(), reg_addr, &mut data_array)?; if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL) { - sensor_settings.gas_sett = self.get_gas_config()?; + sensor_settings.gas_settings = self.get_gas_config()?; } - if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) { - sensor_settings.tph_sett.filter = Some(IIRFilterSize::from_u8( + if desired_settings.contains(DesiredSensorSettings::FILTER_SIZE_SEL) { + sensor_settings.temperature_settings.filter_size = Some(IIRFilterSize::from_u8( ((data_array[5usize] as i32 & 0x1ci32) >> 2i32) as u8, )); } @@ -581,24 +581,24 @@ impl Bme680 { let os_temp: u8 = ((data_array[4usize] as i32 & 0xe0i32) >> 5i32) as u8; let os_pres: u8 = ((data_array[4usize] as i32 & 0x1ci32) >> 2i32) as u8; - sensor_settings.tph_sett.os_temp = Some(OversamplingSetting::from_u8(os_temp)); - sensor_settings.tph_sett.os_pres = Some(OversamplingSetting::from_u8(os_pres)); + sensor_settings.temperature_settings.temperature_oversampling = Some(OversamplingSetting::from_u8(os_temp)); + sensor_settings.temperature_settings.pressure_oversampling = Some(OversamplingSetting::from_u8(os_pres)); } if desired_settings.contains(DesiredSensorSettings::OSH_SEL) { let os_hum: u8 = (data_array[2usize] as i32 & 0x7i32) as u8; - sensor_settings.tph_sett.os_hum = Some(OversamplingSetting::from_u8(os_hum)); + sensor_settings.temperature_settings.humidity_oversampling = Some(OversamplingSetting::from_u8(os_hum)); } - if desired_settings.contains(DesiredSensorSettings::HCNTRL_SEL) { - sensor_settings.gas_sett.heatr_ctrl = Some((data_array[0usize] as i32 & 0x8i32) as u8); + if desired_settings.contains(DesiredSensorSettings::HUMIDITY_CONTROL_SEL) { + sensor_settings.gas_settings.heater_control = Some((data_array[0usize] as i32 & 0x8i32) as u8); } if desired_settings .contains(DesiredSensorSettings::RUN_GAS_SEL | DesiredSensorSettings::NBCONV_SEL) { - sensor_settings.gas_sett.nb_conv = (data_array[1usize] as i32 & 0xfi32) as u8; - sensor_settings.gas_sett.run_gas_measurement = + sensor_settings.gas_settings.nb_conv = (data_array[1usize] as i32 & 0xfi32) as u8; + sensor_settings.gas_settings.enable_gas_measurement = ((data_array[1usize] as i32 & 0x10i32) >> 4i32) == 0; } @@ -665,20 +665,20 @@ impl Bme680 ) -> Result { let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; let mut meas_cycles = os_to_meas_cycles[sensor_settings - .tph_sett - .os_temp + .temperature_settings + .temperature_oversampling .unwrap_or(OversamplingSetting::OSNone) as usize] as u32; meas_cycles = meas_cycles.wrapping_add( os_to_meas_cycles[sensor_settings - .tph_sett - .os_pres + .temperature_settings + .pressure_oversampling .unwrap_or(OversamplingSetting::OSNone) as usize] as u32, ); meas_cycles = meas_cycles.wrapping_add( os_to_meas_cycles[sensor_settings - .tph_sett - .os_hum + .temperature_settings + .humidity_oversampling .unwrap_or(OversamplingSetting::OSNone) as usize] as u32, ); let mut tph_dur = meas_cycles.wrapping_mul(1963u32); @@ -688,8 +688,8 @@ impl Bme680 tph_dur = tph_dur.wrapping_div(1000u32); tph_dur = tph_dur.wrapping_add(1u32); let mut duration = Duration::from_millis(tph_dur as u64); - if sensor_settings.gas_sett.run_gas_measurement { - duration += sensor_settings.gas_sett.heatr_dur.unwrap_or(Duration::default()); + if sensor_settings.gas_settings.enable_gas_measurement { + duration += sensor_settings.gas_settings.heater_duration.unwrap_or(Duration::default()); } Ok(duration) } @@ -765,7 +765,7 @@ impl Bme680 fn set_gas_config( &mut self, - gas_sett: GasSett, + gas_sett: GasSettings, ) -> Result<(), Bme680Error> { if self.power_mode != PowerMode::ForcedMode { return Err(Bme680Error::DefinePwrMode); @@ -777,19 +777,19 @@ impl Bme680 Calculation::heater_resistance( &self.calibration_data, gas_sett.ambient_temperature, - gas_sett.heatr_temp.unwrap_or(0), + gas_sett.heater_temperature.unwrap_or(0), ), ), ( BME680_GAS_WAIT0_ADDR, - Calculation::heater_duration(gas_sett.heatr_dur.unwrap_or_else(|| Duration::from_secs(0))), + Calculation::heater_duration(gas_sett.heater_duration.unwrap_or_else(|| Duration::from_secs(0))), ), ]; self.bme680_set_regs(®) } - fn get_gas_config(&mut self) -> Result { + fn get_gas_config(&mut self) -> Result { let heatr_temp = Some(I2CUtility::read_byte( &mut self.i2c_bus_handle, self.device_address.addr(), @@ -802,9 +802,9 @@ impl Bme680 BME680_ADDR_GAS_CONF_START, )? as u64; - let gas_sett = GasSett { - heatr_temp, - heatr_dur: Some(Duration::from_millis(heatr_dur_ms)), + let gas_sett = GasSettings { + heater_temperature: heatr_temp, + heater_duration: Some(Duration::from_millis(heatr_dur_ms)), ..Default::default() }; diff --git a/src/settings.rs b/src/settings.rs index f921c6a..d45432e 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -14,16 +14,15 @@ pub enum OversamplingSetting { } impl OversamplingSetting { - // TODO replace with TryFrom once stabilized - pub fn from_u8(os: u8) -> OversamplingSetting { - match os { + pub fn from_u8(value: u8) -> OversamplingSetting { + match value { 0 => OversamplingSetting::OSNone, 1 => OversamplingSetting::OS1x, 2 => OversamplingSetting::OS2x, 3 => OversamplingSetting::OS4x, 4 => OversamplingSetting::OS8x, 5 => OversamplingSetting::OS16x, - _ => panic!("Unknown oversampling setting: {}", os), + _ => panic!("Unknown oversampling setting: {}", value), } } } @@ -43,9 +42,8 @@ pub enum IIRFilterSize { } impl IIRFilterSize { - // TODO replace with TryFrom once stabilized - pub fn from_u8(os: u8) -> IIRFilterSize { - match os { + pub fn from_u8(value: u8) -> IIRFilterSize { + match value { 0 => IIRFilterSize::Size0, 1 => IIRFilterSize::Size1, 2 => IIRFilterSize::Size3, @@ -54,7 +52,7 @@ impl IIRFilterSize { 5 => IIRFilterSize::Size31, 6 => IIRFilterSize::Size63, 7 => IIRFilterSize::Size127, - _ => panic!("Unknown IIRFilterSize: {}", os), + _ => panic!("Unknown IIRFilterSize: {}", value), } } } @@ -62,20 +60,20 @@ impl IIRFilterSize { /// Temperature settings #[derive(Debug, Default, Copy)] #[repr(C)] -pub struct TphSett { +pub struct TemperatureSettings { /// Humidity oversampling - pub os_hum: Option, + pub humidity_oversampling: Option, /// Temperature oversampling - pub os_temp: Option, + pub temperature_oversampling: Option, /// Pressure oversampling - pub os_pres: Option, + pub pressure_oversampling: Option, /// Filter coefficient - pub filter: Option, + pub filter_size: Option, /// If set, the temperature t_fine will be increased by the given value in celsius. pub temperature_offset: Option, } -impl Clone for TphSett { +impl Clone for TemperatureSettings { fn clone(&self) -> Self { *self } @@ -84,20 +82,22 @@ impl Clone for TphSett { /// Gas measurement settings #[derive(Debug, Default, Copy)] #[repr(C)] -pub struct GasSett { +pub struct GasSettings { + /// nb_conv is used to select heater set-points of the sensor. pub nb_conv: u8, /// Heater control - pub heatr_ctrl: Option, + pub heater_control: Option, /// Enable measurement of gas, disabled by default - pub run_gas_measurement: bool, - /// Heater temperature - pub heatr_temp: Option, - /// Profile duration - pub heatr_dur: Option, + pub enable_gas_measurement: bool, + /// The heater temperature + pub heater_temperature: Option, + /// The Heating duration + pub heater_duration: Option, + /// The ambient temperature. pub ambient_temperature: i8, } -impl Clone for GasSett { +impl Clone for GasSettings { fn clone(&self) -> Self { *self } @@ -107,9 +107,9 @@ impl Clone for GasSett { #[derive(Debug, Default, Copy)] pub struct SensorSettings { /// Gas settings - pub gas_sett: GasSett, + pub gas_settings: GasSettings, /// Temperature settings - pub tph_sett: TphSett, + pub temperature_settings: TemperatureSettings, } impl Clone for SensorSettings { @@ -132,9 +132,9 @@ bitflags! { /// To set gas measurement setting. const GAS_MEAS_SEL = 8; /// To set filter setting. - const FILTER_SEL = 16; + const FILTER_SIZE_SEL = 16; /// To set humidity control setting. - const HCNTRL_SEL = 32; + const HUMIDITY_CONTROL_SEL = 32; /// To set run gas setting. const RUN_GAS_SEL = 64; /// To set NB conversion setting. @@ -171,74 +171,84 @@ pub struct SettingsBuilder { pub type Settings = (SensorSettings, DesiredSensorSettings); impl SettingsBuilder { + /// Constructs a new instance of the SettingsBuilder. pub fn new() -> SettingsBuilder { SettingsBuilder::default() } - pub fn with_temperature_filter(mut self, filter: IIRFilterSize) -> SettingsBuilder { - self.sensor_settings.tph_sett.filter = Some(filter); - self.desired_settings |= DesiredSensorSettings::FILTER_SEL; + /// With temperature filter. + pub fn with_temperature_filter(mut self, filter_size: IIRFilterSize) -> SettingsBuilder { + self.sensor_settings.temperature_settings.filter_size = Some(filter_size); + self.desired_settings |= DesiredSensorSettings::FILTER_SIZE_SEL; self } - pub fn with_humidity_control(mut self, heatr_control: u8) -> SettingsBuilder { - self.sensor_settings.gas_sett.heatr_ctrl = Some(heatr_control); - self.desired_settings |= DesiredSensorSettings::HCNTRL_SEL; + /// With gas heater control. + pub fn with_gas_heater_control(mut self, heater_control: u8) -> SettingsBuilder { + self.sensor_settings.gas_settings.heater_control = Some(heater_control); + self.desired_settings |= DesiredSensorSettings::HUMIDITY_CONTROL_SEL; self } + /// With temperature oversampling pub fn with_temperature_oversampling( mut self, - os_temp: OversamplingSetting, + temperature_oversampling: OversamplingSetting, ) -> SettingsBuilder { - self.sensor_settings.tph_sett.os_temp = Some(os_temp); + self.sensor_settings.temperature_settings.temperature_oversampling = Some(temperature_oversampling); self.desired_settings |= DesiredSensorSettings::OST_SEL; self } - pub fn with_pressure_oversampling(mut self, os_pres: OversamplingSetting) -> SettingsBuilder { - self.sensor_settings.tph_sett.os_pres = Some(os_pres); + /// With pressure oversampling. + pub fn with_pressure_oversampling(mut self, pressure_oversampling: OversamplingSetting) -> SettingsBuilder { + self.sensor_settings.temperature_settings.pressure_oversampling = Some(pressure_oversampling); self.desired_settings |= DesiredSensorSettings::OSP_SEL; self } - pub fn with_humidity_oversampling(mut self, os_hum: OversamplingSetting) -> SettingsBuilder { - self.sensor_settings.tph_sett.os_hum = Some(os_hum); + /// With humidity oversampling. + pub fn with_humidity_oversampling(mut self, humidity_oversampling: OversamplingSetting) -> SettingsBuilder { + self.sensor_settings.temperature_settings.humidity_oversampling = Some(humidity_oversampling); self.desired_settings |= DesiredSensorSettings::OSH_SEL; self } + /// With gas measurement. pub fn with_gas_measurement( mut self, - heatr_dur: Duration, - heatr_temp: u16, + heater_duration: Duration, + heater_temperature: u16, ambient_temperature: i8, ) -> SettingsBuilder { - self.sensor_settings.gas_sett.heatr_dur = Some(heatr_dur); - self.sensor_settings.gas_sett.heatr_temp = Some(heatr_temp); - self.sensor_settings.gas_sett.ambient_temperature = ambient_temperature; + self.sensor_settings.gas_settings.heater_duration = Some(heater_duration); + self.sensor_settings.gas_settings.heater_temperature = Some(heater_temperature); + self.sensor_settings.gas_settings.ambient_temperature = ambient_temperature; self.desired_settings |= DesiredSensorSettings::GAS_SENSOR_SEL; self } + /// With nb_conv. pub fn with_nb_conv(mut self, nb_conv: u8) -> SettingsBuilder { - self.sensor_settings.gas_sett.nb_conv = nb_conv; + self.sensor_settings.gas_settings.nb_conv = nb_conv; self.desired_settings |= DesiredSensorSettings::GAS_SENSOR_SEL; self } + /// With run gas. pub fn with_run_gas(mut self, run_gas: bool) -> SettingsBuilder { - self.sensor_settings.gas_sett.run_gas_measurement = run_gas; + self.sensor_settings.gas_settings.enable_gas_measurement = run_gas; self.desired_settings |= DesiredSensorSettings::GAS_SENSOR_SEL; self } - /// Temperature offset in Celsius, e.g. 4, -8, 1.25 + /// With temperature offset in Celsius, e.g. 4, -8, 1.25 pub fn with_temperature_offset(mut self, offset: f32) -> SettingsBuilder { - self.sensor_settings.tph_sett.temperature_offset = Some(offset); + self.sensor_settings.temperature_settings.temperature_offset = Some(offset); self } + /// Builds the settings object pub fn build(self) -> Settings { (self.sensor_settings, self.desired_settings) } From 4dc106450adb6a26b9d8bc6d8ccf0ac26f5180da Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Tue, 27 Feb 2024 20:49:06 +0200 Subject: [PATCH 09/18] todo: use anyhow crate to improve readability and maintenance --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index c392778..7d34463 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,6 +151,9 @@ const BME680_TMP_BUFFER_LENGTH: usize = 40; const BME680_REG_BUFFER_LENGTH: usize = 6; /// All possible errors in this crate +/// TODO: use anyhow: +/// - https://antoinerr.github.io/blog-website/2023/01/28/rust-anyhow.html +/// - https://docs.rs/anyhow/latest/anyhow/ #[derive(Debug)] pub enum Bme680Error { /// From 432d3643c7812b41f4ee2d360636537a5e6100f6 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Tue, 27 Feb 2024 22:05:18 +0200 Subject: [PATCH 10/18] refactor: soft_reset, init and set registers --- src/lib.rs | 56 +++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7d34463..74223ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,6 +202,7 @@ impl PowerMode { } } + /// Retrieves the power mode value. fn value(&self) -> u8 { match self { PowerMode::SleepMode => BME680_SLEEP_MODE, @@ -364,65 +365,68 @@ impl Bme680 D: DelayNs, I2C: I2c, { + /// Sends the soft reset command to the chip. pub fn soft_reset( - i2c: &mut I2C, + i2c_handle: &mut I2C, delay: &mut D, - dev_id: Address, + device_address: Address, ) -> Result<(), Bme680Error> { let tmp_buff: [u8; 2] = [BME680_SOFT_RESET_ADDR, BME680_SOFT_RESET_CMD]; - I2CUtility::write_bytes(i2c, dev_id.addr(), &tmp_buff)?; + I2CUtility::write_bytes(i2c_handle, device_address.addr(), &tmp_buff)?; delay.delay_ms(BME680_RESET_PERIOD as u32); Ok(()) } + /// Initializes the BME680 sensor with an I2C handle. pub fn init( - mut i2c: I2C, + mut i2c_handle: I2C, delay: &mut D, - dev_id: Address, + device_address: Address, ) -> Result, Bme680Error> { - Bme680::soft_reset(&mut i2c, delay, dev_id)?; + Bme680::soft_reset(&mut i2c_handle, delay, device_address)?; debug!("Reading chip id"); /* Soft reset to restore it to default values*/ - let chip_id = I2CUtility::read_byte::(&mut i2c, dev_id.addr(), BME680_CHIP_ID_ADDR)?; + let chip_id = I2CUtility::read_byte::(&mut i2c_handle, device_address.addr(), BME680_CHIP_ID_ADDR)?; debug!("Chip id: {}", chip_id); if chip_id == BME680_CHIP_ID { debug!("Reading calibration data"); - let calibration = Bme680::::get_calib_data::(&mut i2c, dev_id)?; - debug!("Calibration data {:?}", calibration); - let dev = Bme680 { - i2c_bus_handle: i2c, + let calibration_data = Bme680::::get_calib_data::(&mut i2c_handle, device_address)?; + debug!("Calibration data {:?}", calibration_data); + let device = Bme680 { + i2c_bus_handle: i2c_handle, delay: PhantomData, - device_address: dev_id, - calibration_data: calibration, + device_address, + calibration_data, temperature_offset: 0.0, power_mode: PowerMode::ForcedMode, }; info!("Finished device init"); - Ok(dev) + Ok(device) } else { error!("Device does not match chip id {}", BME680_CHIP_ID); Err(Bme680Error::DeviceNotFound) } } - fn bme680_set_regs( + /// Sets the sensor registers. + fn bme680_set_registers( &mut self, - reg: &[(u8, u8)], + registers: &[(u8, u8)], ) -> Result<(), Bme680Error> { - if reg.is_empty() || reg.len() > (BME680_TMP_BUFFER_LENGTH / 2) as usize { + if registers.is_empty() || registers.len() > (BME680_TMP_BUFFER_LENGTH / 2) as usize { return Err(Bme680Error::InvalidLength); } - for (reg_addr, reg_data) in reg { - let tmp_buff: [u8; 2] = [*reg_addr, *reg_data]; + for (register_address, register_data) in registers { + let buffer: [u8; 2] = [*register_address, *register_data]; debug!( - "Setting register reg: {:?} tmp_buf: {:?}", - reg_addr, tmp_buff + "Setting register reg: {:?} buffer: {:?}", + register_address, buffer ); self.i2c_bus_handle - .write(self.device_address.addr(), &tmp_buff) + .write(self.device_address.addr(), &buffer) .map_err(|_e| { I2CWrite })?; } @@ -547,7 +551,7 @@ impl Bme680 element_index += 1; } - self.bme680_set_regs(®[0..element_index])?; + self.bme680_set_registers(®[0..element_index])?; // Restore previous intended power mode self.power_mode = intended_power_mode; @@ -635,7 +639,7 @@ impl Bme680 // Set to sleep tmp_pow_mode &= !BME680_MODE_MSK; debug!("Setting to sleep tmp_pow_mode: {}", tmp_pow_mode); - self.bme680_set_regs(&[(BME680_CONF_T_P_MODE_ADDR, tmp_pow_mode)])?; + self.bme680_set_registers(&[(BME680_CONF_T_P_MODE_ADDR, tmp_pow_mode)])?; delay .delay_ms(BME680_POLL_PERIOD_MS as u32); } else { @@ -647,7 +651,7 @@ impl Bme680 if target_power_mode != PowerMode::SleepMode { tmp_pow_mode = tmp_pow_mode & !BME680_MODE_MSK | target_power_mode.value(); debug!("Already in sleep Target power mode: {}", tmp_pow_mode); - self.bme680_set_regs(&[(BME680_CONF_T_P_MODE_ADDR, tmp_pow_mode)])?; + self.bme680_set_registers(&[(BME680_CONF_T_P_MODE_ADDR, tmp_pow_mode)])?; } Ok(()) } @@ -789,7 +793,7 @@ impl Bme680 ), ]; - self.bme680_set_regs(®) + self.bme680_set_registers(®) } fn get_gas_config(&mut self) -> Result { From cf9b0fbdd0aa9d8e8adf2ab97b97076e1522ba79 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Tue, 27 Feb 2024 22:09:16 +0200 Subject: [PATCH 11/18] refactor: format code --- examples/read_sensor_data.rs | 6 +- src/calculation.rs | 35 ++++++-- src/i2c.rs | 26 ++++-- src/lib.rs | 165 ++++++++++++++++++++++------------- src/settings.rs | 22 +++-- 5 files changed, 165 insertions(+), 89 deletions(-) diff --git a/examples/read_sensor_data.rs b/examples/read_sensor_data.rs index 7202f86..280ce59 100644 --- a/examples/read_sensor_data.rs +++ b/examples/read_sensor_data.rs @@ -1,17 +1,15 @@ #![no_std] +use bme680::i2c::Address; use bme680::{Bme680, Bme680Error, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; use core::time::Duration; use embedded_hal::delay::DelayNs; use linux_embedded_hal as hal; use linux_embedded_hal::Delay; use log::info; -use bme680::i2c::Address; - // Please export RUST_LOG=info in order to see logs in the console. -fn main() -> Result<(), Bme680Error> -{ +fn main() -> Result<(), Bme680Error> { env_logger::init(); let i2c = hal::I2cdev::new("/dev/i2c-1").unwrap(); diff --git a/src/calculation.rs b/src/calculation.rs index 43ee7bf..a9fd829 100644 --- a/src/calculation.rs +++ b/src/calculation.rs @@ -9,14 +9,23 @@ impl Calculation { /// * `calibration_data` - The calibration data of the sensor. /// * `ambient_temperature` - The ambient temperature. /// * `heater_temperature` - The heater temperature. - pub fn heater_resistance(calibration_data: &CalibrationData, ambient_temperature: i8, heater_temperature: u16) -> u8 { + pub fn heater_resistance( + calibration_data: &CalibrationData, + ambient_temperature: i8, + heater_temperature: u16, + ) -> u8 { // cap temperature - let temp = if heater_temperature <= 400 { heater_temperature } else { 400 }; + let temp = if heater_temperature <= 400 { + heater_temperature + } else { + 400 + }; let var1 = ambient_temperature as i32 * calibration_data.par_gh3 as i32 / 1000i32 * 256i32; let var2 = (calibration_data.par_gh1 as i32 + 784i32) - * (((calibration_data.par_gh2 as i32 + 154009i32) * temp as i32 * 5i32 / 100i32 + 3276800i32) - / 10i32); + * (((calibration_data.par_gh2 as i32 + 154009i32) * temp as i32 * 5i32 / 100i32 + + 3276800i32) + / 10i32); let var3 = var1 + var2 / 2i32; let var4 = var3 / (calibration_data.res_heat_range as i32 + 4i32); let var5 = 131i32 * calibration_data.res_heat_val as i32 + 65536i32; @@ -81,10 +90,12 @@ impl Calculation { /// * `pressure_adc` - The pressure value as returned by the analog to digital converter. pub fn pressure(calibration_data: &CalibrationData, t_fine: i32, pressure_adc: u32) -> u32 { let mut var1: i32 = (t_fine >> 1) - 64000; - let mut var2: i32 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * calibration_data.par_p6 as i32) >> 2; + let mut var2: i32 = + ((((var1 >> 2) * (var1 >> 2)) >> 11) * calibration_data.par_p6 as i32) >> 2; var2 += (var1 * (calibration_data.par_p5 as i32)) << 1; var2 = (var2 >> 2i32) + ((calibration_data.par_p4 as i32) << 16i32); - var1 = (((((var1 >> 2i32) * (var1 >> 2i32)) >> 13i32) * ((calibration_data.par_p3 as i32) << 5i32)) + var1 = (((((var1 >> 2i32) * (var1 >> 2i32)) >> 13i32) + * ((calibration_data.par_p3 as i32) << 5i32)) >> 3i32) + ((calibration_data.par_p2 as i32 * var1) >> 1i32); var1 >>= 18i32; @@ -120,8 +131,10 @@ impl Calculation { - ((temp_scaled * calibration_data.par_h3 as i32 / 100i32) >> 1i32); let var2: i32 = (calibration_data.par_h2 as i32 * (temp_scaled * calibration_data.par_h4 as i32 / 100i32 - + ((temp_scaled * (temp_scaled * calibration_data.par_h5 as i32 / 100i32)) >> 6i32) / 100i32 - + (1i32 << 14i32))) + + ((temp_scaled * (temp_scaled * calibration_data.par_h5 as i32 / 100i32)) + >> 6i32) + / 100i32 + + (1i32 << 14i32))) >> 10i32; let var3: i32 = var1 * var2; let var4: i32 = (calibration_data.par_h6 as i32) << 7i32; @@ -141,7 +154,11 @@ impl Calculation { /// /// * `gas_resistance_adc` - The gas resistance reading from the analog to digital converter. /// * `gas_range` - The lookup table gas range. - pub fn gas_resistance(calibration_data: &CalibrationData, gas_resistance_adc: u16, gas_range: u8) -> u32 { + pub fn gas_resistance( + calibration_data: &CalibrationData, + gas_resistance_adc: u16, + gas_range: u8, + ) -> u32 { let lookup_table1: [u32; 16] = [ 2147483647u32, 2147483647u32, diff --git a/src/i2c.rs b/src/i2c.rs index 9f5f12a..e317745 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -1,6 +1,6 @@ -use embedded_hal::i2c::I2c; use crate::Bme680Error; use crate::Bme680Error::{I2CRead, I2CWrite}; +use embedded_hal::i2c::I2c; /// /// Represents the I2C address of the BME680 Sensor. @@ -40,11 +40,12 @@ impl I2CUtility { i2c_handle: &mut I2C, device_address: u8, register_address: u8, - ) -> Result - { + ) -> Result { let mut buf = [0; 1]; - i2c_handle.write(device_address, &[register_address]).map_err(|_e| { I2CWrite })?; + i2c_handle + .write(device_address, &[register_address]) + .map_err(|_e| I2CWrite)?; match i2c_handle.read(device_address, &mut buf) { Ok(()) => Ok(buf[0]), @@ -58,9 +59,10 @@ impl I2CUtility { device_address: u8, register_address: u8, buffer: &mut [u8], - ) -> Result<(), Bme680Error> - { - i2c_handle.write(device_address, &[register_address]).map_err(|_e| { I2CWrite })?; + ) -> Result<(), Bme680Error> { + i2c_handle + .write(device_address, &[register_address]) + .map_err(|_e| I2CWrite)?; match i2c_handle.read(device_address, buffer) { Ok(()) => Ok(()), @@ -69,7 +71,13 @@ impl I2CUtility { } /// Writes bytes to the I2C bus. - pub fn write_bytes(i2c_handle: &mut I2C, device_address: u8, buffer: &[u8]) -> Result<(), Bme680Error> { - i2c_handle.write(device_address, &buffer).map_err(|_e| { I2CWrite }) + pub fn write_bytes( + i2c_handle: &mut I2C, + device_address: u8, + buffer: &[u8], + ) -> Result<(), Bme680Error> { + i2c_handle + .write(device_address, &buffer) + .map_err(|_e| I2CWrite) } } diff --git a/src/lib.rs b/src/lib.rs index 74223ba..8485189 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,6 @@ //! In the examples you can find a demo how to use the library in Linux using the linux-embedded-hal crate (e.g. on a RPI). //! ```no_run - //! use bme680::{Bme680, Bme680Error, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; //! use core::time::Duration; //! use embedded_hal::delay::DelayNs; @@ -65,27 +64,27 @@ #![forbid(unsafe_code)] pub use self::settings::{ - DesiredSensorSettings, GasSettings, IIRFilterSize, OversamplingSetting, SensorSettings, Settings, - SettingsBuilder, TemperatureSettings, + DesiredSensorSettings, GasSettings, IIRFilterSize, OversamplingSetting, SensorSettings, + Settings, SettingsBuilder, TemperatureSettings, }; mod calculation; -mod settings; pub mod i2c; +mod settings; use crate::calculation::Calculation; use crate::hal::delay::DelayNs; use crate::hal::i2c::I2c; -use core::time::Duration; use core::marker::PhantomData; +use core::time::Duration; use embedded_hal as hal; use log::{debug, error, info}; +use crate::Bme680Error::{I2CRead, I2CWrite}; +use i2c::{Address, I2CUtility}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use i2c::{Address, I2CUtility}; -use crate::Bme680Error::{I2CRead, I2CWrite}; /// BME680 General config pub const BME680_POLL_PERIOD_MS: u8 = 10; @@ -342,8 +341,7 @@ fn boundary_check_u8( value_name: &'static str, min: u8, max: u8, -) -> Result> -{ +) -> Result { let value = value.ok_or(Bme680Error::BoundaryCheckFailure(value_name))?; if value < min { @@ -361,9 +359,9 @@ fn boundary_check_u8( } impl Bme680 - where - D: DelayNs, - I2C: I2c, +where + D: DelayNs, + I2C: I2c, { /// Sends the soft reset command to the chip. pub fn soft_reset( @@ -387,12 +385,17 @@ impl Bme680 debug!("Reading chip id"); /* Soft reset to restore it to default values*/ - let chip_id = I2CUtility::read_byte::(&mut i2c_handle, device_address.addr(), BME680_CHIP_ID_ADDR)?; + let chip_id = I2CUtility::read_byte::( + &mut i2c_handle, + device_address.addr(), + BME680_CHIP_ID_ADDR, + )?; debug!("Chip id: {}", chip_id); if chip_id == BME680_CHIP_ID { debug!("Reading calibration data"); - let calibration_data = Bme680::::get_calib_data::(&mut i2c_handle, device_address)?; + let calibration_data = + Bme680::::get_calib_data::(&mut i2c_handle, device_address)?; debug!("Calibration data {:?}", calibration_data); let device = Bme680 { i2c_bus_handle: i2c_handle, @@ -411,10 +414,7 @@ impl Bme680 } /// Sets the sensor registers. - fn bme680_set_registers( - &mut self, - registers: &[(u8, u8)], - ) -> Result<(), Bme680Error> { + fn bme680_set_registers(&mut self, registers: &[(u8, u8)]) -> Result<(), Bme680Error> { if registers.is_empty() || registers.len() > (BME680_TMP_BUFFER_LENGTH / 2) as usize { return Err(Bme680Error::InvalidLength); } @@ -427,7 +427,7 @@ impl Bme680 ); self.i2c_bus_handle .write(self.device_address.addr(), &buffer) - .map_err(|_e| { I2CWrite })?; + .map_err(|_e| I2CWrite)?; } Ok(()) @@ -443,7 +443,10 @@ impl Bme680 let tph_sett = sensor_settings.temperature_settings; let gas_sett = sensor_settings.gas_settings; - self.temperature_offset = sensor_settings.temperature_settings.temperature_offset.unwrap_or(0f32); + self.temperature_offset = sensor_settings + .temperature_settings + .temperature_offset + .unwrap_or(0f32); let mut reg: [(u8, u8); BME680_REG_BUFFER_LENGTH] = [(0, 0); BME680_REG_BUFFER_LENGTH]; let intended_power_mode = self.power_mode; @@ -459,8 +462,11 @@ impl Bme680 let mut element_index = 0; // Selecting the filter if desired_settings.contains(DesiredSensorSettings::FILTER_SIZE_SEL) { - let mut data = - I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_ODR_FILT_ADDR)?; + let mut data = I2CUtility::read_byte( + &mut self.i2c_bus_handle, + self.device_address.addr(), + BME680_CONF_ODR_FILT_ADDR, + )?; debug!("FILTER_SEL: true"); data = (data as i32 & !0x1ci32 @@ -488,8 +494,11 @@ impl Bme680 if desired_settings .contains(DesiredSensorSettings::OST_SEL | DesiredSensorSettings::OSP_SEL) { - let mut data = - I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR)?; + let mut data = I2CUtility::read_byte( + &mut self.i2c_bus_handle, + self.device_address.addr(), + BME680_CONF_T_P_MODE_ADDR, + )?; if desired_settings.contains(DesiredSensorSettings::OST_SEL) { debug!("OST_SEL: true"); @@ -504,7 +513,9 @@ impl Bme680 if desired_settings.contains(DesiredSensorSettings::OSP_SEL) { debug!("OSP_SEL: true"); - let tph_sett_os_pres = tph_sett.temperature_oversampling.unwrap_or(OversamplingSetting::OS1x); + let tph_sett_os_pres = tph_sett + .temperature_oversampling + .unwrap_or(OversamplingSetting::OS1x); data = (data as i32 & !0x1ci32 | (tph_sett_os_pres as i32) << 2i32 & 0x1ci32) as u8; } reg[element_index] = (BME680_CONF_T_P_MODE_ADDR, data); @@ -514,10 +525,17 @@ impl Bme680 // Selecting humidity oversampling for the sensor if desired_settings.contains(DesiredSensorSettings::OSH_SEL) { debug!("OSH_SEL: true"); - let tph_sett_os_hum = - boundary_check_u8(tph_sett.humidity_oversampling.map(|x| x as u8), "TphSett.os_hum", 0, 5)?; - let mut data = - I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_OS_H_ADDR)?; + let tph_sett_os_hum = boundary_check_u8( + tph_sett.humidity_oversampling.map(|x| x as u8), + "TphSett.os_hum", + 0, + 5, + )?; + let mut data = I2CUtility::read_byte( + &mut self.i2c_bus_handle, + self.device_address.addr(), + BME680_CONF_OS_H_ADDR, + )?; data = (data as i32 & !0x7i32 | tph_sett_os_hum as i32 & 0x7i32) as u8; reg[element_index] = (BME680_CONF_OS_H_ADDR, data); element_index += 1; @@ -571,7 +589,12 @@ impl Bme680 let mut data_array: [u8; BME680_REG_BUFFER_LENGTH] = [0; BME680_REG_BUFFER_LENGTH]; let mut sensor_settings: SensorSettings = Default::default(); - I2CUtility::read_bytes(&mut self.i2c_bus_handle, self.device_address.addr(), reg_addr, &mut data_array)?; + I2CUtility::read_bytes( + &mut self.i2c_bus_handle, + self.device_address.addr(), + reg_addr, + &mut data_array, + )?; if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL) { sensor_settings.gas_settings = self.get_gas_config()?; @@ -588,17 +611,22 @@ impl Bme680 { let os_temp: u8 = ((data_array[4usize] as i32 & 0xe0i32) >> 5i32) as u8; let os_pres: u8 = ((data_array[4usize] as i32 & 0x1ci32) >> 2i32) as u8; - sensor_settings.temperature_settings.temperature_oversampling = Some(OversamplingSetting::from_u8(os_temp)); - sensor_settings.temperature_settings.pressure_oversampling = Some(OversamplingSetting::from_u8(os_pres)); + sensor_settings + .temperature_settings + .temperature_oversampling = Some(OversamplingSetting::from_u8(os_temp)); + sensor_settings.temperature_settings.pressure_oversampling = + Some(OversamplingSetting::from_u8(os_pres)); } if desired_settings.contains(DesiredSensorSettings::OSH_SEL) { let os_hum: u8 = (data_array[2usize] as i32 & 0x7i32) as u8; - sensor_settings.temperature_settings.humidity_oversampling = Some(OversamplingSetting::from_u8(os_hum)); + sensor_settings.temperature_settings.humidity_oversampling = + Some(OversamplingSetting::from_u8(os_hum)); } if desired_settings.contains(DesiredSensorSettings::HUMIDITY_CONTROL_SEL) { - sensor_settings.gas_settings.heater_control = Some((data_array[0usize] as i32 & 0x8i32) as u8); + sensor_settings.gas_settings.heater_control = + Some((data_array[0usize] as i32 & 0x8i32) as u8); } if desired_settings @@ -627,8 +655,11 @@ impl Bme680 // Call repeatedly until in sleep loop { - tmp_pow_mode = - I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR)?; + tmp_pow_mode = I2CUtility::read_byte( + &mut self.i2c_bus_handle, + self.device_address.addr(), + BME680_CONF_T_P_MODE_ADDR, + )?; // Put to sleep before changing mode current_power_mode = PowerMode::from(tmp_pow_mode & BME680_MODE_MSK); @@ -640,8 +671,7 @@ impl Bme680 tmp_pow_mode &= !BME680_MODE_MSK; debug!("Setting to sleep tmp_pow_mode: {}", tmp_pow_mode); self.bme680_set_registers(&[(BME680_CONF_T_P_MODE_ADDR, tmp_pow_mode)])?; - delay - .delay_ms(BME680_POLL_PERIOD_MS as u32); + delay.delay_ms(BME680_POLL_PERIOD_MS as u32); } else { break; } @@ -657,11 +687,12 @@ impl Bme680 } /// Retrieve current sensor power mode via registers - pub fn get_sensor_mode( - &mut self, - ) -> Result { - let regs = - I2CUtility::read_byte(&mut self.i2c_bus_handle, self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR)?; + pub fn get_sensor_mode(&mut self) -> Result { + let regs = I2CUtility::read_byte( + &mut self.i2c_bus_handle, + self.device_address.addr(), + BME680_CONF_T_P_MODE_ADDR, + )?; let mode = regs & BME680_MODE_MSK; Ok(PowerMode::from(mode)) } @@ -696,17 +727,17 @@ impl Bme680 tph_dur = tph_dur.wrapping_add(1u32); let mut duration = Duration::from_millis(tph_dur as u64); if sensor_settings.gas_settings.enable_gas_measurement { - duration += sensor_settings.gas_settings.heater_duration.unwrap_or(Duration::default()); + duration += sensor_settings + .gas_settings + .heater_duration + .unwrap_or(Duration::default()); } Ok(duration) } - fn get_calib_data( - i2c: &mut I2CX, - dev_id: Address, - ) -> Result - where - I2CX: I2c, + fn get_calib_data(i2c: &mut I2CX, dev_id: Address) -> Result + where + I2CX: I2c, { let mut calib: CalibrationData = Default::default(); @@ -718,7 +749,8 @@ impl Bme680 dev_id.addr(), BME680_COEFF_ADDR1, &mut coeff_array[0..(BME680_COEFF_ADDR1_LEN - 1)], - ).map_err(|_e| { I2CRead })?; + ) + .map_err(|_e| I2CRead)?; I2CUtility::read_bytes::( i2c, @@ -726,7 +758,8 @@ impl Bme680 BME680_COEFF_ADDR2, &mut coeff_array [BME680_COEFF_ADDR1_LEN..(BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN - 1)], - ).map_err(|_e| { I2CRead })?; + ) + .map_err(|_e| I2CRead)?; calib.par_t1 = ((coeff_array[34usize] as i32) << 8i32 | coeff_array[33usize] as i32) as u16; calib.par_t2 = ((coeff_array[2usize] as i32) << 8i32 | coeff_array[1usize] as i32) as i16; @@ -757,23 +790,24 @@ impl Bme680 calib.res_heat_range = (I2CUtility::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_RANGE_ADDR) - .map_err(|_e| { I2CRead })? & 0x30) / 16; + .map_err(|_e| I2CRead)? + & 0x30) + / 16; calib.res_heat_val = I2CUtility::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_VAL_ADDR) - .map_err(|_e| { I2CRead })? as i8; + .map_err(|_e| I2CRead)? as i8; calib.range_sw_err = (I2CUtility::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RANGE_SW_ERR_ADDR) - .map_err(|_e| { I2CRead })? & BME680_RSERROR_MSK) / 16; + .map_err(|_e| I2CRead)? + & BME680_RSERROR_MSK) + / 16; Ok(calib) } - fn set_gas_config( - &mut self, - gas_sett: GasSettings, - ) -> Result<(), Bme680Error> { + fn set_gas_config(&mut self, gas_sett: GasSettings) -> Result<(), Bme680Error> { if self.power_mode != PowerMode::ForcedMode { return Err(Bme680Error::DefinePwrMode); } @@ -789,7 +823,11 @@ impl Bme680 ), ( BME680_GAS_WAIT0_ADDR, - Calculation::heater_duration(gas_sett.heater_duration.unwrap_or_else(|| Duration::from_secs(0))), + Calculation::heater_duration( + gas_sett + .heater_duration + .unwrap_or_else(|| Duration::from_secs(0)), + ), ), ]; @@ -858,8 +896,11 @@ impl Bme680 data.status |= buff[14] & BME680_HEAT_STAB_MSK; if data.status & BME680_NEW_DATA_MSK != 0 { - let (temp, t_fine) = - Calculation::temperature(&self.calibration_data, adc_temp, Some(self.temperature_offset)); + let (temp, t_fine) = Calculation::temperature( + &self.calibration_data, + adc_temp, + Some(self.temperature_offset), + ); debug!( "adc_temp: {} adc_pres: {} adc_hum: {} adc_gas_res: {}, t_fine: {}", adc_temp, adc_pres, adc_hum, adc_gas_res, t_fine diff --git a/src/settings.rs b/src/settings.rs index d45432e..56cff0d 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -195,21 +195,33 @@ impl SettingsBuilder { mut self, temperature_oversampling: OversamplingSetting, ) -> SettingsBuilder { - self.sensor_settings.temperature_settings.temperature_oversampling = Some(temperature_oversampling); + self.sensor_settings + .temperature_settings + .temperature_oversampling = Some(temperature_oversampling); self.desired_settings |= DesiredSensorSettings::OST_SEL; self } /// With pressure oversampling. - pub fn with_pressure_oversampling(mut self, pressure_oversampling: OversamplingSetting) -> SettingsBuilder { - self.sensor_settings.temperature_settings.pressure_oversampling = Some(pressure_oversampling); + pub fn with_pressure_oversampling( + mut self, + pressure_oversampling: OversamplingSetting, + ) -> SettingsBuilder { + self.sensor_settings + .temperature_settings + .pressure_oversampling = Some(pressure_oversampling); self.desired_settings |= DesiredSensorSettings::OSP_SEL; self } /// With humidity oversampling. - pub fn with_humidity_oversampling(mut self, humidity_oversampling: OversamplingSetting) -> SettingsBuilder { - self.sensor_settings.temperature_settings.humidity_oversampling = Some(humidity_oversampling); + pub fn with_humidity_oversampling( + mut self, + humidity_oversampling: OversamplingSetting, + ) -> SettingsBuilder { + self.sensor_settings + .temperature_settings + .humidity_oversampling = Some(humidity_oversampling); self.desired_settings |= DesiredSensorSettings::OSH_SEL; self } From 35c2adef929c2c1062cf62c1ae3427331f6f997c Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Tue, 27 Feb 2024 22:12:24 +0200 Subject: [PATCH 12/18] refactor: fix clippy hints --- src/calculation.rs | 2 +- src/i2c.rs | 11 +++-------- src/lib.rs | 4 ++-- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/calculation.rs b/src/calculation.rs index a9fd829..cf698e6 100644 --- a/src/calculation.rs +++ b/src/calculation.rs @@ -39,7 +39,7 @@ impl Calculation { let mut factor: u8 = 0u8; const MILLIS_PER_SEC: u64 = 1_000; const NANOS_PER_MILLI: u64 = 1_000_000; - let mut dur = (duration.as_secs() as u64 * MILLIS_PER_SEC) + let mut dur = (duration.as_secs() * MILLIS_PER_SEC) + (duration.subsec_nanos() as u64 / NANOS_PER_MILLI); if dur as i32 >= 0xfc0i32 { 0xffu8 // Max duration diff --git a/src/i2c.rs b/src/i2c.rs index e317745..9c3078c 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -5,9 +5,10 @@ use embedded_hal::i2c::I2c; /// /// Represents the I2C address of the BME680 Sensor. /// -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Default)] pub enum Address { /// Primary Address 0x76 + #[default] Primary, /// Secondary Address 0x77 Secondary, @@ -25,12 +26,6 @@ impl Address { } } -impl Default for Address { - fn default() -> Address { - Address::Primary - } -} - /// I2CUtility is a simple wrapper over the I2c trait to make reading and writing data easier. pub(crate) struct I2CUtility {} @@ -77,7 +72,7 @@ impl I2CUtility { buffer: &[u8], ) -> Result<(), Bme680Error> { i2c_handle - .write(device_address, &buffer) + .write(device_address, buffer) .map_err(|_e| I2CWrite) } } diff --git a/src/lib.rs b/src/lib.rs index 8485189..2f7ee03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -415,7 +415,7 @@ where /// Sets the sensor registers. fn bme680_set_registers(&mut self, registers: &[(u8, u8)]) -> Result<(), Bme680Error> { - if registers.is_empty() || registers.len() > (BME680_TMP_BUFFER_LENGTH / 2) as usize { + if registers.is_empty() || registers.len() > (BME680_TMP_BUFFER_LENGTH / 2) { return Err(Bme680Error::InvalidLength); } @@ -730,7 +730,7 @@ where duration += sensor_settings .gas_settings .heater_duration - .unwrap_or(Duration::default()); + .unwrap_or_default(); } Ok(duration) } From d63fcf08b8bf4a9d5e408bc28524a3781042797f Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Tue, 27 Feb 2024 22:13:14 +0200 Subject: [PATCH 13/18] remove license check from flow --- .github/workflows/ci.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ba373e..f187833 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,16 +48,3 @@ jobs: with: command: clippy args: -- -D warnings - - license-check: - name: Check Licenses and Security Advisories - runs-on: ubuntu-latest - strategy: - matrix: - checks: - - advisories bans licenses sources - steps: - - uses: actions/checkout@v2 - - uses: EmbarkStudios/cargo-deny-action@v1 - with: - command: check ${{ matrix.checks }} From 14c2e61aaec8a2e27169c23635f0a2bc5fcc32e8 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Tue, 27 Feb 2024 22:43:10 +0200 Subject: [PATCH 14/18] refactor: store i2c bus handle as refcell --- src/lib.rs | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2f7ee03..82d2c77 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,7 @@ pub use self::settings::{ DesiredSensorSettings, GasSettings, IIRFilterSize, OversamplingSetting, SensorSettings, Settings, SettingsBuilder, TemperatureSettings, }; +use core::cell::RefCell; mod calculation; pub mod i2c; @@ -77,11 +78,12 @@ use crate::hal::delay::DelayNs; use crate::hal::i2c::I2c; use core::marker::PhantomData; +use core::ops::DerefMut; use core::time::Duration; use embedded_hal as hal; use log::{debug, error, info}; -use crate::Bme680Error::{I2CRead, I2CWrite}; +use crate::Bme680Error::I2CRead; use i2c::{Address, I2CUtility}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -321,7 +323,7 @@ pub enum FieldDataCondition { /// Driver for the BME680 environmental sensor #[repr(C)] pub struct Bme680 { - i2c_bus_handle: I2C, + i2c_bus_handle: RefCell, delay: PhantomData, device_address: Address, calibration_data: CalibrationData, @@ -398,7 +400,7 @@ where Bme680::::get_calib_data::(&mut i2c_handle, device_address)?; debug!("Calibration data {:?}", calibration_data); let device = Bme680 { - i2c_bus_handle: i2c_handle, + i2c_bus_handle: RefCell::new(i2c_handle), delay: PhantomData, device_address, calibration_data, @@ -425,9 +427,12 @@ where "Setting register reg: {:?} buffer: {:?}", register_address, buffer ); - self.i2c_bus_handle - .write(self.device_address.addr(), &buffer) - .map_err(|_e| I2CWrite)?; + + I2CUtility::write_bytes( + self.i2c_bus_handle.borrow_mut().deref_mut(), + self.device_address.addr(), + &buffer, + )?; } Ok(()) @@ -463,7 +468,7 @@ where // Selecting the filter if desired_settings.contains(DesiredSensorSettings::FILTER_SIZE_SEL) { let mut data = I2CUtility::read_byte( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_CONF_ODR_FILT_ADDR, )?; @@ -481,7 +486,7 @@ where let gas_sett_heatr_ctrl = boundary_check_u8(gas_sett.heater_control, "GasSett.heatr_ctrl", 0x0u8, 0x8u8)?; let mut data = I2CUtility::read_byte( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_CONF_HEAT_CTRL_ADDR, )?; @@ -495,7 +500,7 @@ where .contains(DesiredSensorSettings::OST_SEL | DesiredSensorSettings::OSP_SEL) { let mut data = I2CUtility::read_byte( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR, )?; @@ -532,7 +537,7 @@ where 5, )?; let mut data = I2CUtility::read_byte( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_CONF_OS_H_ADDR, )?; @@ -546,7 +551,7 @@ where .contains(DesiredSensorSettings::RUN_GAS_SEL | DesiredSensorSettings::NBCONV_SEL) { let mut data = I2CUtility::read_byte( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_CONF_ODR_RUN_GAS_NBC_ADDR, )?; @@ -590,7 +595,7 @@ where let mut sensor_settings: SensorSettings = Default::default(); I2CUtility::read_bytes( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), reg_addr, &mut data_array, @@ -656,7 +661,7 @@ where // Call repeatedly until in sleep loop { tmp_pow_mode = I2CUtility::read_byte( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR, )?; @@ -689,7 +694,7 @@ where /// Retrieve current sensor power mode via registers pub fn get_sensor_mode(&mut self) -> Result { let regs = I2CUtility::read_byte( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR, )?; @@ -836,13 +841,13 @@ where fn get_gas_config(&mut self) -> Result { let heatr_temp = Some(I2CUtility::read_byte( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_ADDR_SENS_CONF_START, )? as u16); let heatr_dur_ms = I2CUtility::read_byte( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_ADDR_GAS_CONF_START, )? as u64; @@ -869,7 +874,7 @@ where const TRIES: u8 = 10; for _ in 0..TRIES { I2CUtility::read_bytes( - &mut self.i2c_bus_handle, + self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_FIELD0_ADDR, &mut buff, From 80c1ee5289695ac85f67836397a1bb36cebd017d Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Tue, 27 Feb 2024 22:45:18 +0200 Subject: [PATCH 15/18] update read_sensor_data.rs example --- examples/read_sensor_data.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/read_sensor_data.rs b/examples/read_sensor_data.rs index 280ce59..c8b5c3e 100644 --- a/examples/read_sensor_data.rs +++ b/examples/read_sensor_data.rs @@ -23,8 +23,7 @@ fn main() -> Result<(), Bme680Error> { .with_pressure_oversampling(OversamplingSetting::OS4x) .with_temperature_oversampling(OversamplingSetting::OS8x) .with_temperature_filter(IIRFilterSize::Size3) - .with_gas_measurement(Duration::from_millis(1500), 320, 25) - .with_temperature_offset(-2.2) + .with_gas_measurement(Duration::from_millis(1500), 320, 23) .with_run_gas(true) .build(); From dfadb520098d2d86622c09c5b26ea20e41025792 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Sun, 3 Mar 2024 11:37:24 +0200 Subject: [PATCH 16/18] refactor lib.rs variables --- examples/read_sensor_data.rs | 4 +- src/lib.rs | 206 +++++++++++++++++------------------ 2 files changed, 105 insertions(+), 105 deletions(-) diff --git a/examples/read_sensor_data.rs b/examples/read_sensor_data.rs index c8b5c3e..b8302fd 100644 --- a/examples/read_sensor_data.rs +++ b/examples/read_sensor_data.rs @@ -27,7 +27,7 @@ fn main() -> Result<(), Bme680Error> { .with_run_gas(true) .build(); - let profile_dur = dev.get_profile_dur(&settings.0)?; + let profile_dur = dev.get_profile_duration(&settings.0)?; info!("Profile duration {:?}", profile_dur); info!("Setting sensor settings"); dev.set_sensor_settings(&mut delayer, settings)?; @@ -44,7 +44,7 @@ fn main() -> Result<(), Bme680Error> { info!("Setting forced power modes"); dev.set_sensor_mode(&mut delayer, PowerMode::ForcedMode)?; info!("Retrieving sensor data"); - let (data, _state) = dev.get_sensor_data(&mut delayer)?; + let (data, _state) = dev.get_measurement(&mut delayer)?; info!("Sensor Data {:?}", data); info!("Temperature {}°C", data.temperature_celsius()); info!("Pressure {}hPa", data.pressure_hpa()); diff --git a/src/lib.rs b/src/lib.rs index 82d2c77..3d05532 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ //! .with_run_gas(true) //! .build(); //! -//! let profile_dur = dev.get_profile_dur(&settings.0)?; +//! let profile_dur = dev.get_profile_duration(&settings.0)?; //! info!("Profile duration {:?}", profile_dur); //! info!("Setting sensor settings"); //! dev.set_sensor_settings(&mut delayer, settings)?; @@ -51,7 +51,7 @@ //! info!("Setting forced power modes"); //! dev.set_sensor_mode(&mut delayer, PowerMode::ForcedMode)?; //! info!("Retrieving sensor data"); -//! let (data, _state) = dev.get_sensor_data(&mut delayer)?; +//! let (data, _state) = dev.get_measurement(&mut delayer)?; //! info!("Sensor Data {:?}", data); //! info!("Temperature {}°C", data.temperature_celsius()); //! info!("Pressure {}hPa", data.pressure_hpa()); @@ -397,7 +397,7 @@ where if chip_id == BME680_CHIP_ID { debug!("Reading calibration data"); let calibration_data = - Bme680::::get_calib_data::(&mut i2c_handle, device_address)?; + Bme680::::get_calibration_data::(&mut i2c_handle, device_address)?; debug!("Calibration data {:?}", calibration_data); let device = Bme680 { i2c_bus_handle: RefCell::new(i2c_handle), @@ -458,7 +458,7 @@ where if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL) { debug!("GAS_MEAS_SEL: true"); - self.set_gas_config(gas_sett)?; + self.set_gas_settings(gas_sett)?; } let power_mode = self.power_mode; @@ -602,7 +602,7 @@ where )?; if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL) { - sensor_settings.gas_settings = self.get_gas_config()?; + sensor_settings.gas_settings = self.get_gas_settings()?; } if desired_settings.contains(DesiredSensorSettings::FILTER_SIZE_SEL) { @@ -655,27 +655,27 @@ where delay: &mut D, target_power_mode: PowerMode, ) -> Result<(), Bme680Error> { - let mut tmp_pow_mode: u8; - let mut current_power_mode: PowerMode; + let mut power_mode_byte: u8; + let mut power_mode: PowerMode; // Call repeatedly until in sleep loop { - tmp_pow_mode = I2CUtility::read_byte( + power_mode_byte = I2CUtility::read_byte( self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR, )?; // Put to sleep before changing mode - current_power_mode = PowerMode::from(tmp_pow_mode & BME680_MODE_MSK); + power_mode = PowerMode::from(power_mode_byte & BME680_MODE_MSK); - debug!("Current power mode: {:?}", current_power_mode); + debug!("Current power mode: {:?}", power_mode); - if current_power_mode != PowerMode::SleepMode { + if power_mode != PowerMode::SleepMode { // Set to sleep - tmp_pow_mode &= !BME680_MODE_MSK; - debug!("Setting to sleep tmp_pow_mode: {}", tmp_pow_mode); - self.bme680_set_registers(&[(BME680_CONF_T_P_MODE_ADDR, tmp_pow_mode)])?; + power_mode_byte &= !BME680_MODE_MSK; + debug!("Setting to sleep tmp_pow_mode: {}", power_mode_byte); + self.bme680_set_registers(&[(BME680_CONF_T_P_MODE_ADDR, power_mode_byte)])?; delay.delay_ms(BME680_POLL_PERIOD_MS as u32); } else { break; @@ -684,53 +684,53 @@ where // Already in sleep if target_power_mode != PowerMode::SleepMode { - tmp_pow_mode = tmp_pow_mode & !BME680_MODE_MSK | target_power_mode.value(); - debug!("Already in sleep Target power mode: {}", tmp_pow_mode); - self.bme680_set_registers(&[(BME680_CONF_T_P_MODE_ADDR, tmp_pow_mode)])?; + power_mode_byte = power_mode_byte & !BME680_MODE_MSK | target_power_mode.value(); + debug!("Already in sleep Target power mode: {}", power_mode_byte); + self.bme680_set_registers(&[(BME680_CONF_T_P_MODE_ADDR, power_mode_byte)])?; } Ok(()) } /// Retrieve current sensor power mode via registers pub fn get_sensor_mode(&mut self) -> Result { - let regs = I2CUtility::read_byte( + let registers = I2CUtility::read_byte( self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_CONF_T_P_MODE_ADDR, )?; - let mode = regs & BME680_MODE_MSK; + let mode = registers & BME680_MODE_MSK; Ok(PowerMode::from(mode)) } - pub fn get_profile_dur( + pub fn get_profile_duration( &self, sensor_settings: &SensorSettings, ) -> Result { let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; - let mut meas_cycles = os_to_meas_cycles[sensor_settings + let mut measurement_cycles = os_to_meas_cycles[sensor_settings .temperature_settings .temperature_oversampling .unwrap_or(OversamplingSetting::OSNone) as usize] as u32; - meas_cycles = meas_cycles.wrapping_add( + measurement_cycles = measurement_cycles.wrapping_add( os_to_meas_cycles[sensor_settings .temperature_settings .pressure_oversampling .unwrap_or(OversamplingSetting::OSNone) as usize] as u32, ); - meas_cycles = meas_cycles.wrapping_add( + measurement_cycles = measurement_cycles.wrapping_add( os_to_meas_cycles[sensor_settings .temperature_settings .humidity_oversampling .unwrap_or(OversamplingSetting::OSNone) as usize] as u32, ); - let mut tph_dur = meas_cycles.wrapping_mul(1963u32); - tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(4u32)); - tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(5u32)); - tph_dur = tph_dur.wrapping_add(500u32); - tph_dur = tph_dur.wrapping_div(1000u32); - tph_dur = tph_dur.wrapping_add(1u32); - let mut duration = Duration::from_millis(tph_dur as u64); + let mut temperature_duration = measurement_cycles.wrapping_mul(1963u32); + temperature_duration = temperature_duration.wrapping_add(477u32.wrapping_mul(4u32)); + temperature_duration = temperature_duration.wrapping_add(477u32.wrapping_mul(5u32)); + temperature_duration = temperature_duration.wrapping_add(500u32); + temperature_duration = temperature_duration.wrapping_div(1000u32); + temperature_duration = temperature_duration.wrapping_add(1u32); + let mut duration = Duration::from_millis(temperature_duration as u64); if sensor_settings.gas_settings.enable_gas_measurement { duration += sensor_settings .gas_settings @@ -740,79 +740,79 @@ where Ok(duration) } - fn get_calib_data(i2c: &mut I2CX, dev_id: Address) -> Result + fn get_calibration_data(i2c: &mut I2CX, device_address: Address) -> Result where I2CX: I2c, { - let mut calib: CalibrationData = Default::default(); + let mut calibration_data: CalibrationData = Default::default(); - let mut coeff_array: [u8; BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN] = + let mut coefficients_array: [u8; BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN] = [0; BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN]; I2CUtility::read_bytes::( i2c, - dev_id.addr(), + device_address.addr(), BME680_COEFF_ADDR1, - &mut coeff_array[0..(BME680_COEFF_ADDR1_LEN - 1)], + &mut coefficients_array[0..(BME680_COEFF_ADDR1_LEN - 1)], ) .map_err(|_e| I2CRead)?; I2CUtility::read_bytes::( i2c, - dev_id.addr(), + device_address.addr(), BME680_COEFF_ADDR2, - &mut coeff_array + &mut coefficients_array [BME680_COEFF_ADDR1_LEN..(BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN - 1)], ) .map_err(|_e| I2CRead)?; - calib.par_t1 = ((coeff_array[34usize] as i32) << 8i32 | coeff_array[33usize] as i32) as u16; - calib.par_t2 = ((coeff_array[2usize] as i32) << 8i32 | coeff_array[1usize] as i32) as i16; - calib.par_t3 = coeff_array[3usize] as i8; - calib.par_p1 = ((coeff_array[6usize] as i32) << 8i32 | coeff_array[5usize] as i32) as u16; - calib.par_p2 = ((coeff_array[8usize] as i32) << 8i32 | coeff_array[7usize] as i32) as i16; - calib.par_p3 = coeff_array[9usize] as i8; - calib.par_p4 = ((coeff_array[12usize] as i32) << 8i32 | coeff_array[11usize] as i32) as i16; - calib.par_p5 = ((coeff_array[14usize] as i32) << 8i32 | coeff_array[13usize] as i32) as i16; - calib.par_p6 = coeff_array[16usize] as i8; - calib.par_p7 = coeff_array[15usize] as i8; - calib.par_p8 = ((coeff_array[20usize] as i32) << 8i32 | coeff_array[19usize] as i32) as i16; - calib.par_p9 = ((coeff_array[22usize] as i32) << 8i32 | coeff_array[21usize] as i32) as i16; - calib.par_p10 = coeff_array[23usize]; - calib.par_h1 = - ((coeff_array[27usize] as i32) << 4i32 | coeff_array[26usize] as i32 & 0xfi32) as u16; - calib.par_h2 = - ((coeff_array[25usize] as i32) << 4i32 | coeff_array[26usize] as i32 >> 4i32) as u16; - calib.par_h3 = coeff_array[28usize] as i8; - calib.par_h4 = coeff_array[29usize] as i8; - calib.par_h5 = coeff_array[30usize] as i8; - calib.par_h6 = coeff_array[31usize]; - calib.par_h7 = coeff_array[32usize] as i8; - calib.par_gh1 = coeff_array[37usize] as i8; - calib.par_gh2 = - ((coeff_array[36usize] as i32) << 8i32 | coeff_array[35usize] as i32) as i16; - calib.par_gh3 = coeff_array[38usize] as i8; + calibration_data.par_t1 = ((coefficients_array[34usize] as i32) << 8i32 | coefficients_array[33usize] as i32) as u16; + calibration_data.par_t2 = ((coefficients_array[2usize] as i32) << 8i32 | coefficients_array[1usize] as i32) as i16; + calibration_data.par_t3 = coefficients_array[3usize] as i8; + calibration_data.par_p1 = ((coefficients_array[6usize] as i32) << 8i32 | coefficients_array[5usize] as i32) as u16; + calibration_data.par_p2 = ((coefficients_array[8usize] as i32) << 8i32 | coefficients_array[7usize] as i32) as i16; + calibration_data.par_p3 = coefficients_array[9usize] as i8; + calibration_data.par_p4 = ((coefficients_array[12usize] as i32) << 8i32 | coefficients_array[11usize] as i32) as i16; + calibration_data.par_p5 = ((coefficients_array[14usize] as i32) << 8i32 | coefficients_array[13usize] as i32) as i16; + calibration_data.par_p6 = coefficients_array[16usize] as i8; + calibration_data.par_p7 = coefficients_array[15usize] as i8; + calibration_data.par_p8 = ((coefficients_array[20usize] as i32) << 8i32 | coefficients_array[19usize] as i32) as i16; + calibration_data.par_p9 = ((coefficients_array[22usize] as i32) << 8i32 | coefficients_array[21usize] as i32) as i16; + calibration_data.par_p10 = coefficients_array[23usize]; + calibration_data.par_h1 = + ((coefficients_array[27usize] as i32) << 4i32 | coefficients_array[26usize] as i32 & 0xfi32) as u16; + calibration_data.par_h2 = + ((coefficients_array[25usize] as i32) << 4i32 | coefficients_array[26usize] as i32 >> 4i32) as u16; + calibration_data.par_h3 = coefficients_array[28usize] as i8; + calibration_data.par_h4 = coefficients_array[29usize] as i8; + calibration_data.par_h5 = coefficients_array[30usize] as i8; + calibration_data.par_h6 = coefficients_array[31usize]; + calibration_data.par_h7 = coefficients_array[32usize] as i8; + calibration_data.par_gh1 = coefficients_array[37usize] as i8; + calibration_data.par_gh2 = + ((coefficients_array[36usize] as i32) << 8i32 | coefficients_array[35usize] as i32) as i16; + calibration_data.par_gh3 = coefficients_array[38usize] as i8; - calib.res_heat_range = - (I2CUtility::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_RANGE_ADDR) + calibration_data.res_heat_range = + (I2CUtility::read_byte::(i2c, device_address.addr(), BME680_ADDR_RES_HEAT_RANGE_ADDR) .map_err(|_e| I2CRead)? & 0x30) / 16; - calib.res_heat_val = - I2CUtility::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_VAL_ADDR) + calibration_data.res_heat_val = + I2CUtility::read_byte::(i2c, device_address.addr(), BME680_ADDR_RES_HEAT_VAL_ADDR) .map_err(|_e| I2CRead)? as i8; - calib.range_sw_err = - (I2CUtility::read_byte::(i2c, dev_id.addr(), BME680_ADDR_RANGE_SW_ERR_ADDR) + calibration_data.range_sw_err = + (I2CUtility::read_byte::(i2c, device_address.addr(), BME680_ADDR_RANGE_SW_ERR_ADDR) .map_err(|_e| I2CRead)? & BME680_RSERROR_MSK) / 16; - Ok(calib) + Ok(calibration_data) } - fn set_gas_config(&mut self, gas_sett: GasSettings) -> Result<(), Bme680Error> { + fn set_gas_settings(&mut self, gas_settings: GasSettings) -> Result<(), Bme680Error> { if self.power_mode != PowerMode::ForcedMode { return Err(Bme680Error::DefinePwrMode); } @@ -822,14 +822,14 @@ where BME680_RES_HEAT0_ADDR, Calculation::heater_resistance( &self.calibration_data, - gas_sett.ambient_temperature, - gas_sett.heater_temperature.unwrap_or(0), + gas_settings.ambient_temperature, + gas_settings.heater_temperature.unwrap_or(0), ), ), ( BME680_GAS_WAIT0_ADDR, Calculation::heater_duration( - gas_sett + gas_settings .heater_duration .unwrap_or_else(|| Duration::from_secs(0)), ), @@ -839,8 +839,8 @@ where self.bme680_set_registers(®) } - fn get_gas_config(&mut self) -> Result { - let heatr_temp = Some(I2CUtility::read_byte( + fn get_gas_settings(&mut self) -> Result { + let heater_temperature = Some(I2CUtility::read_byte( self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_ADDR_SENS_CONF_START, @@ -853,7 +853,7 @@ where )? as u64; let gas_sett = GasSettings { - heater_temperature: heatr_temp, + heater_temperature, heater_duration: Some(Duration::from_millis(heatr_dur_ms)), ..Default::default() }; @@ -861,14 +861,14 @@ where Ok(gas_sett) } - /// Retrieve the current sensor information - pub fn get_sensor_data( + /// Retrieve the current sensor measurement. + pub fn get_measurement( &mut self, delay: &mut D, ) -> Result<(FieldData, FieldDataCondition), Bme680Error> { - let mut buff: [u8; BME680_FIELD_LENGTH] = [0; BME680_FIELD_LENGTH]; + let mut buffer: [u8; BME680_FIELD_LENGTH] = [0; BME680_FIELD_LENGTH]; - debug!("Buf {:?}, len: {}", buff, buff.len()); + debug!("Buf {:?}, len: {}", buffer, buffer.len()); let mut data: FieldData = Default::default(); const TRIES: u8 = 10; @@ -877,44 +877,44 @@ where self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_FIELD0_ADDR, - &mut buff, + &mut buffer, )?; - debug!("Field data read {:?}, len: {}", buff, buff.len()); + debug!("Field data read {:?}, len: {}", buffer, buffer.len()); - data.status = buff[0] & BME680_NEW_DATA_MSK; - data.gas_index = buff[0] & BME680_GAS_INDEX_MSK; - data.measurement_index = buff[1]; + data.status = buffer[0] & BME680_NEW_DATA_MSK; + data.gas_index = buffer[0] & BME680_GAS_INDEX_MSK; + data.measurement_index = buffer[1]; - let adc_pres = (buff[2] as u32).wrapping_mul(4096) - | (buff[3] as u32).wrapping_mul(16) - | (buff[4] as u32).wrapping_div(16); - let adc_temp = (buff[5] as u32).wrapping_mul(4096) - | (buff[6] as u32).wrapping_mul(16) - | (buff[7] as u32).wrapping_div(16); - let adc_hum = ((buff[8] as u32).wrapping_mul(256) | buff[9] as u32) as u16; - let adc_gas_res = - ((buff[13] as u32).wrapping_mul(4) | (buff[14] as u32).wrapping_div(64)) as u16; - let gas_range = buff[14] & BME680_GAS_RANGE_MSK; + let adc_pressure = (buffer[2] as u32).wrapping_mul(4096) + | (buffer[3] as u32).wrapping_mul(16) + | (buffer[4] as u32).wrapping_div(16); + let adc_temperature = (buffer[5] as u32).wrapping_mul(4096) + | (buffer[6] as u32).wrapping_mul(16) + | (buffer[7] as u32).wrapping_div(16); + let adc_humidity = ((buffer[8] as u32).wrapping_mul(256) | buffer[9] as u32) as u16; + let adc_gas_resistance = + ((buffer[13] as u32).wrapping_mul(4) | (buffer[14] as u32).wrapping_div(64)) as u16; + let gas_range = buffer[14] & BME680_GAS_RANGE_MSK; - data.status |= buff[14] & BME680_GASM_VALID_MSK; - data.status |= buff[14] & BME680_HEAT_STAB_MSK; + data.status |= buffer[14] & BME680_GASM_VALID_MSK; + data.status |= buffer[14] & BME680_HEAT_STAB_MSK; if data.status & BME680_NEW_DATA_MSK != 0 { let (temp, t_fine) = Calculation::temperature( &self.calibration_data, - adc_temp, + adc_temperature, Some(self.temperature_offset), ); debug!( "adc_temp: {} adc_pres: {} adc_hum: {} adc_gas_res: {}, t_fine: {}", - adc_temp, adc_pres, adc_hum, adc_gas_res, t_fine + adc_temperature, adc_pressure, adc_humidity, adc_gas_resistance, t_fine ); data.temperature = temp; - data.pressure = Calculation::pressure(&self.calibration_data, t_fine, adc_pres); - data.humidity = Calculation::humidity(&self.calibration_data, t_fine, adc_hum); + data.pressure = Calculation::pressure(&self.calibration_data, t_fine, adc_pressure); + data.humidity = Calculation::humidity(&self.calibration_data, t_fine, adc_humidity); data.gas_resistance = - Calculation::gas_resistance(&self.calibration_data, adc_gas_res, gas_range); + Calculation::gas_resistance(&self.calibration_data, adc_gas_resistance, gas_range); return Ok((data, FieldDataCondition::NewData)); } From fe38f02a9c92ca184a605f37e33b2536355ea2f9 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Sun, 3 Mar 2024 19:02:33 +0200 Subject: [PATCH 17/18] use anyhow crate for error handling --- Cargo.toml | 1 + examples/read_sensor_data.rs | 4 +- src/i2c.rs | 26 +++++---- src/lib.rs | 102 ++++++++++++----------------------- 4 files changed, 53 insertions(+), 80 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b90f9e2..6c3c4cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ embedded-hal = "=1.0.0" log = "0.4" serde = { version = "1.0", optional = true, default-features = false, features = ["derive"] } linux-embedded-hal = "0.4.0" +anyhow = "1.0.80" [dev-dependencies] env_logger = "0.9" \ No newline at end of file diff --git a/examples/read_sensor_data.rs b/examples/read_sensor_data.rs index b8302fd..dfa9243 100644 --- a/examples/read_sensor_data.rs +++ b/examples/read_sensor_data.rs @@ -1,7 +1,7 @@ #![no_std] use bme680::i2c::Address; -use bme680::{Bme680, Bme680Error, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; +use bme680::{Bme680, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; use core::time::Duration; use embedded_hal::delay::DelayNs; use linux_embedded_hal as hal; @@ -9,7 +9,7 @@ use linux_embedded_hal::Delay; use log::info; // Please export RUST_LOG=info in order to see logs in the console. -fn main() -> Result<(), Bme680Error> { +fn main() -> Result<(), anyhow::Error> { env_logger::init(); let i2c = hal::I2cdev::new("/dev/i2c-1").unwrap(); diff --git a/src/i2c.rs b/src/i2c.rs index 9c3078c..4dd9276 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -1,5 +1,5 @@ -use crate::Bme680Error; -use crate::Bme680Error::{I2CRead, I2CWrite}; +use core::fmt::{Display, Formatter}; +use anyhow::anyhow; use embedded_hal::i2c::I2c; /// @@ -26,6 +26,12 @@ impl Address { } } +impl Display for Address { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + write!(f, "Address={:#01x}", self.addr()) + } +} + /// I2CUtility is a simple wrapper over the I2c trait to make reading and writing data easier. pub(crate) struct I2CUtility {} @@ -35,16 +41,16 @@ impl I2CUtility { i2c_handle: &mut I2C, device_address: u8, register_address: u8, - ) -> Result { + ) -> Result { let mut buf = [0; 1]; i2c_handle .write(device_address, &[register_address]) - .map_err(|_e| I2CWrite)?; + .map_err(|e| anyhow!("Failed to write a byte {} to device {}: {:?}", register_address, device_address, e))?; match i2c_handle.read(device_address, &mut buf) { Ok(()) => Ok(buf[0]), - Err(_e) => Err(I2CRead), + Err(_e) => Err(anyhow!("Failed to read byte {} from device {}", register_address, device_address)), } } @@ -54,14 +60,14 @@ impl I2CUtility { device_address: u8, register_address: u8, buffer: &mut [u8], - ) -> Result<(), Bme680Error> { + ) -> Result<(), anyhow::Error> { i2c_handle .write(device_address, &[register_address]) - .map_err(|_e| I2CWrite)?; + .map_err(|_e| anyhow!("Failed to write a byte {} from device {}", register_address, device_address))?; match i2c_handle.read(device_address, buffer) { Ok(()) => Ok(()), - Err(_e) => Err(I2CRead), + Err(_e) => Err(anyhow!("Failed to read bytes from register {} and device {}", register_address, device_address)), } } @@ -70,9 +76,9 @@ impl I2CUtility { i2c_handle: &mut I2C, device_address: u8, buffer: &[u8], - ) -> Result<(), Bme680Error> { + ) -> Result<(), anyhow::Error> { i2c_handle .write(device_address, buffer) - .map_err(|_e| I2CWrite) + .map_err(|_e| anyhow!("Failed to write bytes to address {}", device_address)) } } diff --git a/src/lib.rs b/src/lib.rs index 3d05532..e356ca1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ //! In the examples you can find a demo how to use the library in Linux using the linux-embedded-hal crate (e.g. on a RPI). //! ```no_run -//! use bme680::{Bme680, Bme680Error, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; +//! use bme680::{Bme680, IIRFilterSize, OversamplingSetting, PowerMode, SettingsBuilder}; //! use core::time::Duration; //! use embedded_hal::delay::DelayNs; //! use linux_embedded_hal as hal; @@ -14,7 +14,7 @@ //! use bme680::i2c::Address; //! //! // Please export RUST_LOG=info in order to see logs in the console. -//! fn main() -> Result<(), Bme680Error> +//! fn main() -> Result<(), anyhow::Error> //! { //! env_logger::init(); //! @@ -80,10 +80,10 @@ use crate::hal::i2c::I2c; use core::marker::PhantomData; use core::ops::DerefMut; use core::time::Duration; +use anyhow::anyhow; use embedded_hal as hal; use log::{debug, error, info}; -use crate::Bme680Error::I2CRead; use i2c::{Address, I2CUtility}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -151,40 +151,6 @@ const BME680_HEAT_STAB_MSK: u8 = 0x10; const BME680_TMP_BUFFER_LENGTH: usize = 40; const BME680_REG_BUFFER_LENGTH: usize = 6; -/// All possible errors in this crate -/// TODO: use anyhow: -/// - https://antoinerr.github.io/blog-website/2023/01/28/rust-anyhow.html -/// - https://docs.rs/anyhow/latest/anyhow/ -#[derive(Debug)] -pub enum Bme680Error { - /// - /// aka BME680_E_COM_FAIL - /// - I2CWrite, - I2CRead, - Delay, - /// - /// aka BME680_E_DEV_NOT_FOUND - /// - DeviceNotFound, - /// - /// aka BME680_E_INVALID_LENGTH - /// - InvalidLength, - /// - /// Warning aka BME680_W_DEFINE_PWR_MODE - /// - DefinePwrMode, - /// - /// Warning aka BME680_W_DEFINE_PWR_MODE - /// - NoNewData, - /// - /// Warning Boundary Check - /// - BoundaryCheckFailure(&'static str), -} - /// /// Power mode settings of the sensor. /// @@ -343,34 +309,34 @@ fn boundary_check_u8( value_name: &'static str, min: u8, max: u8, -) -> Result { - let value = value.ok_or(Bme680Error::BoundaryCheckFailure(value_name))?; +) -> Result { + let value = value.ok_or(anyhow!("Boundary check failed for {}", value_name))?; if value < min { const MIN: &str = "Boundary check failure, value exceeds maximum"; error!("{}, value name: {}", MIN, value_name); - return Err(Bme680Error::BoundaryCheckFailure(MIN)); + return Err(anyhow!("Failed MIN={} boundary check for {}", MIN, value_name)); } if value > max { const MAX: &str = "Boundary check, value exceeds minimum"; error!("{}, value name: {}", MAX, value_name); - return Err(Bme680Error::BoundaryCheckFailure(MAX)); + return Err(anyhow!("Failed MAX={} boundary check for {}", MAX, value_name)); } Ok(value) } impl Bme680 -where - D: DelayNs, - I2C: I2c, + where + D: DelayNs, + I2C: I2c, { /// Sends the soft reset command to the chip. pub fn soft_reset( i2c_handle: &mut I2C, delay: &mut D, device_address: Address, - ) -> Result<(), Bme680Error> { + ) -> Result<(), anyhow::Error> { let tmp_buff: [u8; 2] = [BME680_SOFT_RESET_ADDR, BME680_SOFT_RESET_CMD]; I2CUtility::write_bytes(i2c_handle, device_address.addr(), &tmp_buff)?; delay.delay_ms(BME680_RESET_PERIOD as u32); @@ -382,7 +348,7 @@ where mut i2c_handle: I2C, delay: &mut D, device_address: Address, - ) -> Result, Bme680Error> { + ) -> Result, anyhow::Error> { Bme680::soft_reset(&mut i2c_handle, delay, device_address)?; debug!("Reading chip id"); @@ -411,14 +377,14 @@ where Ok(device) } else { error!("Device does not match chip id {}", BME680_CHIP_ID); - Err(Bme680Error::DeviceNotFound) + Err(anyhow!("Device address not found")) } } /// Sets the sensor registers. - fn bme680_set_registers(&mut self, registers: &[(u8, u8)]) -> Result<(), Bme680Error> { + fn bme680_set_registers(&mut self, registers: &[(u8, u8)]) -> Result<(), anyhow::Error> { if registers.is_empty() || registers.len() > (BME680_TMP_BUFFER_LENGTH / 2) { - return Err(Bme680Error::InvalidLength); + return Err(anyhow!("Invalid register length!")); } for (register_address, register_data) in registers { @@ -443,7 +409,7 @@ where &mut self, delay: &mut D, settings: Settings, - ) -> Result<(), Bme680Error> { + ) -> Result<(), anyhow::Error> { let (sensor_settings, desired_settings) = settings; let tph_sett = sensor_settings.temperature_settings; let gas_sett = sensor_settings.gas_settings; @@ -589,7 +555,7 @@ where pub fn get_sensor_settings( &mut self, desired_settings: DesiredSensorSettings, - ) -> Result { + ) -> Result { let reg_addr: u8 = 0x70u8; let mut data_array: [u8; BME680_REG_BUFFER_LENGTH] = [0; BME680_REG_BUFFER_LENGTH]; let mut sensor_settings: SensorSettings = Default::default(); @@ -654,7 +620,7 @@ where &mut self, delay: &mut D, target_power_mode: PowerMode, - ) -> Result<(), Bme680Error> { + ) -> Result<(), anyhow::Error> { let mut power_mode_byte: u8; let mut power_mode: PowerMode; @@ -692,7 +658,7 @@ where } /// Retrieve current sensor power mode via registers - pub fn get_sensor_mode(&mut self) -> Result { + pub fn get_sensor_mode(&mut self) -> Result { let registers = I2CUtility::read_byte( self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), @@ -705,7 +671,7 @@ where pub fn get_profile_duration( &self, sensor_settings: &SensorSettings, - ) -> Result { + ) -> Result { let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; let mut measurement_cycles = os_to_meas_cycles[sensor_settings .temperature_settings @@ -740,9 +706,9 @@ where Ok(duration) } - fn get_calibration_data(i2c: &mut I2CX, device_address: Address) -> Result - where - I2CX: I2c, + fn get_calibration_data(i2c: &mut I2CX, device_address: Address) -> Result + where + I2CX: I2c, { let mut calibration_data: CalibrationData = Default::default(); @@ -755,7 +721,7 @@ where BME680_COEFF_ADDR1, &mut coefficients_array[0..(BME680_COEFF_ADDR1_LEN - 1)], ) - .map_err(|_e| I2CRead)?; + .map_err(|_e| anyhow!("Failed to get calibration data from device: {}", device_address))?; I2CUtility::read_bytes::( i2c, @@ -764,7 +730,7 @@ where &mut coefficients_array [BME680_COEFF_ADDR1_LEN..(BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN - 1)], ) - .map_err(|_e| I2CRead)?; + .map_err(|_e| anyhow!("Failed to get calibration data from device: {}", device_address))?; calibration_data.par_t1 = ((coefficients_array[34usize] as i32) << 8i32 | coefficients_array[33usize] as i32) as u16; calibration_data.par_t2 = ((coefficients_array[2usize] as i32) << 8i32 | coefficients_array[1usize] as i32) as i16; @@ -795,26 +761,26 @@ where calibration_data.res_heat_range = (I2CUtility::read_byte::(i2c, device_address.addr(), BME680_ADDR_RES_HEAT_RANGE_ADDR) - .map_err(|_e| I2CRead)? + .map_err(|_e| anyhow!("Failed to read from register BME680_ADDR_RES_HEAT_RANGE_ADDR"))? & 0x30) / 16; calibration_data.res_heat_val = I2CUtility::read_byte::(i2c, device_address.addr(), BME680_ADDR_RES_HEAT_VAL_ADDR) - .map_err(|_e| I2CRead)? as i8; + .map_err(|_e| anyhow!("Failed to read from register BME680_ADDR_RES_HEAT_VAL_ADDR"))? as i8; calibration_data.range_sw_err = (I2CUtility::read_byte::(i2c, device_address.addr(), BME680_ADDR_RANGE_SW_ERR_ADDR) - .map_err(|_e| I2CRead)? + .map_err(|_e| anyhow!("Failed to read from register BME680_ADDR_RANGE_SW_ERR_ADDR"))? & BME680_RSERROR_MSK) / 16; Ok(calibration_data) } - fn set_gas_settings(&mut self, gas_settings: GasSettings) -> Result<(), Bme680Error> { + fn set_gas_settings(&mut self, gas_settings: GasSettings) -> Result<(), anyhow::Error> { if self.power_mode != PowerMode::ForcedMode { - return Err(Bme680Error::DefinePwrMode); + return Err(anyhow!("Current power mode is not forced")); } let reg: [(u8, u8); 2] = [ @@ -839,14 +805,14 @@ where self.bme680_set_registers(®) } - fn get_gas_settings(&mut self) -> Result { + fn get_gas_settings(&mut self) -> Result { let heater_temperature = Some(I2CUtility::read_byte( self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_ADDR_SENS_CONF_START, )? as u16); - let heatr_dur_ms = I2CUtility::read_byte( + let heater_duration_ms = I2CUtility::read_byte( self.i2c_bus_handle.borrow_mut().deref_mut(), self.device_address.addr(), BME680_ADDR_GAS_CONF_START, @@ -854,7 +820,7 @@ where let gas_sett = GasSettings { heater_temperature, - heater_duration: Some(Duration::from_millis(heatr_dur_ms)), + heater_duration: Some(Duration::from_millis(heater_duration_ms)), ..Default::default() }; @@ -865,7 +831,7 @@ where pub fn get_measurement( &mut self, delay: &mut D, - ) -> Result<(FieldData, FieldDataCondition), Bme680Error> { + ) -> Result<(FieldData, FieldDataCondition), anyhow::Error> { let mut buffer: [u8; BME680_FIELD_LENGTH] = [0; BME680_FIELD_LENGTH]; debug!("Buf {:?}, len: {}", buffer, buffer.len()); From f77e251bfbcd36eceeaea2f48d9fd0c2465017c9 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Sun, 3 Mar 2024 19:05:01 +0200 Subject: [PATCH 18/18] fix code formatting --- src/i2c.rs | 31 +++++++++++--- src/lib.rs | 122 +++++++++++++++++++++++++++++++++++------------------ 2 files changed, 108 insertions(+), 45 deletions(-) diff --git a/src/i2c.rs b/src/i2c.rs index 4dd9276..a610b0a 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -1,5 +1,5 @@ -use core::fmt::{Display, Formatter}; use anyhow::anyhow; +use core::fmt::{Display, Formatter}; use embedded_hal::i2c::I2c; /// @@ -46,11 +46,22 @@ impl I2CUtility { i2c_handle .write(device_address, &[register_address]) - .map_err(|e| anyhow!("Failed to write a byte {} to device {}: {:?}", register_address, device_address, e))?; + .map_err(|e| { + anyhow!( + "Failed to write a byte {} to device {}: {:?}", + register_address, + device_address, + e + ) + })?; match i2c_handle.read(device_address, &mut buf) { Ok(()) => Ok(buf[0]), - Err(_e) => Err(anyhow!("Failed to read byte {} from device {}", register_address, device_address)), + Err(_e) => Err(anyhow!( + "Failed to read byte {} from device {}", + register_address, + device_address + )), } } @@ -63,11 +74,21 @@ impl I2CUtility { ) -> Result<(), anyhow::Error> { i2c_handle .write(device_address, &[register_address]) - .map_err(|_e| anyhow!("Failed to write a byte {} from device {}", register_address, device_address))?; + .map_err(|_e| { + anyhow!( + "Failed to write a byte {} from device {}", + register_address, + device_address + ) + })?; match i2c_handle.read(device_address, buffer) { Ok(()) => Ok(()), - Err(_e) => Err(anyhow!("Failed to read bytes from register {} and device {}", register_address, device_address)), + Err(_e) => Err(anyhow!( + "Failed to read bytes from register {} and device {}", + register_address, + device_address + )), } } diff --git a/src/lib.rs b/src/lib.rs index e356ca1..dd65499 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,10 +77,10 @@ use crate::calculation::Calculation; use crate::hal::delay::DelayNs; use crate::hal::i2c::I2c; +use anyhow::anyhow; use core::marker::PhantomData; use core::ops::DerefMut; use core::time::Duration; -use anyhow::anyhow; use embedded_hal as hal; use log::{debug, error, info}; @@ -315,21 +315,29 @@ fn boundary_check_u8( if value < min { const MIN: &str = "Boundary check failure, value exceeds maximum"; error!("{}, value name: {}", MIN, value_name); - return Err(anyhow!("Failed MIN={} boundary check for {}", MIN, value_name)); + return Err(anyhow!( + "Failed MIN={} boundary check for {}", + MIN, + value_name + )); } if value > max { const MAX: &str = "Boundary check, value exceeds minimum"; error!("{}, value name: {}", MAX, value_name); - return Err(anyhow!("Failed MAX={} boundary check for {}", MAX, value_name)); + return Err(anyhow!( + "Failed MAX={} boundary check for {}", + MAX, + value_name + )); } Ok(value) } impl Bme680 - where - D: DelayNs, - I2C: I2c, +where + D: DelayNs, + I2C: I2c, { /// Sends the soft reset command to the chip. pub fn soft_reset( @@ -706,9 +714,12 @@ impl Bme680 Ok(duration) } - fn get_calibration_data(i2c: &mut I2CX, device_address: Address) -> Result - where - I2CX: I2c, + fn get_calibration_data( + i2c: &mut I2CX, + device_address: Address, + ) -> Result + where + I2CX: I2c, { let mut calibration_data: CalibrationData = Default::default(); @@ -721,7 +732,12 @@ impl Bme680 BME680_COEFF_ADDR1, &mut coefficients_array[0..(BME680_COEFF_ADDR1_LEN - 1)], ) - .map_err(|_e| anyhow!("Failed to get calibration data from device: {}", device_address))?; + .map_err(|_e| { + anyhow!( + "Failed to get calibration data from device: {}", + device_address + ) + })?; I2CUtility::read_bytes::( i2c, @@ -730,50 +746,73 @@ impl Bme680 &mut coefficients_array [BME680_COEFF_ADDR1_LEN..(BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN - 1)], ) - .map_err(|_e| anyhow!("Failed to get calibration data from device: {}", device_address))?; + .map_err(|_e| { + anyhow!( + "Failed to get calibration data from device: {}", + device_address + ) + })?; - calibration_data.par_t1 = ((coefficients_array[34usize] as i32) << 8i32 | coefficients_array[33usize] as i32) as u16; - calibration_data.par_t2 = ((coefficients_array[2usize] as i32) << 8i32 | coefficients_array[1usize] as i32) as i16; + calibration_data.par_t1 = ((coefficients_array[34usize] as i32) << 8i32 + | coefficients_array[33usize] as i32) as u16; + calibration_data.par_t2 = ((coefficients_array[2usize] as i32) << 8i32 + | coefficients_array[1usize] as i32) as i16; calibration_data.par_t3 = coefficients_array[3usize] as i8; - calibration_data.par_p1 = ((coefficients_array[6usize] as i32) << 8i32 | coefficients_array[5usize] as i32) as u16; - calibration_data.par_p2 = ((coefficients_array[8usize] as i32) << 8i32 | coefficients_array[7usize] as i32) as i16; + calibration_data.par_p1 = ((coefficients_array[6usize] as i32) << 8i32 + | coefficients_array[5usize] as i32) as u16; + calibration_data.par_p2 = ((coefficients_array[8usize] as i32) << 8i32 + | coefficients_array[7usize] as i32) as i16; calibration_data.par_p3 = coefficients_array[9usize] as i8; - calibration_data.par_p4 = ((coefficients_array[12usize] as i32) << 8i32 | coefficients_array[11usize] as i32) as i16; - calibration_data.par_p5 = ((coefficients_array[14usize] as i32) << 8i32 | coefficients_array[13usize] as i32) as i16; + calibration_data.par_p4 = ((coefficients_array[12usize] as i32) << 8i32 + | coefficients_array[11usize] as i32) as i16; + calibration_data.par_p5 = ((coefficients_array[14usize] as i32) << 8i32 + | coefficients_array[13usize] as i32) as i16; calibration_data.par_p6 = coefficients_array[16usize] as i8; calibration_data.par_p7 = coefficients_array[15usize] as i8; - calibration_data.par_p8 = ((coefficients_array[20usize] as i32) << 8i32 | coefficients_array[19usize] as i32) as i16; - calibration_data.par_p9 = ((coefficients_array[22usize] as i32) << 8i32 | coefficients_array[21usize] as i32) as i16; + calibration_data.par_p8 = ((coefficients_array[20usize] as i32) << 8i32 + | coefficients_array[19usize] as i32) as i16; + calibration_data.par_p9 = ((coefficients_array[22usize] as i32) << 8i32 + | coefficients_array[21usize] as i32) as i16; calibration_data.par_p10 = coefficients_array[23usize]; - calibration_data.par_h1 = - ((coefficients_array[27usize] as i32) << 4i32 | coefficients_array[26usize] as i32 & 0xfi32) as u16; - calibration_data.par_h2 = - ((coefficients_array[25usize] as i32) << 4i32 | coefficients_array[26usize] as i32 >> 4i32) as u16; + calibration_data.par_h1 = ((coefficients_array[27usize] as i32) << 4i32 + | coefficients_array[26usize] as i32 & 0xfi32) as u16; + calibration_data.par_h2 = ((coefficients_array[25usize] as i32) << 4i32 + | coefficients_array[26usize] as i32 >> 4i32) as u16; calibration_data.par_h3 = coefficients_array[28usize] as i8; calibration_data.par_h4 = coefficients_array[29usize] as i8; calibration_data.par_h5 = coefficients_array[30usize] as i8; calibration_data.par_h6 = coefficients_array[31usize]; calibration_data.par_h7 = coefficients_array[32usize] as i8; calibration_data.par_gh1 = coefficients_array[37usize] as i8; - calibration_data.par_gh2 = - ((coefficients_array[36usize] as i32) << 8i32 | coefficients_array[35usize] as i32) as i16; + calibration_data.par_gh2 = ((coefficients_array[36usize] as i32) << 8i32 + | coefficients_array[35usize] as i32) as i16; calibration_data.par_gh3 = coefficients_array[38usize] as i8; - calibration_data.res_heat_range = - (I2CUtility::read_byte::(i2c, device_address.addr(), BME680_ADDR_RES_HEAT_RANGE_ADDR) - .map_err(|_e| anyhow!("Failed to read from register BME680_ADDR_RES_HEAT_RANGE_ADDR"))? - & 0x30) - / 16; + calibration_data.res_heat_range = (I2CUtility::read_byte::( + i2c, + device_address.addr(), + BME680_ADDR_RES_HEAT_RANGE_ADDR, + ) + .map_err(|_e| anyhow!("Failed to read from register BME680_ADDR_RES_HEAT_RANGE_ADDR"))? + & 0x30) + / 16; - calibration_data.res_heat_val = - I2CUtility::read_byte::(i2c, device_address.addr(), BME680_ADDR_RES_HEAT_VAL_ADDR) - .map_err(|_e| anyhow!("Failed to read from register BME680_ADDR_RES_HEAT_VAL_ADDR"))? as i8; + calibration_data.res_heat_val = I2CUtility::read_byte::( + i2c, + device_address.addr(), + BME680_ADDR_RES_HEAT_VAL_ADDR, + ) + .map_err(|_e| anyhow!("Failed to read from register BME680_ADDR_RES_HEAT_VAL_ADDR"))? + as i8; - calibration_data.range_sw_err = - (I2CUtility::read_byte::(i2c, device_address.addr(), BME680_ADDR_RANGE_SW_ERR_ADDR) - .map_err(|_e| anyhow!("Failed to read from register BME680_ADDR_RANGE_SW_ERR_ADDR"))? - & BME680_RSERROR_MSK) - / 16; + calibration_data.range_sw_err = (I2CUtility::read_byte::( + i2c, + device_address.addr(), + BME680_ADDR_RANGE_SW_ERR_ADDR, + ) + .map_err(|_e| anyhow!("Failed to read from register BME680_ADDR_RANGE_SW_ERR_ADDR"))? + & BME680_RSERROR_MSK) + / 16; Ok(calibration_data) } @@ -879,8 +918,11 @@ impl Bme680 data.temperature = temp; data.pressure = Calculation::pressure(&self.calibration_data, t_fine, adc_pressure); data.humidity = Calculation::humidity(&self.calibration_data, t_fine, adc_humidity); - data.gas_resistance = - Calculation::gas_resistance(&self.calibration_data, adc_gas_resistance, gas_range); + data.gas_resistance = Calculation::gas_resistance( + &self.calibration_data, + adc_gas_resistance, + gas_range, + ); return Ok((data, FieldDataCondition::NewData)); }