Return I2C error

This commit is contained in:
marcelbuesing 2018-05-18 17:37:11 +02:00 committed by marcelbuesing
parent 287e673761
commit a5f8310bf6
No known key found for this signature in database
GPG key ID: EF3934305E975944
2 changed files with 48 additions and 41 deletions

View file

@ -4,11 +4,12 @@ extern crate bme680_rs;
use bme680_rs::*; use bme680_rs::*;
use hal::*; use hal::*;
use embedded_hal::blocking::i2c as i2c;
use std::thread; use std::thread;
use std::result; use std::result;
use std::time::Duration; use std::time::Duration;
fn main() -> result::Result<(), Bme680Error>{ fn main() -> result::Result<(), Bme680Error<<hal::I2cdev as i2c::Read>::Error , <hal::I2cdev as i2c::Write>::Error>>{
let i2c = I2cdev::new("/dev/i2c-1").unwrap(); let i2c = I2cdev::new("/dev/i2c-1").unwrap();

View file

@ -131,7 +131,7 @@ pub const BME680_NBCONV_SEL: u16 = 128;
pub const BME680_GAS_SENSOR_SEL: u16 = BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL; pub const BME680_GAS_SENSOR_SEL: u16 = BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL;
#[derive(Debug)] #[derive(Debug)]
pub enum Bme680Error { pub enum Bme680Error<R, W> {
/// ///
/// aka BME680_E_NULL_PTR /// aka BME680_E_NULL_PTR
/// ///
@ -139,7 +139,8 @@ pub enum Bme680Error {
/// ///
/// aka BME680_E_COM_FAIL /// aka BME680_E_COM_FAIL
/// ///
CommunicationFailure, I2CWrite(W),
I2CRead(R),
/// ///
/// aka BME680_E_DEV_NOT_FOUND /// aka BME680_E_DEV_NOT_FOUND
/// ///
@ -162,7 +163,14 @@ pub enum Bme680Error {
BoundaryCheckFailure(InfoMsg, u8, u8), BoundaryCheckFailure(InfoMsg, u8, u8),
} }
pub type Result<T> = result::Result<T, Bme680Error>; //impl<I2C> From<<I2C as Read>::Error> for Bme680Error<<I2C as Read>::Error, <I2C as Write>::Error>
// where I2C: Read + Write {
// fn from(e: <I2C as Read>::Error) {
// Bme680Error::I2CRead(e)
// }
//}
pub type Result<T, R, W> = result::Result<T, Bme680Error<R, W>>;
/// ///
/// Power mode settings /// Power mode settings
@ -330,21 +338,21 @@ pub struct I2CUtil {}
impl I2CUtil impl I2CUtil
{ {
pub fn get_regs_u8<I2C>(i2c: &mut I2C, reg_addr: u8) -> Result<u8> pub fn get_regs_u8<I2C>(i2c: &mut I2C, reg_addr: u8) -> Result<u8, <I2C as Read>::Error, <I2C as Write>::Error>
where I2C: Read { where I2C: Read + Write {
let mut buf = [0; 1]; let mut buf = [0; 1];
match i2c.read(reg_addr, &mut buf) { match i2c.read(reg_addr, &mut buf) {
Ok(()) => Ok(buf[0]), Ok(()) => Ok(buf[0]),
Err(_) => Err(Bme680Error::CommunicationFailure), Err(e) => Err(Bme680Error::I2CRead(e)),
} }
} }
pub fn get_regs_i8<I2C>(i2c: &mut I2C, reg_addr: u8) -> Result<i8> pub fn get_regs_i8<I2C>(i2c: &mut I2C, reg_addr: u8) -> Result<i8, <I2C as Read>::Error, <I2C as Write>::Error>
where I2C: Read { where I2C: Read + Write {
let mut buf = [0; 1]; let mut buf = [0; 1];
match i2c.read(reg_addr, &mut buf) { match i2c.read(reg_addr, &mut buf) {
Ok(()) => Ok(buf[0] as i8), Ok(()) => Ok(buf[0] as i8),
Err(_) => Err(Bme680Error::CommunicationFailure), Err(e) => Err(Bme680Error::I2CRead(e)),
} }
} }
} }
@ -354,7 +362,6 @@ pub struct Bme680_dev<I2C, D> {
i2c: I2C, i2c: I2C,
delay: D, delay: D,
dev_id: u8, dev_id: u8,
// pub mem_page: u8,
amb_temp: i8, amb_temp: i8,
calib: CalibData, calib: CalibData,
// TODO remove ? as it may not reflect the state of the device // TODO remove ? as it may not reflect the state of the device
@ -363,11 +370,10 @@ pub struct Bme680_dev<I2C, D> {
gas_sett: GasSett, gas_sett: GasSett,
// TODO remove ? as it may not reflect the state of the device // TODO remove ? as it may not reflect the state of the device
power_mode: PowerMode, power_mode: PowerMode,
// pub new_fields: u8,
// pub info_msg: u8,
} }
fn boundary_check(value: Option<u8>, min: u8, max: u8) -> Result<u8> { fn boundary_check<I2C>(value: Option<u8>, min: u8, max: u8) -> Result<u8, <I2C as Read>::Error, <I2C as Write>::Error>
where I2C: Read + Write {
let mut info_msg: InfoMsg = Default::default(); let mut info_msg: InfoMsg = Default::default();
// TODO give the nullptr here a different name // TODO give the nullptr here a different name
@ -392,26 +398,26 @@ where
D: DelayMs<u8>, D: DelayMs<u8>,
I2C: Read + Write, I2C: Read + Write,
{ {
pub fn soft_reset(i2c: &mut I2C, delay: &mut D, dev_id: u8) -> Result<()> { pub fn soft_reset(i2c: &mut I2C, delay: &mut D, dev_id: u8) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error> {
// TODO do we we really need TMP_BUFFER_LENGTH ? // TODO do we we really need TMP_BUFFER_LENGTH ?
let mut tmp_buff = Vec::with_capacity(BME680_TMP_BUFFER_LENGTH); let mut tmp_buff = Vec::with_capacity(BME680_TMP_BUFFER_LENGTH);
tmp_buff.push(BME680_SOFT_RESET_ADDR); tmp_buff.push(BME680_SOFT_RESET_ADDR);
tmp_buff.push(BME680_SOFT_RESET_CMD); tmp_buff.push(BME680_SOFT_RESET_CMD);
i2c.write(dev_id, tmp_buff.as_slice()) i2c.write(dev_id, tmp_buff.as_slice())
.map_err(|_| Bme680Error::CommunicationFailure)?; .map_err(|e| Bme680Error::I2CWrite(e))?;
delay.delay_ms(BME680_RESET_PERIOD); delay.delay_ms(BME680_RESET_PERIOD);
Ok(()) Ok(())
} }
pub fn init(mut i2c: I2C, mut delay: D, dev_id: u8, ambient_temperature: i8) -> Result<Bme680_dev<I2C, D>> { pub fn init(mut i2c: I2C, mut delay: D, dev_id: u8, ambient_temperature: i8) -> Result<Bme680_dev<I2C, D>, <I2C as Read>::Error, <I2C as Write>::Error> {
Bme680_dev::soft_reset(&mut i2c, &mut delay, dev_id)?; Bme680_dev::soft_reset(&mut i2c, &mut delay, dev_id)?;
let mut buf = [0; 1]; let mut buf = [0; 1];
/* Soft reset to restore it to default values*/ /* Soft reset to restore it to default values*/
let chip_id = i2c.read(BME680_CHIP_ID_ADDR, &mut buf) let chip_id = i2c.read(BME680_CHIP_ID_ADDR, &mut buf)
.map_err(|_| Bme680Error::CommunicationFailure) .map_err(|e| Bme680Error::I2CRead(e))
.map(move |_| buf[0])?; .map(move |_| buf[0])?;
//let chip_id = dev.get_regs_u8(BME680_CHIP_ID_ADDR)?; //let chip_id = dev.get_regs_u8(BME680_CHIP_ID_ADDR)?;
@ -433,7 +439,7 @@ where
} }
} }
pub fn bme680_set_regs(&mut self, reg: &[(u8, u8)]) -> Result<()> { pub fn bme680_set_regs(&mut self, reg: &[(u8, u8)]) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error> {
if reg.is_empty() || reg.len() > (BME680_TMP_BUFFER_LENGTH / 2) as usize { if reg.is_empty() || reg.len() > (BME680_TMP_BUFFER_LENGTH / 2) as usize {
return Err(Bme680Error::InvalidLength); return Err(Bme680Error::InvalidLength);
} }
@ -447,7 +453,7 @@ where
self.i2c self.i2c
.write(self.dev_id, tmp_buff.as_slice()) .write(self.dev_id, tmp_buff.as_slice())
.map_err(|_| Bme680Error::CommunicationFailure) .map_err(|e| Bme680Error::I2CWrite(e))
} }
// TODO replace parameter desired_settings with safe flags // TODO replace parameter desired_settings with safe flags
@ -456,7 +462,7 @@ where
&mut self, &mut self,
desired_settings: DesiredSensorSettings, desired_settings: DesiredSensorSettings,
sensor_settings: &SensorSettings, sensor_settings: &SensorSettings,
) -> Result<()> { ) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error> {
let tph_sett = sensor_settings.tph_sett; let tph_sett = sensor_settings.tph_sett;
let gas_sett = sensor_settings.gas_sett; let gas_sett = sensor_settings.gas_sett;
@ -474,7 +480,7 @@ where
/* Selecting the filter */ /* Selecting the filter */
if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) { if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) {
let tph_sett_filter = boundary_check(tph_sett.filter, 0, 7)?; let tph_sett_filter = boundary_check::<I2C>(tph_sett.filter, 0, 7)?;
reg_addr = 0x75u8; reg_addr = 0x75u8;
let mut data = I2CUtil::get_regs_u8(&mut self.i2c, reg_addr)?; let mut data = I2CUtil::get_regs_u8(&mut self.i2c, reg_addr)?;
@ -487,7 +493,7 @@ where
} }
if desired_settings.contains(DesiredSensorSettings::HCNTRL_SEL) { if desired_settings.contains(DesiredSensorSettings::HCNTRL_SEL) {
let gas_sett_heatr_ctrl = boundary_check(gas_sett.heatr_ctrl, 0x0u8, 0x8u8)?; let gas_sett_heatr_ctrl = boundary_check::<I2C>(gas_sett.heatr_ctrl, 0x0u8, 0x8u8)?;
reg_addr = 0x70u8; reg_addr = 0x70u8;
let mut data = I2CUtil::get_regs_u8(&mut self.i2c, reg_addr)?; let mut data = I2CUtil::get_regs_u8(&mut self.i2c, reg_addr)?;
data = (data as (i32) & !0x8i32 | gas_sett_heatr_ctrl as (i32) & 0x8) as (u8) ; data = (data as (i32) & !0x8i32 | gas_sett_heatr_ctrl as (i32) & 0x8) as (u8) ;
@ -502,7 +508,7 @@ where
let mut data = I2CUtil::get_regs_u8(&mut self.i2c, reg_addr)?; let mut data = I2CUtil::get_regs_u8(&mut self.i2c, reg_addr)?;
if desired_settings.contains(DesiredSensorSettings::OST_SEL) { if desired_settings.contains(DesiredSensorSettings::OST_SEL) {
let tph_sett_os_temp = boundary_check(tph_sett.os_temp, 0, 5)?; let tph_sett_os_temp = boundary_check::<I2C>(tph_sett.os_temp, 0, 5)?;
data = (data as (i32) & !0xe0i32 | tph_sett_os_temp as (i32) << 5i32 & 0xe0i32) data = (data as (i32) & !0xe0i32 | tph_sett_os_temp as (i32) << 5i32 & 0xe0i32)
as (u8); as (u8);
} }
@ -518,7 +524,7 @@ where
/* Selecting humidity oversampling for the sensor */ /* Selecting humidity oversampling for the sensor */
if desired_settings.contains(DesiredSensorSettings::OSH_SEL) { if desired_settings.contains(DesiredSensorSettings::OSH_SEL) {
let tph_sett_os_hum = boundary_check(self.tph_sett.os_hum, 0, 5)?; let tph_sett_os_hum = boundary_check::<I2C>(self.tph_sett.os_hum, 0, 5)?;
reg_addr = 0x72u8; reg_addr = 0x72u8;
let mut data = I2CUtil::get_regs_u8(&mut self.i2c, reg_addr)?; let mut data = I2CUtil::get_regs_u8(&mut self.i2c, reg_addr)?;
data = (data as (i32) & !0x7i32 | tph_sett_os_hum as (i32) & 0x7i32) as (u8); data = (data as (i32) & !0x7i32 | tph_sett_os_hum as (i32) & 0x7i32) as (u8);
@ -533,13 +539,13 @@ where
let mut data = I2CUtil::get_regs_u8(&mut self.i2c, reg_addr)?; let mut data = I2CUtil::get_regs_u8(&mut self.i2c, reg_addr)?;
if desired_settings.contains(DesiredSensorSettings::RUN_GAS_SEL) { if desired_settings.contains(DesiredSensorSettings::RUN_GAS_SEL) {
let gas_sett_run_gas = boundary_check(gas_sett.run_gas, 0, 1)?; let gas_sett_run_gas = boundary_check::<I2C>(gas_sett.run_gas, 0, 1)?;
data = (data as (i32) & !0x10i32 | gas_sett_run_gas as (i32) << 4i32 & 0x10i32) data = (data as (i32) & !0x10i32 | gas_sett_run_gas as (i32) << 4i32 & 0x10i32)
as (u8); as (u8);
} }
if desired_settings.contains(DesiredSensorSettings::NBCONV_SEL) { if desired_settings.contains(DesiredSensorSettings::NBCONV_SEL) {
let gas_sett_nb_conv = boundary_check(gas_sett.nb_conv, 0, 10)?; let gas_sett_nb_conv = boundary_check::<I2C>(gas_sett.nb_conv, 0, 10)?;
data = (data as (i32) & !0xfi32 | gas_sett_nb_conv as (i32) & 0xfi32) as (u8); data = (data as (i32) & !0xfi32 | gas_sett_nb_conv as (i32) & 0xfi32) as (u8);
} }
@ -554,12 +560,12 @@ where
} }
// TODO replace desired_settings with proper flags type see lib.rs // TODO replace desired_settings with proper flags type see lib.rs
pub fn get_sensor_settings(&mut self, desired_settings: DesiredSensorSettings) -> Result<SensorSettings> { pub fn get_sensor_settings(&mut self, desired_settings: DesiredSensorSettings) -> Result<SensorSettings, <I2C as Read>::Error, <I2C as Write>::Error> {
let reg_addr: u8 = 0x70u8; let reg_addr: u8 = 0x70u8;
let mut data_array: [u8; BME680_REG_BUFFER_LENGTH] = [0; BME680_REG_BUFFER_LENGTH]; let mut data_array: [u8; BME680_REG_BUFFER_LENGTH] = [0; BME680_REG_BUFFER_LENGTH];
let mut sensor_settings: SensorSettings = Default::default(); let mut sensor_settings: SensorSettings = Default::default();
self.i2c.read(reg_addr, &mut data_array).map_err(|_| Bme680Error::CommunicationFailure)?; self.i2c.read(reg_addr, &mut data_array).map_err(|e| Bme680Error::I2CRead(e))?;
if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL){ if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL){
sensor_settings.gas_sett = self.get_gas_config()?; sensor_settings.gas_sett = self.get_gas_config()?;
@ -594,7 +600,7 @@ where
Ok(sensor_settings) Ok(sensor_settings)
} }
pub fn set_sensor_mode(&mut self, target_power_mode: PowerMode) -> Result<()> { pub fn set_sensor_mode(&mut self, target_power_mode: PowerMode) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error> {
let mut tmp_pow_mode: u8; let mut tmp_pow_mode: u8;
let mut current_power_mode: PowerMode; let mut current_power_mode: PowerMode;
let reg_addr: u8 = 0x74u8; let reg_addr: u8 = 0x74u8;
@ -625,7 +631,7 @@ where
Ok(()) Ok(())
} }
pub fn get_sensor_mode(&mut self) -> Result<PowerMode> { pub fn get_sensor_mode(&mut self) -> Result<PowerMode, <I2C as Read>::Error, <I2C as Write>::Error> {
let regs = I2CUtil::get_regs_u8(&mut self.i2c, BME680_CONF_T_P_MODE_ADDR)?; let regs = I2CUtil::get_regs_u8(&mut self.i2c, BME680_CONF_T_P_MODE_ADDR)?;
let mode = regs & BME680_MODE_MSK; let mode = regs & BME680_MODE_MSK;
Ok(PowerMode::from(mode)) Ok(PowerMode::from(mode))
@ -648,7 +654,7 @@ where
self.gas_sett.heatr_dur = Some((duration as (i32) - tph_dur as (u16) as (i32)) as (u16)); self.gas_sett.heatr_dur = Some((duration as (i32) - tph_dur as (u16) as (i32)) as (u16));
} }
pub fn get_profile_dur(&self, sensor_settings: &SensorSettings) -> Result<u16> { pub fn get_profile_dur(&self, sensor_settings: &SensorSettings) -> Result<u16, <I2C as Read>::Error, <I2C as Write>::Error> {
let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; 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 check if the following unwrap_ors do not change behaviour
let mut meas_cycles = os_to_meas_cycles[sensor_settings.tph_sett.os_temp.unwrap_or(0) as (usize)] as (u32); let mut meas_cycles = os_to_meas_cycles[sensor_settings.tph_sett.os_temp.unwrap_or(0) as (usize)] as (u32);
@ -670,7 +676,7 @@ where
} }
/// @returns (FieldData, IsNewFields) /// @returns (FieldData, IsNewFields)
pub fn get_sensor_data(&mut self) -> Result<(FieldData, FieldDataState)> { pub fn get_sensor_data(&mut self) -> Result<(FieldData, FieldDataState), <I2C as Read>::Error, <I2C as Write>::Error> {
let field_data = self.read_field_data()?; let field_data = self.read_field_data()?;
if field_data.status & BME680_NEW_DATA_MSK != 0 { if field_data.status & BME680_NEW_DATA_MSK != 0 {
// new fields // new fields
@ -680,8 +686,8 @@ where
} }
} }
fn get_calib_data<I2CX>(i2c:&mut I2CX) -> Result<CalibData> fn get_calib_data<I2CX>(i2c:&mut I2CX) -> Result<CalibData, <I2CX as Read>::Error, <I2CX as Write>::Error>
where I2CX: Read where I2CX: Read + Write
{ {
let mut calib: CalibData = Default::default(); let mut calib: CalibData = Default::default();
let mut coeff_array: [u8; BME680_COEFF_SIZE] = [0; BME680_COEFF_SIZE]; let mut coeff_array: [u8; BME680_COEFF_SIZE] = [0; BME680_COEFF_SIZE];
@ -689,12 +695,12 @@ where
i2c.read( i2c.read(
BME680_COEFF_ADDR1, BME680_COEFF_ADDR1,
&mut coeff_array, &mut coeff_array,
).map_err(|_| Bme680Error::CommunicationFailure)?; ).map_err(|e| Bme680Error::I2CRead(e))?;
i2c.read( i2c.read(
BME680_COEFF_ADDR2, BME680_COEFF_ADDR2,
&mut coeff_array, &mut coeff_array,
).map_err(|_| Bme680Error::CommunicationFailure)?; ).map_err(|e| Bme680Error::I2CRead(e))?;
calib.par_t1 = (coeff_array[34usize] as (u16) as (i32) << 8i32 calib.par_t1 = (coeff_array[34usize] as (u16) as (i32) << 8i32
| coeff_array[33usize] as (u16) as (i32)) as (u16); | coeff_array[33usize] as (u16) as (i32)) as (u16);
@ -740,7 +746,7 @@ where
Ok(calib) Ok(calib)
} }
fn set_gas_config(&mut self, gas_sett: GasSett) -> Result<()> { fn set_gas_config(&mut self, gas_sett: GasSett) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error> {
let mut reg = Vec::with_capacity(2); let mut reg = Vec::with_capacity(2);
if self.power_mode != PowerMode::ForcedMode { if self.power_mode != PowerMode::ForcedMode {
@ -755,7 +761,7 @@ where
self.bme680_set_regs(reg.as_slice()) self.bme680_set_regs(reg.as_slice())
} }
fn get_gas_config(&mut self) -> Result<GasSett> { fn get_gas_config(&mut self) -> Result<GasSett, <I2C as Read>::Error, <I2C as Write>::Error> {
// TODO move both GasSett fields to new struct // TODO move both GasSett fields to new struct
let mut gas_sett: GasSett = Default::default(); let mut gas_sett: GasSett = Default::default();
// TODO figure out if heat_temp and dur can be u8 // TODO figure out if heat_temp and dur can be u8
@ -902,7 +908,7 @@ where
calc_gas_res calc_gas_res
} }
fn read_field_data(&mut self) -> Result<FieldData> { fn read_field_data(&mut self) -> Result<FieldData, <I2C as Read>::Error, <I2C as Write>::Error> {
let mut buff = [0, BME680_FIELD_LENGTH]; let mut buff = [0, BME680_FIELD_LENGTH];
let mut data: FieldData = Default::default(); let mut data: FieldData = Default::default();
let mut gas_range: u8; let mut gas_range: u8;
@ -914,7 +920,7 @@ where
loop { loop {
self.i2c.read(BME680_FIELD0_ADDR, &mut buff) self.i2c.read(BME680_FIELD0_ADDR, &mut buff)
.map_err(|_| Bme680Error::CommunicationFailure)?; .map_err(|e| Bme680Error::I2CRead(e))?;
data.status = buff[0] & BME680_NEW_DATA_MSK; data.status = buff[0] & BME680_NEW_DATA_MSK;
data.gas_index = buff[0] & BME680_GAS_INDEX_MSK;; data.gas_index = buff[0] & BME680_GAS_INDEX_MSK;;
data.meas_index = buff[1]; data.meas_index = buff[1];