1#![no_std]
85#![forbid(unsafe_code)]
86
87pub use self::settings::{
88 DesiredSensorSettings, GasSett, IIRFilterSize, OversamplingSetting, SensorSettings, Settings,
89 SettingsBuilder, TphSett,
90};
91
92mod calc;
93mod settings;
94
95use crate::calc::Calc;
96use crate::hal::blocking::delay::DelayMs;
97use crate::hal::blocking::i2c::{Read, Write};
98
99use core::time::Duration;
100use core::{marker::PhantomData, result};
101use embedded_hal as hal;
102use log::{debug, error, info};
103
104pub const BME680_POLL_PERIOD_MS: u8 = 10;
106
107pub const BME680_CHIP_ID: u8 = 0x61;
109
110const BME680_FIELD_LENGTH: usize = 15;
112
113const BME680_COEFF_ADDR1_LEN: usize = 25;
115const BME680_COEFF_ADDR2_LEN: usize = 16;
116
117const BME680_SOFT_RESET_CMD: u8 = 0xb6;
118
119const BME680_ADDR_RES_HEAT_VAL_ADDR: u8 = 0x00;
122const BME680_ADDR_RES_HEAT_RANGE_ADDR: u8 = 0x02;
123const BME680_ADDR_RANGE_SW_ERR_ADDR: u8 = 0x04;
124const BME680_ADDR_SENS_CONF_START: u8 = 0x5A;
125const BME680_ADDR_GAS_CONF_START: u8 = 0x64;
126
127const BME680_SOFT_RESET_ADDR: u8 = 0xe0;
128
129const BME680_FIELD0_ADDR: u8 = 0x1d;
131
132const BME680_RES_HEAT0_ADDR: u8 = 0x5a;
134const BME680_GAS_WAIT0_ADDR: u8 = 0x64;
135
136const BME680_CONF_HEAT_CTRL_ADDR: u8 = 0x70;
138const BME680_CONF_ODR_RUN_GAS_NBC_ADDR: u8 = 0x71;
139const BME680_CONF_OS_H_ADDR: u8 = 0x72;
140const BME680_CONF_T_P_MODE_ADDR: u8 = 0x74;
141const BME680_CONF_ODR_FILT_ADDR: u8 = 0x75;
142
143const BME680_COEFF_ADDR1: u8 = 0x89;
145const BME680_COEFF_ADDR2: u8 = 0xe1;
146
147const BME680_CHIP_ID_ADDR: u8 = 0xd0;
149
150const BME680_SLEEP_MODE: u8 = 0;
151const BME680_FORCED_MODE: u8 = 1;
152
153const BME680_RESET_PERIOD: u8 = 10;
154
155const BME680_MODE_MSK: u8 = 0x03;
156const BME680_RSERROR_MSK: u8 = 0xf0;
157const BME680_NEW_DATA_MSK: u8 = 0x80;
158const BME680_GAS_INDEX_MSK: u8 = 0x0f;
159const BME680_GAS_RANGE_MSK: u8 = 0x0f;
160const BME680_GASM_VALID_MSK: u8 = 0x20;
161const BME680_HEAT_STAB_MSK: u8 = 0x10;
162
163const BME680_TMP_BUFFER_LENGTH: usize = 40;
165const BME680_REG_BUFFER_LENGTH: usize = 6;
166
167#[derive(Debug)]
169pub enum Error<R, W> {
170 I2CWrite(W),
174 I2CRead(R),
175 DeviceNotFound,
179 InvalidLength,
183 DefinePwrMode,
187 NoNewData,
191 BoundaryCheckFailure(&'static str),
195}
196
197pub type Result<T, R, W> = result::Result<T, Error<R, W>>;
199
200#[derive(Debug, PartialEq, Clone, Copy)]
204pub enum PowerMode {
205 SleepMode,
206 ForcedMode,
207}
208
209impl PowerMode {
210 fn from(power_mode: u8) -> Self {
212 match power_mode {
213 BME680_SLEEP_MODE => PowerMode::SleepMode,
214 BME680_FORCED_MODE => PowerMode::ForcedMode,
215 _ => panic!("Unknown power mode: {}", power_mode),
216 }
217 }
218
219 fn value(&self) -> u8 {
220 match self {
221 PowerMode::SleepMode => BME680_SLEEP_MODE,
222 PowerMode::ForcedMode => BME680_FORCED_MODE,
223 }
224 }
225}
226
227#[derive(Debug, Clone, Copy)]
236pub enum I2CAddress {
237 Primary,
239 Secondary,
241 Other(u8),
243}
244
245impl I2CAddress {
246 pub fn addr(&self) -> u8 {
247 match &self {
248 I2CAddress::Primary => 0x76u8,
249 I2CAddress::Secondary => 0x77u8,
250 I2CAddress::Other(addr) => *addr,
251 }
252 }
253}
254
255impl Default for I2CAddress {
256 fn default() -> I2CAddress {
257 I2CAddress::Primary
258 }
259}
260
261#[derive(Debug, Default, Copy)]
263#[repr(C)]
264pub struct CalibData {
265 pub par_h1: u16,
266 pub par_h2: u16,
267 pub par_h3: i8,
268 pub par_h4: i8,
269 pub par_h5: i8,
270 pub par_h6: u8,
271 pub par_h7: i8,
272 pub par_gh1: i8,
273 pub par_gh2: i16,
274 pub par_gh3: i8,
275 pub par_t1: u16,
276 pub par_t2: i16,
277 pub par_t3: i8,
278 pub par_p1: u16,
279 pub par_p2: i16,
280 pub par_p3: i8,
281 pub par_p4: i16,
282 pub par_p5: i16,
283 pub par_p6: i8,
284 pub par_p7: i8,
285 pub par_p8: i16,
286 pub par_p9: i16,
287 pub par_p10: u8,
288 pub res_heat_range: u8,
289 pub res_heat_val: i8,
290 pub range_sw_err: u8,
291}
292
293impl Clone for CalibData {
294 fn clone(&self) -> Self {
295 *self
296 }
297}
298
299#[derive(Debug, Default, Copy)]
301#[repr(C)]
302pub struct FieldData {
303 status: u8,
305 gas_index: u8,
307 meas_index: u8,
309 temperature: i16,
310 pressure: u32,
311 humidity: u32,
312 gas_resistance: u32,
313}
314
315impl Clone for FieldData {
316 fn clone(&self) -> Self {
317 *self
318 }
319}
320
321impl FieldData {
322 pub fn temperature_celsius(&self) -> f32 {
324 self.temperature as f32 / 100f32
325 }
326
327 pub fn pressure_hpa(&self) -> f32 {
329 self.pressure as f32 / 100f32
330 }
331
332 pub fn humidity_percent(&self) -> f32 {
334 self.humidity as f32 / 1000f32
335 }
336
337 pub fn gas_resistance_ohm(&self) -> u32 {
338 self.gas_resistance
339 }
340
341 pub fn gas_valid(&self) -> bool {
343 self.status & BME680_GASM_VALID_MSK != 0
344 }
345
346 pub fn heat_stable(&self) -> bool {
351 self.status & BME680_HEAT_STAB_MSK != 0
352 }
353}
354
355#[derive(PartialEq, Debug)]
357pub enum FieldDataCondition {
358 NewData,
362 Unchanged,
366}
367
368struct I2CUtil {}
369
370impl I2CUtil {
371 pub fn read_byte<I2C>(
372 i2c: &mut I2C,
373 dev_id: u8,
374 reg_addr: u8,
375 ) -> Result<u8, <I2C as Read>::Error, <I2C as Write>::Error>
376 where
377 I2C: Read + Write,
378 {
379 let mut buf = [0; 1];
380
381 i2c.write(dev_id, &[reg_addr]).map_err(Error::I2CWrite)?;
382
383 match i2c.read(dev_id, &mut buf) {
384 Ok(()) => Ok(buf[0]),
385 Err(e) => Err(Error::I2CRead(e)),
386 }
387 }
388
389 pub fn read_bytes<I2C>(
390 i2c: &mut I2C,
391 dev_id: u8,
392 reg_addr: u8,
393 buf: &mut [u8],
394 ) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error>
395 where
396 I2C: Read + Write,
397 {
398 i2c.write(dev_id, &[reg_addr]).map_err(Error::I2CWrite)?;
399
400 match i2c.read(dev_id, buf) {
401 Ok(()) => Ok(()),
402 Err(e) => Err(Error::I2CRead(e)),
403 }
404 }
405}
406
407#[repr(C)]
409pub struct Bme680<I2C, D> {
410 i2c: I2C,
411 delay: PhantomData<D>,
412 dev_id: I2CAddress,
413 calib: CalibData,
414 tph_sett: TphSett,
416 gas_sett: GasSett,
418 power_mode: PowerMode,
420}
421
422fn boundary_check<I2C>(
423 value: Option<u8>,
424 value_name: &'static str,
425 min: u8,
426 max: u8,
427) -> Result<u8, <I2C as Read>::Error, <I2C as Write>::Error>
428where
429 I2C: Read + Write,
430{
431 let value = value.ok_or(Error::BoundaryCheckFailure(value_name))?;
432
433 if value < min {
434 const MIN: &str = "Boundary check failure, value exceeds maximum";
435 error!("{}, value name: {}", MIN, value_name);
436 return Err(Error::BoundaryCheckFailure(MIN));
437 }
438
439 if value > max {
440 const MAX: &str = "Boundary check, value exceeds minimum";
441 error!("{}, value name: {}", MAX, value_name);
442 return Err(Error::BoundaryCheckFailure(MAX));
443 }
444 Ok(value)
445}
446
447impl<I2C, D> Bme680<I2C, D>
448where
449 D: DelayMs<u8>,
450 I2C: Read + Write,
451{
452 pub fn soft_reset(
453 i2c: &mut I2C,
454 delay: &mut D,
455 dev_id: I2CAddress,
456 ) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error> {
457 let tmp_buff: [u8; 2] = [BME680_SOFT_RESET_ADDR, BME680_SOFT_RESET_CMD];
458
459 i2c.write(dev_id.addr(), &tmp_buff)
460 .map_err(Error::I2CWrite)?;
461
462 delay.delay_ms(BME680_RESET_PERIOD);
463 Ok(())
464 }
465
466 pub fn init(
467 mut i2c: I2C,
468 delay: &mut D,
469 dev_id: I2CAddress,
470 ) -> Result<Bme680<I2C, D>, <I2C as Read>::Error, <I2C as Write>::Error> {
471 Bme680::soft_reset(&mut i2c, delay, dev_id)?;
472
473 debug!("Reading chip id");
474 let chip_id = I2CUtil::read_byte::<I2C>(&mut i2c, dev_id.addr(), BME680_CHIP_ID_ADDR)?;
476 debug!("Chip id: {}", chip_id);
477
478 if chip_id == BME680_CHIP_ID {
479 debug!("Reading calib data");
480 let calib = Bme680::<I2C, D>::get_calib_data::<I2C>(&mut i2c, dev_id)?;
481 debug!("Calib data {:?}", calib);
482 let dev = Bme680 {
483 i2c,
484 delay: PhantomData,
485 dev_id,
486 calib,
487 power_mode: PowerMode::ForcedMode,
488 tph_sett: Default::default(),
489 gas_sett: Default::default(),
490 };
491 info!("Finished device init");
492 Ok(dev)
493 } else {
494 error!("Device does not match chip id {}", BME680_CHIP_ID);
495 Err(Error::DeviceNotFound)
496 }
497 }
498
499 fn bme680_set_regs(
500 &mut self,
501 reg: &[(u8, u8)],
502 ) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error> {
503 if reg.is_empty() || reg.len() > (BME680_TMP_BUFFER_LENGTH / 2) as usize {
504 return Err(Error::InvalidLength);
505 }
506
507 for (reg_addr, reg_data) in reg {
508 let tmp_buff: [u8; 2] = [*reg_addr, *reg_data];
509 debug!(
510 "Setting register reg: {:?} tmp_buf: {:?}",
511 reg_addr, tmp_buff
512 );
513 self.i2c
514 .write(self.dev_id.addr(), &tmp_buff)
515 .map_err(Error::I2CWrite)?;
516 }
517
518 Ok(())
519 }
520
521 pub fn set_sensor_settings(
523 &mut self,
524 delay: &mut D,
525 settings: Settings,
526 ) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error> {
527 let (sensor_settings, desired_settings) = settings;
528 let tph_sett = sensor_settings.tph_sett;
529 let gas_sett = sensor_settings.gas_sett;
530
531 let mut reg: [(u8, u8); BME680_REG_BUFFER_LENGTH] = [(0, 0); BME680_REG_BUFFER_LENGTH];
532 let intended_power_mode = self.power_mode;
533
534 if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL) {
535 debug!("GAS_MEAS_SEL: true");
536 self.set_gas_config(gas_sett)?;
537 }
538
539 let power_mode = self.power_mode;
540 self.set_sensor_mode(delay, power_mode)?;
541
542 let mut element_index = 0;
543 if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) {
545 let mut data =
546 I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_ODR_FILT_ADDR)?;
547
548 debug!("FILTER_SEL: true");
549 data = (data as i32 & !0x1ci32
550 | (tph_sett.filter.unwrap_or(IIRFilterSize::Size0) as i32) << 2i32 & 0x1ci32)
551 as u8;
552 reg[element_index] = (BME680_CONF_ODR_FILT_ADDR, data);
553 element_index += 1;
554 }
555
556 if desired_settings.contains(DesiredSensorSettings::HCNTRL_SEL) {
557 debug!("HCNTRL_SEL: true");
558 let gas_sett_heatr_ctrl =
559 boundary_check::<I2C>(gas_sett.heatr_ctrl, "GasSett.heatr_ctrl", 0x0u8, 0x8u8)?;
560 let mut data = I2CUtil::read_byte(
561 &mut self.i2c,
562 self.dev_id.addr(),
563 BME680_CONF_HEAT_CTRL_ADDR,
564 )?;
565 data = (data as i32 & !0x8i32 | gas_sett_heatr_ctrl as i32 & 0x8) as u8;
566 reg[element_index] = (BME680_CONF_HEAT_CTRL_ADDR, data);
567 element_index += 1;
568 }
569
570 if desired_settings
572 .contains(DesiredSensorSettings::OST_SEL | DesiredSensorSettings::OSP_SEL)
573 {
574 let mut data =
575 I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_T_P_MODE_ADDR)?;
576
577 if desired_settings.contains(DesiredSensorSettings::OST_SEL) {
578 debug!("OST_SEL: true");
579 let tph_sett_os_temp = boundary_check::<I2C>(
580 tph_sett.os_temp.map(|x| x as u8),
581 "TphSett.os_temp",
582 0,
583 5,
584 )?;
585 data = (data as i32 & !0xe0i32 | (tph_sett_os_temp as i32) << 5i32 & 0xe0i32) as u8;
586 }
587
588 if desired_settings.contains(DesiredSensorSettings::OSP_SEL) {
589 debug!("OSP_SEL: true");
590 let tph_sett_os_pres = tph_sett.os_temp.expect("OS TEMP");
591 data = (data as i32 & !0x1ci32 | (tph_sett_os_pres as i32) << 2i32 & 0x1ci32) as u8;
592 }
593 reg[element_index] = (BME680_CONF_T_P_MODE_ADDR, data);
594 element_index += 1;
595 }
596
597 if desired_settings.contains(DesiredSensorSettings::OSH_SEL) {
599 debug!("OSH_SEL: true");
600 let tph_sett_os_hum =
601 boundary_check::<I2C>(tph_sett.os_hum.map(|x| x as u8), "TphSett.os_hum", 0, 5)?;
602 let mut data =
603 I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_OS_H_ADDR)?;
604 data = (data as i32 & !0x7i32 | tph_sett_os_hum as i32 & 0x7i32) as u8;
605 reg[element_index] = (BME680_CONF_OS_H_ADDR, data);
606 element_index += 1;
607 }
608
609 if desired_settings
611 .contains(DesiredSensorSettings::RUN_GAS_SEL | DesiredSensorSettings::NBCONV_SEL)
612 {
613 let mut data = I2CUtil::read_byte(
614 &mut self.i2c,
615 self.dev_id.addr(),
616 BME680_CONF_ODR_RUN_GAS_NBC_ADDR,
617 )?;
618
619 if desired_settings.contains(DesiredSensorSettings::RUN_GAS_SEL) {
620 debug!("RUN_GAS_SEL: true");
621 data = (data as i32 & !0x10i32
622 | (gas_sett.run_gas_measurement as i32) << 4i32 & 0x10i32)
623 as u8;
624 }
625
626 if desired_settings.contains(DesiredSensorSettings::NBCONV_SEL) {
627 debug!("NBCONV_SEL: true");
628 let gas_sett_nb_conv =
629 boundary_check::<I2C>(Some(gas_sett.nb_conv), "GasSett.nb_conv", 0, 10)?;
630 data = (data as i32 & !0xfi32 | gas_sett_nb_conv as i32 & 0xfi32) as u8;
631 }
632
633 reg[element_index] = (BME680_CONF_ODR_RUN_GAS_NBC_ADDR, data);
634 element_index += 1;
635 }
636
637 self.bme680_set_regs(®[0..element_index])?;
638
639 self.power_mode = intended_power_mode;
641 self.tph_sett = tph_sett;
642 Ok(())
643 }
644
645 pub fn get_sensor_settings(
651 &mut self,
652 desired_settings: DesiredSensorSettings,
653 ) -> Result<SensorSettings, <I2C as Read>::Error, <I2C as Write>::Error> {
654 let reg_addr: u8 = 0x70u8;
655 let mut data_array: [u8; BME680_REG_BUFFER_LENGTH] = [0; BME680_REG_BUFFER_LENGTH];
656 let mut sensor_settings: SensorSettings = Default::default();
657 sensor_settings.tph_sett.temperature_offset = self.tph_sett.temperature_offset;
658
659 I2CUtil::read_bytes(&mut self.i2c, self.dev_id.addr(), reg_addr, &mut data_array)?;
660
661 if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL) {
662 sensor_settings.gas_sett = self.get_gas_config()?;
663 }
664
665 if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) {
666 sensor_settings.tph_sett.filter = Some(IIRFilterSize::from_u8(
667 ((data_array[5usize] as i32 & 0x1ci32) >> 2i32) as u8,
668 ));
669 }
670
671 if desired_settings
672 .contains(DesiredSensorSettings::OST_SEL | DesiredSensorSettings::OSP_SEL)
673 {
674 let os_temp: u8 = ((data_array[4usize] as i32 & 0xe0i32) >> 5i32) as u8;
675 let os_pres: u8 = ((data_array[4usize] as i32 & 0x1ci32) >> 2i32) as u8;
676 sensor_settings.tph_sett.os_temp = Some(OversamplingSetting::from_u8(os_temp));
677 sensor_settings.tph_sett.os_pres = Some(OversamplingSetting::from_u8(os_pres));
678 }
679
680 if desired_settings.contains(DesiredSensorSettings::OSH_SEL) {
681 let os_hum: u8 = (data_array[2usize] as i32 & 0x7i32) as u8;
682 sensor_settings.tph_sett.os_hum = Some(OversamplingSetting::from_u8(os_hum));
683 }
684
685 if desired_settings.contains(DesiredSensorSettings::HCNTRL_SEL) {
686 sensor_settings.gas_sett.heatr_ctrl = Some((data_array[0usize] as i32 & 0x8i32) as u8);
687 }
688
689 if desired_settings
690 .contains(DesiredSensorSettings::RUN_GAS_SEL | DesiredSensorSettings::NBCONV_SEL)
691 {
692 sensor_settings.gas_sett.nb_conv = (data_array[1usize] as i32 & 0xfi32) as u8;
693 sensor_settings.gas_sett.run_gas_measurement =
694 ((data_array[1usize] as i32 & 0x10i32) >> 4i32) == 0;
695 }
696
697 Ok(sensor_settings)
698 }
699
700 pub fn set_sensor_mode(
706 &mut self,
707 delay: &mut D,
708 target_power_mode: PowerMode,
709 ) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error> {
710 let mut tmp_pow_mode: u8;
711 let mut current_power_mode: PowerMode;
712
713 loop {
715 tmp_pow_mode =
716 I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_T_P_MODE_ADDR)?;
717
718 current_power_mode = PowerMode::from(tmp_pow_mode & BME680_MODE_MSK);
720
721 debug!("Current power mode: {:?}", current_power_mode);
722
723 if current_power_mode != PowerMode::SleepMode {
724 tmp_pow_mode &= !BME680_MODE_MSK;
726 debug!("Setting to sleep tmp_pow_mode: {}", tmp_pow_mode);
727 self.bme680_set_regs(&[(BME680_CONF_T_P_MODE_ADDR, tmp_pow_mode)])?;
728 delay.delay_ms(BME680_POLL_PERIOD_MS);
729 } else {
730 break;
732 }
733 }
734
735 if target_power_mode != PowerMode::SleepMode {
737 tmp_pow_mode = tmp_pow_mode & !BME680_MODE_MSK | target_power_mode.value();
738 debug!("Already in sleep Target power mode: {}", tmp_pow_mode);
739 self.bme680_set_regs(&[(BME680_CONF_T_P_MODE_ADDR, tmp_pow_mode)])?;
740 }
741 Ok(())
742 }
743
744 pub fn get_sensor_mode(
746 &mut self,
747 ) -> Result<PowerMode, <I2C as Read>::Error, <I2C as Write>::Error> {
748 let regs =
749 I2CUtil::read_byte(&mut self.i2c, self.dev_id.addr(), BME680_CONF_T_P_MODE_ADDR)?;
750 let mode = regs & BME680_MODE_MSK;
751 Ok(PowerMode::from(mode))
752 }
753
754 pub fn bme680_set_profile_dur(&mut self, tph_sett: TphSett, duration: Duration) {
755 let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8];
756 const MILLIS_PER_SEC: u64 = 1_000;
759 const NANOS_PER_MILLI: u64 = 1_000_000;
760 let millis = (duration.as_secs() as u64 * MILLIS_PER_SEC)
761 + (duration.subsec_nanos() as u64 / NANOS_PER_MILLI);
762
763 let mut meas_cycles = os_to_meas_cycles
764 [tph_sett.os_temp.unwrap_or(OversamplingSetting::OSNone) as usize]
765 as u64;
766 meas_cycles = meas_cycles.wrapping_add(
767 os_to_meas_cycles[tph_sett.os_pres.unwrap_or(OversamplingSetting::OSNone) as usize]
768 as u64,
769 );
770 meas_cycles = meas_cycles.wrapping_add(
771 os_to_meas_cycles[tph_sett.os_hum.unwrap_or(OversamplingSetting::OSNone) as usize]
772 as u64,
773 );
774 let mut tph_dur = meas_cycles.wrapping_mul(1963u64);
775 tph_dur = tph_dur.wrapping_add(477u64.wrapping_mul(4u64));
776 tph_dur = tph_dur.wrapping_add(477u64.wrapping_mul(5u64));
777 tph_dur = tph_dur.wrapping_add(500u64);
778 tph_dur = tph_dur.wrapping_div(1000u64);
779 tph_dur = tph_dur.wrapping_add(1u64);
780 self.gas_sett.heatr_dur = Some(Duration::from_millis(millis - tph_dur));
781 }
782
783 pub fn get_profile_dur(
784 &self,
785 sensor_settings: &SensorSettings,
786 ) -> Result<Duration, <I2C as Read>::Error, <I2C as Write>::Error> {
787 let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8];
788 let mut meas_cycles = os_to_meas_cycles[sensor_settings
790 .tph_sett
791 .os_temp
792 .unwrap_or(OversamplingSetting::OSNone)
793 as usize] as u32;
794 meas_cycles = meas_cycles.wrapping_add(
795 os_to_meas_cycles[sensor_settings
796 .tph_sett
797 .os_pres
798 .unwrap_or(OversamplingSetting::OSNone) as usize] as u32,
799 );
800 meas_cycles = meas_cycles.wrapping_add(
801 os_to_meas_cycles[sensor_settings
802 .tph_sett
803 .os_hum
804 .unwrap_or(OversamplingSetting::OSNone) as usize] as u32,
805 );
806 let mut tph_dur = meas_cycles.wrapping_mul(1963u32);
807 tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(4u32));
808 tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(5u32));
809 tph_dur = tph_dur.wrapping_add(500u32);
810 tph_dur = tph_dur.wrapping_div(1000u32);
811 tph_dur = tph_dur.wrapping_add(1u32);
812 let mut duration = Duration::from_millis(tph_dur as u64);
813 if sensor_settings.gas_sett.run_gas_measurement {
814 duration += sensor_settings.gas_sett.heatr_dur.expect("Heatrdur");
815 }
816 Ok(duration)
817 }
818
819 fn get_calib_data<I2CX>(
820 i2c: &mut I2CX,
821 dev_id: I2CAddress,
822 ) -> Result<CalibData, <I2CX as Read>::Error, <I2CX as Write>::Error>
823 where
824 I2CX: Read + Write,
825 {
826 let mut calib: CalibData = Default::default();
827
828 let mut coeff_array: [u8; BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN] =
829 [0; BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN];
830
831 I2CUtil::read_bytes::<I2CX>(
832 i2c,
833 dev_id.addr(),
834 BME680_COEFF_ADDR1,
835 &mut coeff_array[0..(BME680_COEFF_ADDR1_LEN - 1)],
836 )?;
837
838 I2CUtil::read_bytes::<I2CX>(
839 i2c,
840 dev_id.addr(),
841 BME680_COEFF_ADDR2,
842 &mut coeff_array
843 [BME680_COEFF_ADDR1_LEN..(BME680_COEFF_ADDR1_LEN + BME680_COEFF_ADDR2_LEN - 1)],
844 )?;
845
846 calib.par_t1 = ((coeff_array[34usize] as i32) << 8i32 | coeff_array[33usize] as i32) as u16;
847 calib.par_t2 = ((coeff_array[2usize] as i32) << 8i32 | coeff_array[1usize] as i32) as i16;
848 calib.par_t3 = coeff_array[3usize] as i8;
849 calib.par_p1 = ((coeff_array[6usize] as i32) << 8i32 | coeff_array[5usize] as i32) as u16;
850 calib.par_p2 = ((coeff_array[8usize] as i32) << 8i32 | coeff_array[7usize] as i32) as i16;
851 calib.par_p3 = coeff_array[9usize] as i8;
852 calib.par_p4 = ((coeff_array[12usize] as i32) << 8i32 | coeff_array[11usize] as i32) as i16;
853 calib.par_p5 = ((coeff_array[14usize] as i32) << 8i32 | coeff_array[13usize] as i32) as i16;
854 calib.par_p6 = coeff_array[16usize] as i8;
855 calib.par_p7 = coeff_array[15usize] as i8;
856 calib.par_p8 = ((coeff_array[20usize] as i32) << 8i32 | coeff_array[19usize] as i32) as i16;
857 calib.par_p9 = ((coeff_array[22usize] as i32) << 8i32 | coeff_array[21usize] as i32) as i16;
858 calib.par_p10 = coeff_array[23usize];
859 calib.par_h1 =
860 ((coeff_array[27usize] as i32) << 4i32 | coeff_array[26usize] as i32 & 0xfi32) as u16;
861 calib.par_h2 =
862 ((coeff_array[25usize] as i32) << 4i32 | coeff_array[26usize] as i32 >> 4i32) as u16;
863 calib.par_h3 = coeff_array[28usize] as i8;
864 calib.par_h4 = coeff_array[29usize] as i8;
865 calib.par_h5 = coeff_array[30usize] as i8;
866 calib.par_h6 = coeff_array[31usize];
867 calib.par_h7 = coeff_array[32usize] as i8;
868 calib.par_gh1 = coeff_array[37usize] as i8;
869 calib.par_gh2 =
870 ((coeff_array[36usize] as i32) << 8i32 | coeff_array[35usize] as i32) as i16;
871 calib.par_gh3 = coeff_array[38usize] as i8;
872
873 calib.res_heat_range =
874 (I2CUtil::read_byte::<I2CX>(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_RANGE_ADDR)?
875 & 0x30)
876 / 16;
877
878 calib.res_heat_val =
879 I2CUtil::read_byte::<I2CX>(i2c, dev_id.addr(), BME680_ADDR_RES_HEAT_VAL_ADDR)? as i8;
880
881 calib.range_sw_err =
882 (I2CUtil::read_byte::<I2CX>(i2c, dev_id.addr(), BME680_ADDR_RANGE_SW_ERR_ADDR)?
883 & BME680_RSERROR_MSK)
884 / 16;
885
886 Ok(calib)
887 }
888
889 fn set_gas_config(
890 &mut self,
891 gas_sett: GasSett,
892 ) -> Result<(), <I2C as Read>::Error, <I2C as Write>::Error> {
893 if self.power_mode != PowerMode::ForcedMode {
894 return Err(Error::DefinePwrMode);
895 }
896
897 let reg: [(u8, u8); 2] = [
899 (
900 BME680_RES_HEAT0_ADDR,
901 Calc::calc_heater_res(
902 &self.calib,
903 gas_sett.ambient_temperature,
904 gas_sett.heatr_temp.unwrap_or(0),
905 ),
906 ),
907 (
908 BME680_GAS_WAIT0_ADDR,
909 Calc::calc_heater_dur(gas_sett.heatr_dur.unwrap_or_else(|| Duration::from_secs(0))),
910 ),
911 ];
912
913 self.gas_sett.nb_conv = 0;
914 self.bme680_set_regs(®)
915 }
916
917 fn get_gas_config(&mut self) -> Result<GasSett, <I2C as Read>::Error, <I2C as Write>::Error> {
918 let heatr_temp = Some(I2CUtil::read_byte(
919 &mut self.i2c,
920 self.dev_id.addr(),
921 BME680_ADDR_SENS_CONF_START,
922 )? as u16);
923
924 let heatr_dur_ms = I2CUtil::read_byte(
925 &mut self.i2c,
926 self.dev_id.addr(),
927 BME680_ADDR_GAS_CONF_START,
928 )? as u64;
929
930 let gas_sett = GasSett {
931 heatr_temp,
932 heatr_dur: Some(Duration::from_millis(heatr_dur_ms)),
933 ..Default::default()
934 };
935
936 Ok(gas_sett)
937 }
938
939 pub fn get_sensor_data(
941 &mut self,
942 delay: &mut D,
943 ) -> Result<(FieldData, FieldDataCondition), <I2C as Read>::Error, <I2C as Write>::Error> {
944 let mut buff: [u8; BME680_FIELD_LENGTH] = [0; BME680_FIELD_LENGTH];
945
946 debug!("Buf {:?}, len: {}", buff, buff.len());
947 let mut data: FieldData = Default::default();
948
949 const TRIES: u8 = 10;
950 for _ in 0..TRIES {
951 I2CUtil::read_bytes(
952 &mut self.i2c,
953 self.dev_id.addr(),
954 BME680_FIELD0_ADDR,
955 &mut buff,
956 )?;
957
958 debug!("Field data read {:?}, len: {}", buff, buff.len());
959
960 data.status = buff[0] & BME680_NEW_DATA_MSK;
961 data.gas_index = buff[0] & BME680_GAS_INDEX_MSK;
962 data.meas_index = buff[1];
963
964 let adc_pres = (buff[2] as u32).wrapping_mul(4096)
965 | (buff[3] as u32).wrapping_mul(16)
966 | (buff[4] as u32).wrapping_div(16);
967 let adc_temp = (buff[5] as u32).wrapping_mul(4096)
968 | (buff[6] as u32).wrapping_mul(16)
969 | (buff[7] as u32).wrapping_div(16);
970 let adc_hum = ((buff[8] as u32).wrapping_mul(256) | buff[9] as u32) as u16;
971 let adc_gas_res =
972 ((buff[13] as u32).wrapping_mul(4) | (buff[14] as u32).wrapping_div(64)) as u16;
973 let gas_range = buff[14] & BME680_GAS_RANGE_MSK;
974
975 data.status |= buff[14] & BME680_GASM_VALID_MSK;
976 data.status |= buff[14] & BME680_HEAT_STAB_MSK;
977
978 if data.status & BME680_NEW_DATA_MSK != 0 {
979 let (temp, t_fine) =
980 Calc::calc_temperature(&self.calib, adc_temp, self.tph_sett.temperature_offset);
981 debug!(
982 "adc_temp: {} adc_pres: {} adc_hum: {} adc_gas_res: {}, t_fine: {}",
983 adc_temp, adc_pres, adc_hum, adc_gas_res, t_fine
984 );
985 data.temperature = temp;
986 data.pressure = Calc::calc_pressure(&self.calib, t_fine, adc_pres);
987 data.humidity = Calc::calc_humidity(&self.calib, t_fine, adc_hum);
988 data.gas_resistance =
989 Calc::calc_gas_resistance(&self.calib, adc_gas_res, gas_range);
990 return Ok((data, FieldDataCondition::NewData));
991 }
992
993 delay.delay_ms(BME680_POLL_PERIOD_MS);
994 }
995 Ok((data, FieldDataCondition::Unchanged))
996 }
997}