1use embedded_hal::delay::DelayNs;
12use embedded_hal::i2c::I2c;
13
14use crate::calibration;
15use crate::constants::BME280_COMMAND_SOFTRESET;
16use crate::constants::BME280_REGISTER_CHIPID;
17use crate::constants::BME280_REGISTER_CONFIG;
18use crate::constants::BME280_REGISTER_CONTROL;
19use crate::constants::BME280_REGISTER_CONTROLHUMID;
20use crate::constants::BME280_REGISTER_HUMIDDATA;
21use crate::constants::BME280_REGISTER_PRESSUREDATA;
22use crate::constants::BME280_REGISTER_SOFTRESET;
23use crate::constants::BME280_REGISTER_STATUS;
24use crate::constants::BME280_REGISTER_TEMPDATA;
25use crate::constants::DEFAULT_ADDRESS;
26use crate::constants::MODE_SLEEP;
27use crate::constants::SKIPPED_HUMIDITY_OUTPUT;
28use crate::constants::SKIPPED_PRESSURE_OUTPUT;
29use crate::constants::SKIPPED_TEMPERATURE_OUTPUT;
30use crate::macros::debug;
31use crate::macros::warn;
32use crate::sample::humidity_from_number;
33use crate::sample::pressure_from_pascal;
34use crate::sample::temperature_from_celsius;
35use crate::sample::Humidity;
36use crate::sample::Pressure;
37use crate::sample::RawSample;
38use crate::sample::Sample;
39use crate::sample::Temperature;
40use crate::CalibrationData;
41use crate::Configuration;
42use crate::Status;
43
44pub struct Bme280<I2c, Delay> {
73 i2c: I2c,
75
76 address: u8,
78
79 delay: Delay,
81
82 coefficients: CalibrationData,
84
85 configuration: Configuration,
87}
88
89impl<I2C, D> Bme280<I2C, D>
90where
91 I2C: I2c,
92 D: DelayNs,
93{
94 pub fn new(i2c: I2C, delay: D) -> Self {
97 Self::new_with_address(i2c, DEFAULT_ADDRESS, delay)
98 }
99
100 pub fn release(self) -> I2C {
102 self.i2c
103 }
104
105 pub fn new_with_address(i2c: I2C, address: u8, delay: D) -> Self {
107 Self::new_with_coefficients(i2c, address, delay, CalibrationData::default())
108 }
109
110 fn new_with_coefficients(
112 i2c: I2C,
113 address: u8,
114 delay: D,
115 coefficients: CalibrationData,
116 ) -> Self {
117 debug!("Creating new BME280 device at address 0x{:x}", address);
118 Self {
119 i2c,
120 address,
121 delay,
122 coefficients,
123 configuration: Configuration::default(),
124 }
125 }
126
127 pub fn init(&mut self) -> Result<(), I2C::Error> {
139 debug!("Sending soft-reset signal");
140 self.write_u8(BME280_REGISTER_SOFTRESET, BME280_COMMAND_SOFTRESET)?;
141
142 debug!("Waiting 10 ms");
143 self.delay.delay_ms(10);
144
145 while self.status()?.is_calibrating() {
146 debug!("Calibration not complete, waiting 10 ms");
147 self.delay.delay_ms(10);
148 }
149
150 debug!("Reading coefficients");
151 self.read_calibration_coefficients()?;
152
153 debug!("Set sampling");
154 let configuration = Configuration::default();
155 self.set_sampling_configuration(configuration)?;
156
157 debug!("Waiting 100 ms");
158 self.delay.delay_ms(100);
159
160 Ok(())
161 }
162
163 pub fn chip_id(&mut self) -> Result<u8, I2C::Error> {
172 debug!("Read chip id");
173 let chip_id = self.read_u8(BME280_REGISTER_CHIPID)?;
174
175 Ok(chip_id)
176 }
177
178 pub fn status(&mut self) -> Result<Status, I2C::Error> {
184 debug!("Read chip status");
185 let status = self.read_u8(BME280_REGISTER_STATUS)?.into();
186
187 Ok(status)
188 }
189
190 pub fn set_sampling_configuration(
196 &mut self,
197 configuration: Configuration,
198 ) -> Result<(), I2C::Error> {
199 self.configuration = configuration;
200
201 let (config, ctrl_meas, ctrl_hum) = self.configuration.to_lowlevel_configuration();
202
203 self.write_u8(BME280_REGISTER_CONTROL, MODE_SLEEP)?;
206
207 self.write_u8(BME280_REGISTER_CONTROLHUMID, ctrl_hum.into())?;
211 self.write_u8(BME280_REGISTER_CONFIG, config.into())?;
212 self.write_u8(BME280_REGISTER_CONTROL, ctrl_meas.into())?;
213
214 Ok(())
215 }
216
217 pub fn take_forced_measurement(&mut self) -> Result<bool, I2C::Error> {
228 if self.configuration.is_forced() {
229 debug!("Forcing taking a measurement");
230
231 let (_config, ctrl_meas, _ctrl_hum) = self.configuration.to_lowlevel_configuration();
232 self.write_u8(BME280_REGISTER_CONTROL, ctrl_meas.into())?;
233
234 for _ in 0..10 {
235 if !self.status()?.is_measuring() {
236 break;
237 }
238
239 debug!("Measuring not complete, waiting 10 ms");
240 self.delay.delay_ms(10);
241 }
242
243 Ok(true)
244 } else {
245 Ok(false)
246 }
247 }
248
249 fn read_raw_sample(&mut self) -> Result<RawSample, I2C::Error> {
254 let buffer: [u8; 1] = [BME280_REGISTER_PRESSUREDATA];
255 let mut buf: [u8; 8] = [0; 8];
256 self.i2c.write_read(self.address, &buffer, &mut buf)?;
257
258 let adc_p: u32 =
262 (u32::from(buf[0]) << 12) | (u32::from(buf[1]) << 4) | (u32::from(buf[2]) >> 4);
263 let adc_t: u32 =
267 (u32::from(buf[3]) << 12) | (u32::from(buf[4]) << 4) | (u32::from(buf[5]) >> 4);
268 let adc_h: u16 = (u16::from(buf[6]) << 8) | u16::from(buf[7]);
271
272 Ok(RawSample {
273 adc_t: if adc_t == SKIPPED_TEMPERATURE_OUTPUT {
274 None
275 } else {
276 Some(adc_t)
277 },
278 adc_p: if adc_p == SKIPPED_PRESSURE_OUTPUT {
279 None
280 } else {
281 Some(adc_p)
282 },
283 adc_h: if adc_h == SKIPPED_HUMIDITY_OUTPUT {
284 None
285 } else {
286 Some(adc_h)
287 },
288 })
289 }
290
291 pub fn read_sample(&mut self) -> Result<Sample, I2C::Error> {
300 let RawSample {
301 adc_t,
302 adc_p,
303 adc_h,
304 } = self.read_raw_sample()?;
305
306 if let Some(adc_t) = adc_t {
307 let t_fine = self.coefficients.compensate_temperature(adc_t);
308 let t = Some(Self::temperature_fine_to_temperature(t_fine));
309 let p = adc_p.map(|adc_p| self.coefficients.compensate_pressure(adc_p, t_fine));
310 let h = adc_h.map(|adc_h| self.coefficients.compensate_humidity(adc_h, t_fine));
311
312 let temperature = t;
313
314 #[allow(clippy::cast_precision_loss)] let pressure = p.map(|p| p as f32 / 256.0);
316 let pressure = pressure.map(pressure_from_pascal);
317 #[allow(clippy::cast_precision_loss)] let humidity = h.map(|h| h as f32 / 1024.0);
319 let humidity = humidity.map(humidity_from_number);
320
321 Ok(Sample {
322 temperature,
323 pressure,
324 humidity,
325 })
326 } else {
327 warn!("Temperature measurement is disabled");
328
329 Ok(Sample::default())
330 }
331 }
332
333 fn temperature_fine_to_temperature(t_fine: i32) -> Temperature {
335 let t = (t_fine * 5 + 128) >> 8;
336
337 #[allow(clippy::cast_precision_loss)] let t = t as f32;
339
340 temperature_from_celsius(t / 100.0)
341 }
342
343 pub fn read_temperature(&mut self) -> Result<Option<Temperature>, I2C::Error> {
351 if let Some(t_fine) = self.read_temperature_fine()? {
352 Ok(Some(Self::temperature_fine_to_temperature(t_fine)))
353 } else {
354 Ok(None)
355 }
356 }
357
358 fn read_temperature_fine(&mut self) -> Result<Option<i32>, I2C::Error> {
360 let adc_t = self.read_raw_temperature()?;
361 let t_fine = adc_t.map(|adc_t| self.coefficients.compensate_temperature(adc_t));
362 Ok(t_fine)
363 }
364
365 fn read_raw_temperature(&mut self) -> Result<Option<u32>, I2C::Error> {
370 let adc_t = self.read_u24(BME280_REGISTER_TEMPDATA)?;
371
372 if adc_t == SKIPPED_TEMPERATURE_OUTPUT {
373 Ok(None)
374 } else {
375 Ok(Some(adc_t))
376 }
377 }
378
379 pub fn read_pressure(&mut self) -> Result<Option<Pressure>, I2C::Error> {
390 if let Some(t_fine) = self.read_temperature_fine()? {
391 self.read_pressure_with_temperature_fine(t_fine)
392 } else {
393 warn!("Pressure measurement is disabled");
394 Ok(None)
395 }
396 }
397
398 pub fn read_pressure_with_temperature(
410 &mut self,
411 temperature: f32,
412 ) -> Result<Option<Pressure>, I2C::Error> {
413 #[allow(clippy::cast_possible_truncation)] let t = (temperature * 100.0) as i32;
415 let t_fine = ((t << 8) - 128) / 5;
416 self.read_pressure_with_temperature_fine(t_fine)
417 }
418
419 fn read_pressure_with_temperature_fine(
421 &mut self,
422 t_fine: i32,
423 ) -> Result<Option<Pressure>, I2C::Error> {
424 let adc_p = self.read_raw_pressure()?;
425 let p = adc_p.map(|adc_p| {
426 let p = self.coefficients.compensate_pressure(adc_p, t_fine);
427
428 #[allow(clippy::cast_precision_loss)] let p = p as f32;
430
431 pressure_from_pascal(p / 256.0)
432 });
433 Ok(p)
434 }
435
436 fn read_raw_pressure(&mut self) -> Result<Option<u32>, I2C::Error> {
441 let adc_p = self.read_u24(BME280_REGISTER_PRESSUREDATA)?;
442
443 if adc_p == SKIPPED_PRESSURE_OUTPUT {
444 Ok(None)
445 } else {
446 Ok(Some(adc_p))
447 }
448 }
449
450 pub fn read_humidity(&mut self) -> Result<Option<Humidity>, I2C::Error> {
461 if let Some(t_fine) = self.read_temperature_fine()? {
462 self.read_humidity_with_temperature_fine(t_fine)
463 } else {
464 warn!("Humidity measurement is disabled");
465 Ok(None)
466 }
467 }
468
469 pub fn read_humidity_with_temperature(
481 &mut self,
482 temperature: f32,
483 ) -> Result<Option<Humidity>, I2C::Error> {
484 #[allow(clippy::cast_possible_truncation)] let t = (temperature * 100.0) as i32;
486 let t_fine = ((t << 8) - 128) / 5;
487 self.read_humidity_with_temperature_fine(t_fine)
488 }
489
490 fn read_humidity_with_temperature_fine(
492 &mut self,
493 t_fine: i32,
494 ) -> Result<Option<Humidity>, I2C::Error> {
495 let adc_h = self.read_raw_humidity()?;
496 let h = adc_h.map(|adc_h| {
497 let h = self.coefficients.compensate_humidity(adc_h, t_fine);
498
499 #[allow(clippy::cast_precision_loss)] let h = h as f32;
501
502 humidity_from_number(h / 1024.0)
503 });
504 Ok(h)
505 }
506
507 fn read_raw_humidity(&mut self) -> Result<Option<u16>, I2C::Error> {
512 let adc_h = self.read_u16(BME280_REGISTER_HUMIDDATA)?;
513
514 if adc_h == SKIPPED_HUMIDITY_OUTPUT {
515 Ok(None)
516 } else {
517 Ok(Some(adc_h))
518 }
519 }
520
521 fn read_calibration_coefficients(&mut self) -> Result<(), I2C::Error> {
523 let buffer: [u8; 1] = [calibration::FIRST_REGISTER];
524
525 let mut out: [u8; calibration::TOTAL_LENGTH] = [0; calibration::TOTAL_LENGTH];
526 self.i2c.write_read(
527 self.address,
528 &buffer,
529 &mut out[0..calibration::FIRST_LENGTH],
530 )?;
531
532 let buffer: [u8; 1] = [calibration::SECOND_REGISTER];
533 self.i2c.write_read(
534 self.address,
535 &buffer,
536 &mut out[calibration::FIRST_LENGTH..calibration::TOTAL_LENGTH],
537 )?;
538
539 self.coefficients = (&out).into();
540
541 Ok(())
542 }
543
544 fn write_u8(&mut self, register: u8, value: u8) -> Result<(), I2C::Error> {
546 let buffer: [u8; 2] = [register, value];
547 self.i2c.write(self.address, &buffer)?;
548 Ok(())
549 }
550
551 fn read_u8(&mut self, register: u8) -> Result<u8, I2C::Error> {
553 let buffer: [u8; 1] = [register];
554 let mut output_buffer: [u8; 1] = [0];
555 self.i2c
556 .write_read(self.address, &buffer, &mut output_buffer)?;
557 Ok(output_buffer[0])
558 }
559
560 fn read_u16(&mut self, register: u8) -> Result<u16, I2C::Error> {
562 let buffer: [u8; 1] = [register];
563 let mut output_buffer: [u8; 2] = [0, 0];
564 self.i2c
565 .write_read(self.address, &buffer, &mut output_buffer)?;
566 Ok((u16::from(output_buffer[0]) << 8) | u16::from(output_buffer[1]))
567 }
568
569 fn read_u24(&mut self, register: u8) -> Result<u32, I2C::Error> {
571 let buffer: [u8; 1] = [register];
572 let mut output_buffer: [u8; 3] = [0, 0, 0];
573 self.i2c
574 .write_read(self.address, &buffer, &mut output_buffer)?;
575 Ok((u32::from(output_buffer[0]) << 12)
576 | (u32::from(output_buffer[1]) << 4)
577 | (u32::from(output_buffer[2]) >> 4))
578 }
579}
580
581#[cfg(test)]
582mod tests {
583 #![allow(clippy::panic_in_result_fn)]
584
585 use alloc::vec;
586
587 use embedded_hal::i2c::ErrorKind;
588
589 use embedded_hal_mock::eh1::delay::NoopDelay as DelayMock;
590 use embedded_hal_mock::eh1::i2c::Mock as I2cMock;
591 use embedded_hal_mock::eh1::i2c::Transaction as I2cTransaction;
592
593 use crate::calibration::TEST_CALIBRATION_DATA;
594 use crate::constants::CHIP_ID;
595
596 use super::*;
597
598 #[test]
599 fn test_init() -> Result<(), ErrorKind> {
600 let expectations = [
601 I2cTransaction::write(
603 DEFAULT_ADDRESS,
604 vec![BME280_REGISTER_SOFTRESET, BME280_COMMAND_SOFTRESET],
605 ),
606 I2cTransaction::write_read(
608 DEFAULT_ADDRESS,
609 vec![BME280_REGISTER_STATUS],
610 vec![0b0000_0001],
611 ),
612 I2cTransaction::write_read(
614 DEFAULT_ADDRESS,
615 vec![BME280_REGISTER_STATUS],
616 vec![0b0000_0000],
617 ),
618 I2cTransaction::write_read(
620 DEFAULT_ADDRESS,
621 vec![calibration::FIRST_REGISTER],
622 vec![0; 26],
623 ),
624 I2cTransaction::write_read(
625 DEFAULT_ADDRESS,
626 vec![calibration::SECOND_REGISTER],
627 vec![0; 7],
628 ),
629 I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONTROL, MODE_SLEEP]),
631 I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONTROLHUMID, 0]),
632 I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONFIG, 0]),
633 I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONTROL, 0]),
634 ];
635 let i2c = I2cMock::new(&expectations);
636
637 let mut bme280 = Bme280::new(i2c, DelayMock);
638
639 bme280.init()?;
640
641 bme280.release().done();
642
643 Ok(())
644 }
645
646 #[test]
647 fn test_chip_id() -> Result<(), ErrorKind> {
648 let expectations = [I2cTransaction::write_read(
649 DEFAULT_ADDRESS,
650 vec![BME280_REGISTER_CHIPID],
651 vec![CHIP_ID],
652 )];
653 let i2c = I2cMock::new(&expectations);
654
655 let mut bme280 = Bme280::new(i2c, DelayMock);
656
657 let chip_id = bme280.chip_id()?;
658
659 assert_eq!(chip_id, CHIP_ID);
660
661 bme280.release().done();
662 Ok(())
663 }
664
665 #[test]
666 fn test_chip_status() -> Result<(), ErrorKind> {
667 let expectations = [I2cTransaction::write_read(
668 DEFAULT_ADDRESS,
669 vec![BME280_REGISTER_STATUS],
670 vec![0x00],
671 )];
672 let i2c = I2cMock::new(&expectations);
673
674 let mut bme280 = Bme280::new(i2c, DelayMock);
675
676 let status = bme280.status()?;
677
678 assert!(!status.is_measuring());
679 assert!(!status.is_calibrating());
680
681 bme280.release().done();
682 Ok(())
683 }
684
685 #[test]
686 fn test_chip_status_measuring() -> Result<(), ErrorKind> {
687 let expectations = [I2cTransaction::write_read(
688 DEFAULT_ADDRESS,
689 vec![BME280_REGISTER_STATUS],
690 vec![0b0000_0100],
691 )];
692 let i2c = I2cMock::new(&expectations);
693
694 let mut bme280 = Bme280::new(i2c, DelayMock);
695
696 let status = bme280.status()?;
697
698 assert!(status.is_measuring());
699 assert!(!status.is_calibrating());
700
701 bme280.release().done();
702 Ok(())
703 }
704
705 #[test]
706 fn test_read_temperature_disabled() -> Result<(), ErrorKind> {
707 let expectations = [I2cTransaction::write_read(
708 DEFAULT_ADDRESS,
709 vec![BME280_REGISTER_TEMPDATA],
710 vec![0x80, 0x00, 0x00],
711 )];
712 let i2c = I2cMock::new(&expectations);
713
714 let mut bme280 = Bme280::new_with_coefficients(
715 i2c,
716 DEFAULT_ADDRESS,
717 DelayMock,
718 TEST_CALIBRATION_DATA.clone(),
719 );
720
721 let expected = None;
722
723 let temperature = bme280.read_temperature()?;
724
725 assert_eq!(temperature, expected);
726
727 bme280.release().done();
728 Ok(())
729 }
730
731 #[test]
732 fn test_read_temperature() -> Result<(), ErrorKind> {
733 let expectations = [I2cTransaction::write_read(
734 DEFAULT_ADDRESS,
735 vec![BME280_REGISTER_TEMPDATA],
736 vec![0x84, 0x47, 0x00],
737 )];
738 let i2c = I2cMock::new(&expectations);
739
740 let mut bme280 = Bme280::new_with_coefficients(
741 i2c,
742 DEFAULT_ADDRESS,
743 DelayMock,
744 TEST_CALIBRATION_DATA.clone(),
745 );
746
747 let expected = Some(temperature_from_celsius(27.33));
748
749 let temperature = bme280.read_temperature()?;
750
751 assert_eq!(temperature, expected);
752
753 bme280.release().done();
754 Ok(())
755 }
756
757 #[test]
758 fn test_read_pressure_disabled() -> Result<(), ErrorKind> {
759 let expectations = [
760 I2cTransaction::write_read(
761 DEFAULT_ADDRESS,
762 vec![BME280_REGISTER_TEMPDATA],
763 vec![0x84, 0x47, 0x00],
764 ),
765 I2cTransaction::write_read(
766 DEFAULT_ADDRESS,
767 vec![BME280_REGISTER_PRESSUREDATA],
768 vec![0x80, 0x00, 0x00],
769 ),
770 ];
771 let i2c = I2cMock::new(&expectations);
772
773 let mut bme280 = Bme280::new_with_coefficients(
774 i2c,
775 DEFAULT_ADDRESS,
776 DelayMock,
777 TEST_CALIBRATION_DATA.clone(),
778 );
779
780 let expected = None;
781
782 let pressure = bme280.read_pressure()?;
783
784 assert_eq!(pressure, expected);
785
786 bme280.release().done();
787 Ok(())
788 }
789
790 #[test]
791 fn test_read_pressure() -> Result<(), ErrorKind> {
792 let expectations = [
793 I2cTransaction::write_read(
794 DEFAULT_ADDRESS,
795 vec![BME280_REGISTER_TEMPDATA],
796 vec![0x84, 0x47, 0x00],
797 ),
798 I2cTransaction::write_read(
799 DEFAULT_ADDRESS,
800 vec![BME280_REGISTER_PRESSUREDATA],
801 vec![0x4f, 0x50, 0x00],
802 ),
803 ];
804 let i2c = I2cMock::new(&expectations);
805
806 let mut bme280 = Bme280::new_with_coefficients(
807 i2c,
808 DEFAULT_ADDRESS,
809 DelayMock,
810 TEST_CALIBRATION_DATA.clone(),
811 );
812
813 let expected = Some(pressure_from_pascal(101_233.016));
814
815 let pressure = bme280.read_pressure()?;
816
817 assert_eq!(pressure, expected);
818
819 bme280.release().done();
820 Ok(())
821 }
822
823 #[test]
824 fn test_read_humidity_disabled() -> Result<(), ErrorKind> {
825 let expectations = [
826 I2cTransaction::write_read(
827 DEFAULT_ADDRESS,
828 vec![BME280_REGISTER_TEMPDATA],
829 vec![0x84, 0x47, 0x00],
830 ),
831 I2cTransaction::write_read(
832 DEFAULT_ADDRESS,
833 vec![BME280_REGISTER_HUMIDDATA],
834 vec![0x80, 0x00],
835 ),
836 ];
837 let i2c = I2cMock::new(&expectations);
838
839 let mut bme280 = Bme280::new_with_coefficients(
840 i2c,
841 DEFAULT_ADDRESS,
842 DelayMock,
843 TEST_CALIBRATION_DATA.clone(),
844 );
845
846 let expected = None;
847
848 let humidity = bme280.read_humidity()?;
849
850 assert_eq!(humidity, expected);
851
852 bme280.release().done();
853 Ok(())
854 }
855
856 #[test]
857 fn test_read_humidity() -> Result<(), ErrorKind> {
858 let expectations = [
859 I2cTransaction::write_read(
860 DEFAULT_ADDRESS,
861 vec![BME280_REGISTER_TEMPDATA],
862 vec![0x84, 0x47, 0x00],
863 ),
864 I2cTransaction::write_read(
865 DEFAULT_ADDRESS,
866 vec![BME280_REGISTER_HUMIDDATA],
867 vec![0x60, 0x02],
868 ),
869 ];
870 let i2c = I2cMock::new(&expectations);
871
872 let mut bme280 = Bme280::new_with_coefficients(
873 i2c,
874 DEFAULT_ADDRESS,
875 DelayMock,
876 TEST_CALIBRATION_DATA.clone(),
877 );
878
879 let expected = Some(humidity_from_number(34.854_492));
880
881 let humidity = bme280.read_humidity()?;
882
883 assert_eq!(humidity, expected);
884
885 bme280.release().done();
886 Ok(())
887 }
888}