1use embedded_hal_async::delay::DelayNs;
12use embedded_hal_async::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> {
46 i2c: I2c,
48
49 address: u8,
51
52 delay: Delay,
54
55 coefficients: CalibrationData,
57
58 configuration: Configuration,
60}
61
62impl<I2C, D> Bme280<I2C, D>
63where
64 I2C: I2c,
65 D: DelayNs,
66{
67 pub fn new(i2c: I2C, delay: D) -> Self {
70 Self::new_with_address(i2c, DEFAULT_ADDRESS, delay)
71 }
72
73 pub fn release(self) -> I2C {
75 self.i2c
76 }
77
78 pub fn new_with_address(i2c: I2C, address: u8, delay: D) -> Self {
80 Self::new_with_coefficients(i2c, address, delay, CalibrationData::default())
81 }
82
83 fn new_with_coefficients(
85 i2c: I2C,
86 address: u8,
87 delay: D,
88 coefficients: CalibrationData,
89 ) -> Self {
90 debug!("Creating new BME280 device at address 0x{:x}", address);
91 Self {
92 i2c,
93 address,
94 delay,
95 coefficients,
96 configuration: Configuration::default(),
97 }
98 }
99
100 pub async fn init(&mut self) -> Result<(), I2C::Error> {
112 debug!("Sending soft-reset signal");
113 self.write_u8(BME280_REGISTER_SOFTRESET, BME280_COMMAND_SOFTRESET)
114 .await?;
115
116 debug!("Waiting 10 ms");
117 self.delay.delay_ms(10).await;
118
119 while self.status().await?.is_calibrating() {
120 debug!("Calibration not complete, waiting 10 ms");
121 self.delay.delay_ms(10).await;
122 }
123
124 debug!("Reading coefficients");
125 self.read_calibration_coefficients().await?;
126
127 debug!("Set sampling");
128 let configuration = Configuration::default();
129 self.set_sampling_configuration(configuration).await?;
130
131 debug!("Waiting 100 ms");
132 self.delay.delay_ms(100).await;
133
134 Ok(())
135 }
136
137 pub async fn chip_id(&mut self) -> Result<u8, I2C::Error> {
146 debug!("Read chip id");
147 let chip_id = self.read_u8(BME280_REGISTER_CHIPID).await?;
148
149 Ok(chip_id)
150 }
151
152 pub async fn status(&mut self) -> Result<Status, I2C::Error> {
158 debug!("Read chip status");
159 let status = self.read_u8(BME280_REGISTER_STATUS).await?.into();
160
161 Ok(status)
162 }
163
164 pub async fn set_sampling_configuration(
170 &mut self,
171 configuration: Configuration,
172 ) -> Result<(), I2C::Error> {
173 self.configuration = configuration;
174
175 let (config, ctrl_meas, ctrl_hum) = self.configuration.to_lowlevel_configuration();
176
177 self.write_u8(BME280_REGISTER_CONTROL, MODE_SLEEP).await?;
180
181 self.write_u8(BME280_REGISTER_CONTROLHUMID, ctrl_hum.into())
185 .await?;
186 self.write_u8(BME280_REGISTER_CONFIG, config.into()).await?;
187 self.write_u8(BME280_REGISTER_CONTROL, ctrl_meas.into())
188 .await?;
189
190 Ok(())
191 }
192
193 pub async fn take_forced_measurement(&mut self) -> Result<bool, I2C::Error> {
204 if self.configuration.is_forced() {
205 debug!("Forcing taking a measurement");
206
207 let (_config, ctrl_meas, _ctrl_hum) = self.configuration.to_lowlevel_configuration();
208 self.write_u8(BME280_REGISTER_CONTROL, ctrl_meas.into())
209 .await?;
210
211 for _ in 0..10 {
212 if !self.status().await?.is_measuring() {
213 break;
214 }
215
216 debug!("Measuring not complete, waiting 10 ms");
217 self.delay.delay_ms(10).await;
218 }
219
220 Ok(true)
221 } else {
222 Ok(false)
223 }
224 }
225
226 async fn read_raw_sample(&mut self) -> Result<RawSample, I2C::Error> {
231 let buffer: [u8; 1] = [BME280_REGISTER_PRESSUREDATA];
232 let mut buf: [u8; 8] = [0; 8];
233 self.i2c.write_read(self.address, &buffer, &mut buf).await?;
234
235 let adc_p: u32 =
239 (u32::from(buf[0]) << 12) | (u32::from(buf[1]) << 4) | (u32::from(buf[2]) >> 4);
240 let adc_t: u32 =
244 (u32::from(buf[3]) << 12) | (u32::from(buf[4]) << 4) | (u32::from(buf[5]) >> 4);
245 let adc_h: u16 = (u16::from(buf[6]) << 8) | u16::from(buf[7]);
248
249 Ok(RawSample {
250 adc_t: if adc_t == SKIPPED_TEMPERATURE_OUTPUT {
251 None
252 } else {
253 Some(adc_t)
254 },
255 adc_p: if adc_p == SKIPPED_PRESSURE_OUTPUT {
256 None
257 } else {
258 Some(adc_p)
259 },
260 adc_h: if adc_h == SKIPPED_HUMIDITY_OUTPUT {
261 None
262 } else {
263 Some(adc_h)
264 },
265 })
266 }
267
268 pub async fn read_sample(&mut self) -> Result<Sample, I2C::Error> {
277 let RawSample {
278 adc_t,
279 adc_p,
280 adc_h,
281 } = self.read_raw_sample().await?;
282
283 if let Some(adc_t) = adc_t {
284 let t_fine = self.coefficients.compensate_temperature(adc_t);
285 let t = Some(Self::temperature_fine_to_temperature(t_fine));
286 let p = adc_p.map(|adc_p| self.coefficients.compensate_pressure(adc_p, t_fine));
287 let h = adc_h.map(|adc_h| self.coefficients.compensate_humidity(adc_h, t_fine));
288
289 let temperature = t;
290
291 #[allow(clippy::cast_precision_loss)] let pressure = p.map(|p| p as f32 / 256.0);
293 let pressure = pressure.map(pressure_from_pascal);
294 #[allow(clippy::cast_precision_loss)] let humidity = h.map(|h| h as f32 / 1024.0);
296 let humidity = humidity.map(humidity_from_number);
297
298 Ok(Sample {
299 temperature,
300 pressure,
301 humidity,
302 })
303 } else {
304 warn!("Temperature measurement is disabled");
305
306 Ok(Sample::default())
307 }
308 }
309
310 fn temperature_fine_to_temperature(t_fine: i32) -> Temperature {
312 let t = (t_fine * 5 + 128) >> 8;
313
314 #[allow(clippy::cast_precision_loss)] let t = t as f32;
316
317 temperature_from_celsius(t / 100.0)
318 }
319
320 pub async fn read_temperature(&mut self) -> Result<Option<Temperature>, I2C::Error> {
328 if let Some(t_fine) = self.read_temperature_fine().await? {
329 Ok(Some(Self::temperature_fine_to_temperature(t_fine)))
330 } else {
331 Ok(None)
332 }
333 }
334
335 async fn read_temperature_fine(&mut self) -> Result<Option<i32>, I2C::Error> {
337 let adc_t = self.read_raw_temperature().await?;
338 let t_fine = adc_t.map(|adc_t| self.coefficients.compensate_temperature(adc_t));
339 Ok(t_fine)
340 }
341
342 async fn read_raw_temperature(&mut self) -> Result<Option<u32>, I2C::Error> {
347 let adc_t = self.read_u24(BME280_REGISTER_TEMPDATA).await?;
348
349 if adc_t == SKIPPED_TEMPERATURE_OUTPUT {
350 Ok(None)
351 } else {
352 Ok(Some(adc_t))
353 }
354 }
355
356 pub async fn read_pressure(&mut self) -> Result<Option<Pressure>, I2C::Error> {
367 if let Some(t_fine) = self.read_temperature_fine().await? {
368 self.read_pressure_with_temperature_fine(t_fine).await
369 } else {
370 warn!("Pressure measurement is disabled");
371 Ok(None)
372 }
373 }
374
375 pub async fn read_pressure_with_temperature(
387 &mut self,
388 temperature: f32,
389 ) -> Result<Option<Pressure>, I2C::Error> {
390 #[allow(clippy::cast_possible_truncation)] let t = (temperature * 100.0) as i32;
392 let t_fine = ((t << 8) - 128) / 5;
393 self.read_pressure_with_temperature_fine(t_fine).await
394 }
395
396 async fn read_pressure_with_temperature_fine(
398 &mut self,
399 t_fine: i32,
400 ) -> Result<Option<Pressure>, I2C::Error> {
401 let adc_p = self.read_raw_pressure().await?;
402 let p = adc_p.map(|adc_p| {
403 let p = self.coefficients.compensate_pressure(adc_p, t_fine);
404
405 #[allow(clippy::cast_precision_loss)] let p = p as f32;
407
408 pressure_from_pascal(p / 256.0)
409 });
410 Ok(p)
411 }
412
413 async fn read_raw_pressure(&mut self) -> Result<Option<u32>, I2C::Error> {
418 let adc_p = self.read_u24(BME280_REGISTER_PRESSUREDATA).await?;
419
420 if adc_p == SKIPPED_PRESSURE_OUTPUT {
421 Ok(None)
422 } else {
423 Ok(Some(adc_p))
424 }
425 }
426
427 pub async fn read_humidity(&mut self) -> Result<Option<Humidity>, I2C::Error> {
438 if let Some(t_fine) = self.read_temperature_fine().await? {
439 self.read_humidity_with_temperature_fine(t_fine).await
440 } else {
441 warn!("Humidity measurement is disabled");
442 Ok(None)
443 }
444 }
445
446 pub async fn read_humidity_with_temperature(
458 &mut self,
459 temperature: f32,
460 ) -> Result<Option<Humidity>, I2C::Error> {
461 #[allow(clippy::cast_possible_truncation)] let t = (temperature * 100.0) as i32;
463 let t_fine = ((t << 8) - 128) / 5;
464 self.read_humidity_with_temperature_fine(t_fine).await
465 }
466
467 async fn read_humidity_with_temperature_fine(
469 &mut self,
470 t_fine: i32,
471 ) -> Result<Option<Humidity>, I2C::Error> {
472 let adc_h = self.read_raw_humidity().await?;
473 let h = adc_h.map(|adc_h| {
474 let h = self.coefficients.compensate_humidity(adc_h, t_fine);
475
476 #[allow(clippy::cast_precision_loss)] let h = h as f32;
478
479 humidity_from_number(h / 1024.0)
480 });
481 Ok(h)
482 }
483
484 async fn read_raw_humidity(&mut self) -> Result<Option<u16>, I2C::Error> {
489 let adc_h = self.read_u16(BME280_REGISTER_HUMIDDATA).await?;
490
491 if adc_h == SKIPPED_HUMIDITY_OUTPUT {
492 Ok(None)
493 } else {
494 Ok(Some(adc_h))
495 }
496 }
497
498 async fn read_calibration_coefficients(&mut self) -> Result<(), I2C::Error> {
500 let buffer: [u8; 1] = [calibration::FIRST_REGISTER];
501
502 let mut out: [u8; calibration::TOTAL_LENGTH] = [0; calibration::TOTAL_LENGTH];
503 self.i2c
504 .write_read(
505 self.address,
506 &buffer,
507 &mut out[0..calibration::FIRST_LENGTH],
508 )
509 .await?;
510
511 let buffer: [u8; 1] = [calibration::SECOND_REGISTER];
512 self.i2c
513 .write_read(
514 self.address,
515 &buffer,
516 &mut out[calibration::FIRST_LENGTH..calibration::TOTAL_LENGTH],
517 )
518 .await?;
519
520 self.coefficients = (&out).into();
521
522 Ok(())
523 }
524
525 async fn write_u8(&mut self, register: u8, value: u8) -> Result<(), I2C::Error> {
527 let buffer: [u8; 2] = [register, value];
528 self.i2c.write(self.address, &buffer).await?;
529 Ok(())
530 }
531
532 async fn read_u8(&mut self, register: u8) -> Result<u8, I2C::Error> {
534 let buffer: [u8; 1] = [register];
535 let mut output_buffer: [u8; 1] = [0];
536 self.i2c
537 .write_read(self.address, &buffer, &mut output_buffer)
538 .await?;
539 Ok(output_buffer[0])
540 }
541
542 async fn read_u16(&mut self, register: u8) -> Result<u16, I2C::Error> {
544 let buffer: [u8; 1] = [register];
545 let mut output_buffer: [u8; 2] = [0, 0];
546 self.i2c
547 .write_read(self.address, &buffer, &mut output_buffer)
548 .await?;
549 Ok((u16::from(output_buffer[0]) << 8) | u16::from(output_buffer[1]))
550 }
551
552 async fn read_u24(&mut self, register: u8) -> Result<u32, I2C::Error> {
554 let buffer: [u8; 1] = [register];
555 let mut output_buffer: [u8; 3] = [0, 0, 0];
556 self.i2c
557 .write_read(self.address, &buffer, &mut output_buffer)
558 .await?;
559 Ok((u32::from(output_buffer[0]) << 12)
560 | (u32::from(output_buffer[1]) << 4)
561 | (u32::from(output_buffer[2]) >> 4))
562 }
563}
564
565#[cfg(test)]
566mod tests {
567 #![allow(clippy::panic_in_result_fn)]
568
569 use alloc::vec;
570
571 use embedded_hal::i2c::ErrorKind;
572
573 use embedded_hal_mock::eh1::delay::NoopDelay as DelayMock;
574 use embedded_hal_mock::eh1::i2c::Mock as I2cMock;
575 use embedded_hal_mock::eh1::i2c::Transaction as I2cTransaction;
576
577 use crate::calibration::TEST_CALIBRATION_DATA;
578 use crate::constants::CHIP_ID;
579
580 use super::*;
581
582 #[tokio::test]
583 async fn test_init() -> Result<(), ErrorKind> {
584 let expectations = [
585 I2cTransaction::write(
587 DEFAULT_ADDRESS,
588 vec![BME280_REGISTER_SOFTRESET, BME280_COMMAND_SOFTRESET],
589 ),
590 I2cTransaction::write_read(
592 DEFAULT_ADDRESS,
593 vec![BME280_REGISTER_STATUS],
594 vec![0b0000_0001],
595 ),
596 I2cTransaction::write_read(
598 DEFAULT_ADDRESS,
599 vec![BME280_REGISTER_STATUS],
600 vec![0b0000_0000],
601 ),
602 I2cTransaction::write_read(
604 DEFAULT_ADDRESS,
605 vec![calibration::FIRST_REGISTER],
606 vec![0; 26],
607 ),
608 I2cTransaction::write_read(
609 DEFAULT_ADDRESS,
610 vec![calibration::SECOND_REGISTER],
611 vec![0; 7],
612 ),
613 I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONTROL, MODE_SLEEP]),
615 I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONTROLHUMID, 0]),
616 I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONFIG, 0]),
617 I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONTROL, 0]),
618 ];
619 let i2c = I2cMock::new(&expectations);
620
621 let mut bme280 = Bme280::new(i2c, DelayMock);
622
623 bme280.init().await?;
624
625 bme280.release().done();
626
627 Ok(())
628 }
629
630 #[tokio::test]
631 async fn test_chip_id() -> Result<(), ErrorKind> {
632 let expectations = [I2cTransaction::write_read(
633 DEFAULT_ADDRESS,
634 vec![BME280_REGISTER_CHIPID],
635 vec![CHIP_ID],
636 )];
637 let i2c = I2cMock::new(&expectations);
638
639 let mut bme280 = Bme280::new(i2c, DelayMock);
640
641 let chip_id = bme280.chip_id().await?;
642
643 assert_eq!(chip_id, CHIP_ID);
644
645 bme280.release().done();
646 Ok(())
647 }
648
649 #[tokio::test]
650 async fn test_chip_status() -> Result<(), ErrorKind> {
651 let expectations = [I2cTransaction::write_read(
652 DEFAULT_ADDRESS,
653 vec![BME280_REGISTER_STATUS],
654 vec![0x00],
655 )];
656 let i2c = I2cMock::new(&expectations);
657
658 let mut bme280 = Bme280::new(i2c, DelayMock);
659
660 let status = bme280.status().await?;
661
662 assert!(!status.is_measuring());
663 assert!(!status.is_calibrating());
664
665 bme280.release().done();
666 Ok(())
667 }
668
669 #[tokio::test]
670 async fn test_chip_status_measuring() -> Result<(), ErrorKind> {
671 let expectations = [I2cTransaction::write_read(
672 DEFAULT_ADDRESS,
673 vec![BME280_REGISTER_STATUS],
674 vec![0b0000_0100],
675 )];
676 let i2c = I2cMock::new(&expectations);
677
678 let mut bme280 = Bme280::new(i2c, DelayMock);
679
680 let status = bme280.status().await?;
681
682 assert!(status.is_measuring());
683 assert!(!status.is_calibrating());
684
685 bme280.release().done();
686 Ok(())
687 }
688
689 #[tokio::test]
690 async fn test_read_temperature_disabled() -> Result<(), ErrorKind> {
691 let expectations = [I2cTransaction::write_read(
692 DEFAULT_ADDRESS,
693 vec![BME280_REGISTER_TEMPDATA],
694 vec![0x80, 0x00, 0x00],
695 )];
696 let i2c = I2cMock::new(&expectations);
697
698 let mut bme280 = Bme280::new_with_coefficients(
699 i2c,
700 DEFAULT_ADDRESS,
701 DelayMock,
702 TEST_CALIBRATION_DATA.clone(),
703 );
704
705 let expected = None;
706
707 let temperature = bme280.read_temperature().await?;
708
709 assert_eq!(temperature, expected);
710
711 bme280.release().done();
712 Ok(())
713 }
714
715 #[tokio::test]
716 async fn test_read_temperature() -> Result<(), ErrorKind> {
717 let expectations = [I2cTransaction::write_read(
718 DEFAULT_ADDRESS,
719 vec![BME280_REGISTER_TEMPDATA],
720 vec![0x84, 0x47, 0x00],
721 )];
722 let i2c = I2cMock::new(&expectations);
723
724 let mut bme280 = Bme280::new_with_coefficients(
725 i2c,
726 DEFAULT_ADDRESS,
727 DelayMock,
728 TEST_CALIBRATION_DATA.clone(),
729 );
730
731 let expected = Some(temperature_from_celsius(27.33));
732
733 let temperature = bme280.read_temperature().await?;
734
735 assert_eq!(temperature, expected);
736
737 bme280.release().done();
738 Ok(())
739 }
740
741 #[tokio::test]
742 async fn test_read_pressure_disabled() -> Result<(), ErrorKind> {
743 let expectations = [
744 I2cTransaction::write_read(
745 DEFAULT_ADDRESS,
746 vec![BME280_REGISTER_TEMPDATA],
747 vec![0x84, 0x47, 0x00],
748 ),
749 I2cTransaction::write_read(
750 DEFAULT_ADDRESS,
751 vec![BME280_REGISTER_PRESSUREDATA],
752 vec![0x80, 0x00, 0x00],
753 ),
754 ];
755 let i2c = I2cMock::new(&expectations);
756
757 let mut bme280 = Bme280::new_with_coefficients(
758 i2c,
759 DEFAULT_ADDRESS,
760 DelayMock,
761 TEST_CALIBRATION_DATA.clone(),
762 );
763
764 let expected = None;
765
766 let pressure = bme280.read_pressure().await?;
767
768 assert_eq!(pressure, expected);
769
770 bme280.release().done();
771 Ok(())
772 }
773
774 #[tokio::test]
775 async fn test_read_pressure() -> Result<(), ErrorKind> {
776 let expectations = [
777 I2cTransaction::write_read(
778 DEFAULT_ADDRESS,
779 vec![BME280_REGISTER_TEMPDATA],
780 vec![0x84, 0x47, 0x00],
781 ),
782 I2cTransaction::write_read(
783 DEFAULT_ADDRESS,
784 vec![BME280_REGISTER_PRESSUREDATA],
785 vec![0x4f, 0x50, 0x00],
786 ),
787 ];
788 let i2c = I2cMock::new(&expectations);
789
790 let mut bme280 = Bme280::new_with_coefficients(
791 i2c,
792 DEFAULT_ADDRESS,
793 DelayMock,
794 TEST_CALIBRATION_DATA.clone(),
795 );
796
797 let expected = Some(pressure_from_pascal(101_233.016));
798
799 let pressure = bme280.read_pressure().await?;
800
801 assert_eq!(pressure, expected);
802
803 bme280.release().done();
804 Ok(())
805 }
806
807 #[tokio::test]
808 async fn test_read_humidity_disabled() -> Result<(), ErrorKind> {
809 let expectations = [
810 I2cTransaction::write_read(
811 DEFAULT_ADDRESS,
812 vec![BME280_REGISTER_TEMPDATA],
813 vec![0x84, 0x47, 0x00],
814 ),
815 I2cTransaction::write_read(
816 DEFAULT_ADDRESS,
817 vec![BME280_REGISTER_HUMIDDATA],
818 vec![0x80, 0x00],
819 ),
820 ];
821 let i2c = I2cMock::new(&expectations);
822
823 let mut bme280 = Bme280::new_with_coefficients(
824 i2c,
825 DEFAULT_ADDRESS,
826 DelayMock,
827 TEST_CALIBRATION_DATA.clone(),
828 );
829
830 let expected = None;
831
832 let humidity = bme280.read_humidity().await?;
833
834 assert_eq!(humidity, expected);
835
836 bme280.release().done();
837 Ok(())
838 }
839
840 #[tokio::test]
841 async fn test_read_humidity() -> Result<(), ErrorKind> {
842 let expectations = [
843 I2cTransaction::write_read(
844 DEFAULT_ADDRESS,
845 vec![BME280_REGISTER_TEMPDATA],
846 vec![0x84, 0x47, 0x00],
847 ),
848 I2cTransaction::write_read(
849 DEFAULT_ADDRESS,
850 vec![BME280_REGISTER_HUMIDDATA],
851 vec![0x60, 0x02],
852 ),
853 ];
854 let i2c = I2cMock::new(&expectations);
855
856 let mut bme280 = Bme280::new_with_coefficients(
857 i2c,
858 DEFAULT_ADDRESS,
859 DelayMock,
860 TEST_CALIBRATION_DATA.clone(),
861 );
862
863 let expected = Some(humidity_from_number(34.854_492));
864
865 let humidity = bme280.read_humidity().await?;
866
867 assert_eq!(humidity, expected);
868
869 bme280.release().done();
870 Ok(())
871 }
872}