Skip to main content

bme280_rs/
blocking.rs

1// Copyright Claudio Mattera 2022-2026.
2//
3// Distributed under the MIT License or the Apache 2.0 License at your option.
4// See the accompanying files LICENSE-MIT.txt and LICENSE-APACHE-2.0.txt, or
5// online at
6// https://opensource.org/licenses/MIT
7// https://opensource.org/licenses/Apache-2.0
8
9//! Data types and functions for BME280 sensor interface
10
11use 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
44/// Interface to BME280 sensor over I²C
45///
46/// ```no_run
47/// # use embedded_hal_mock::eh1::delay::NoopDelay as DelayMock;
48/// # use embedded_hal_mock::eh1::i2c::Mock as I2cMock;
49/// # use embedded_hal::i2c::ErrorKind;
50/// use bme280_rs::{Bme280, Configuration, Oversampling, SensorMode};
51/// # let i2c = I2cMock::new(&[]);
52/// # let delay = DelayMock;
53///
54/// let mut bme280 = Bme280::new(i2c, delay);
55///
56/// bme280.init()?;
57///
58/// let configuration = Configuration::default()
59///     .with_temperature_oversampling(Oversampling::Oversample1)
60///     .with_pressure_oversampling(Oversampling::Oversample1)
61///     .with_humidity_oversampling(Oversampling::Oversample1)
62///     .with_sensor_mode(SensorMode::Normal);
63/// bme280.set_sampling_configuration(configuration)?;
64///
65/// if let Some(temperature) = bme280.read_temperature()? {
66///     println!("Temperature: {:?}", temperature);
67/// } else {
68///     println!("Temperature reading was disabled");
69/// }
70/// # Ok::<(), ErrorKind>(())
71/// ```
72pub struct Bme280<I2c, Delay> {
73    /// I²C device
74    i2c: I2c,
75
76    /// I²C address
77    address: u8,
78
79    /// Delay function
80    delay: Delay,
81
82    /// Calibration coefficients
83    coefficients: CalibrationData,
84
85    /// Sensor configuration
86    configuration: Configuration,
87}
88
89impl<I2C, D> Bme280<I2C, D>
90where
91    I2C: I2c,
92    D: DelayNs,
93{
94    /// Create a new sensor using an I²C interface and a delay function using
95    /// the sensor's default address [`DEFAULT_ADDRESS`])
96    pub fn new(i2c: I2C, delay: D) -> Self {
97        Self::new_with_address(i2c, DEFAULT_ADDRESS, delay)
98    }
99
100    /// Release the I²C interface
101    pub fn release(self) -> I2C {
102        self.i2c
103    }
104
105    /// Create a new sensor using an I²C interface and a delay function
106    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    /// Create a new sensor with specific calibration coefficients
111    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    /// Initialize the sensor
128    ///
129    /// Send a soft-reset signal, obtain the calibration coefficients, and set
130    /// default sampling configuration.
131    ///
132    /// Note that the default sampling configuration disables measurement of
133    /// temperature, pressure and humidity.
134    ///
135    /// # Errors
136    ///
137    /// Return an error if it cannot communicate with the sensor.
138    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    /// Obtain the chip id
164    ///
165    /// The chip id is always [`crate::constants::CHIP_ID`], so this function
166    /// can be used to validate that communication with the chip works fine.
167    ///
168    /// # Errors
169    ///
170    /// Return an error if it cannot communicate with the sensor.
171    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    /// Obtain the chip status
179    ///
180    /// # Errors
181    ///
182    /// Return an error if it cannot communicate with the sensor.
183    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    /// Set the sampling configuration
191    ///
192    /// # Errors
193    ///
194    /// Return an error if it cannot communicate with the sensor.
195    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        // making sure sensor is in sleep mode before setting configuration
204        // as it otherwise may be ignored
205        self.write_u8(BME280_REGISTER_CONTROL, MODE_SLEEP)?;
206
207        // you must make sure to also set REGISTER_CONTROL after setting the
208        // CONTROLHUMID register, otherwise the values won't be applied (see
209        // DS 5.4.3)
210        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    /// Take a forced measurement
218    ///
219    /// When the chip is set to work in forced mode, it goes back to sleep
220    /// after every measurement.
221    /// It must be set again to forced mode in order to force a new
222    /// measurement.
223    ///
224    /// # Errors
225    ///
226    /// Return an error if it cannot communicate with the sensor.
227    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    /// Read a raw sample from sensor
250    ///
251    /// Raw sample must be converted to human-readable quantities using
252    /// compensation formulas from the data sheet.
253    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        // msb [7:0] = p[19:12]
259        // lsb [7:0] = p[11:4]
260        // xlsb[7:4] = p[3:0]
261        let adc_p: u32 =
262            (u32::from(buf[0]) << 12) | (u32::from(buf[1]) << 4) | (u32::from(buf[2]) >> 4);
263        // msb [7:0] = t[19:12]
264        // lsb [7:0] = t[11:4]
265        // xlsb[7:4] = t[3:0]
266        let adc_t: u32 =
267            (u32::from(buf[3]) << 12) | (u32::from(buf[4]) << 4) | (u32::from(buf[5]) >> 4);
268        // msb [7:0] = h[15:8]
269        // lsb [7:0] = h[7:0]
270        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    /// Read a sample of temperature, pressure and humidity
292    ///
293    /// Measures that are disabled in the sampling configuration have value
294    /// `None`.
295    ///
296    /// # Errors
297    ///
298    /// Return an error if it cannot communicate with the sensor.
299    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)] // Acceptable precision loss
315            let pressure = p.map(|p| p as f32 / 256.0);
316            let pressure = pressure.map(pressure_from_pascal);
317            #[allow(clippy::cast_precision_loss)] // Acceptable precision loss
318            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    /// Compute raw temperature from human-readable temperature
334    fn temperature_fine_to_temperature(t_fine: i32) -> Temperature {
335        let t = (t_fine * 5 + 128) >> 8;
336
337        #[allow(clippy::cast_precision_loss)] // Acceptable precision loss
338        let t = t as f32;
339
340        temperature_from_celsius(t / 100.0)
341    }
342
343    /// Read a sample of temperature
344    ///
345    /// If temperature is disabled in the sampling configuration, return `None`.
346    ///
347    /// # Errors
348    ///
349    /// Return an error if it cannot communicate with the sensor.
350    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    /// Read temperature from sensor
359    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    /// Read raw temperature from sensor
366    ///
367    /// Raw temperature must be converted to human-readable temperature using
368    /// compensation formulas from the data sheet.
369    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    /// Read a sample of pressure
380    ///
381    /// The temperature value, necessary to compute the compensated pressure
382    /// value, is also read from the sensor.
383    ///
384    /// If pressure is disabled in the sampling configuration, return `None`.
385    ///
386    /// # Errors
387    ///
388    /// Return an error if it cannot communicate with the sensor.
389    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    /// Read a sample of pressure with a user-specified temperature value
399    ///
400    /// Unlike in [`Self::read_pressure()`], this function does not take the
401    /// temperature from the sensor, so it can be used if the temperature
402    /// is already known.
403    ///
404    /// If pressure is disabled in the sampling configuration, return `None`.
405    ///
406    /// # Errors
407    ///
408    /// Return an error if it cannot communicate with the sensor.
409    pub fn read_pressure_with_temperature(
410        &mut self,
411        temperature: f32,
412    ) -> Result<Option<Pressure>, I2C::Error> {
413        #[allow(clippy::cast_possible_truncation)] // Acceptable truncation
414        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    /// Read pressure from sensor using specific temperature reference
420    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)] // Acceptable precision loss
429            let p = p as f32;
430
431            pressure_from_pascal(p / 256.0)
432        });
433        Ok(p)
434    }
435
436    /// Read raw pressure from sensor
437    ///
438    /// Raw pressure must be converted to human-readable pressure using
439    /// compensation formulas from the data sheet.
440    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    /// Read a sample of humidity
451    ///
452    /// The temperature value, necessary to compute the compensated pressure
453    /// value, is also read from the sensor.
454    ///
455    /// If humidity is disabled in the sampling configuration, return `None`.
456    ///
457    /// # Errors
458    ///
459    /// Return an error if it cannot communicate with the sensor.
460    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    /// Read a sample of humidity with a user-specified temperature value
470    ///
471    /// Unlike in [`Self::read_humidity()`], this function does not take the
472    /// temperature from the sensor, so it can be used if the temperature
473    /// is already known.
474    ///
475    /// If humidity is disabled in the sampling configuration, return `None`.
476    ///
477    /// # Errors
478    ///
479    /// Return an error if it cannot communicate with the sensor.
480    pub fn read_humidity_with_temperature(
481        &mut self,
482        temperature: f32,
483    ) -> Result<Option<Humidity>, I2C::Error> {
484        #[allow(clippy::cast_possible_truncation)] // Acceptable truncation
485        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    /// Read humidity from sensor using specific reference temperature
491    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)] // Acceptable precision loss
500            let h = h as f32;
501
502            humidity_from_number(h / 1024.0)
503        });
504        Ok(h)
505    }
506
507    /// Read raw humidity from sensor
508    ///
509    /// Raw humidity must be converted to human-readable humidity using
510    /// compensation formulas from the data sheet.
511    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    /// Read calibration coefficients from sensor
522    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    /// Write an unsigned byte to an I²C register
545    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    /// Write an unsigned byte from an I²C register
552    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    /// Write two unsigned bytes to an I²C register
561    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    /// Write three unsigned bytes to an I²C register
570    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            // Reset sensor
602            I2cTransaction::write(
603                DEFAULT_ADDRESS,
604                vec![BME280_REGISTER_SOFTRESET, BME280_COMMAND_SOFTRESET],
605            ),
606            // Wait for calibration
607            I2cTransaction::write_read(
608                DEFAULT_ADDRESS,
609                vec![BME280_REGISTER_STATUS],
610                vec![0b0000_0001],
611            ),
612            // Wait for calibration
613            I2cTransaction::write_read(
614                DEFAULT_ADDRESS,
615                vec![BME280_REGISTER_STATUS],
616                vec![0b0000_0000],
617            ),
618            // Read coefficients
619            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            // Configure sensor
630            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}