1#![doc = include_str!("../README.md")]
2#![deny(unsafe_code, missing_docs)]
3#![no_std]
4
5#[allow(unused_imports)]
6use micromath::F32Ext;
7
8#[cfg(not(feature = "async"))]
9use embedded_hal as hal;
10#[cfg(feature = "async")]
11use embedded_hal_async as hal;
12
13use hal::i2c::{Operation, SevenBitAddress};
14
15pub use weather_utils::Temperature;
16use weather_utils::{BarometricPressure, Celsius, TemperatureAndBarometricPressure};
17
18pub const I2C_ADDRESS_LOGIC_LOW: SevenBitAddress = 0x70;
20pub const I2C_ADDRESS_LOGIC_HIGH: SevenBitAddress = 0x56;
22pub const DEFAULT_I2C_ADDRESS: SevenBitAddress = I2C_ADDRESS_LOGIC_LOW;
24
25const CHIP_ID_REGISTER: u8 = 0xd1;
26const COE_B00_1_REGISTER: u8 = 0xa0;
27const CTRL_MEAS_REGISTER: u8 = 0xf4;
28const IIR_CNT_REGISTER: u8 = 0xf1;
29const PRESS_TXD2: u8 = 0xf7;
30const RESET_REGISTER: u8 = 0xe0;
31
32#[derive(Debug)]
34pub enum Error<I2cE>
35where
36 I2cE: hal::i2c::Error,
37{
38 I2c(I2cE),
40 ChipNotDetected,
42 BadCrc,
44}
45
46impl<I2cE> From<I2cE> for Error<I2cE>
47where
48 I2cE: hal::i2c::Error,
49{
50 fn from(value: I2cE) -> Self {
51 Error::I2c(value)
52 }
53}
54
55#[derive(Clone, Copy, Debug, Default)]
60#[repr(u8)]
61pub enum IirFilter {
62 Off = 0x00,
64 Coeff2 = 0x01,
66 #[default]
68 Coeff4 = 0x02,
69 Coeff8 = 0x03,
71 Coeff16 = 0x04,
73 Coeff32 = 0x05,
75}
76
77#[derive(Clone, Copy, Debug, Default)]
83#[repr(u8)]
84pub enum OverSamplingSetting {
85 HighSpeed,
88 LowPower,
91 #[default]
95 Standard,
96 HighAccuracy,
99 UltraHighAccuracy,
102}
103
104#[derive(Clone, Copy, Debug, Default)]
105#[repr(u8)]
106enum PowerMode {
107 #[default]
108 Sleep = 0x00,
109 Forced = 0x01,
110 #[allow(dead_code)]
111 Normal = 0x03,
112}
113
114#[derive(Clone, Copy, Debug, Default)]
115#[repr(u8)]
116enum OverSampling {
117 #[default]
119 X1 = 0x01,
120 X2 = 0x02,
121 X4 = 0x03,
122 X8 = 0x04,
123 X16 = 0x05,
124 X32 = 0x06,
125 }
127
128#[derive(Debug, Default)]
129struct Coe {
130 a0: i32,
131 a1: i16,
132 a2: i16,
133 b00: i32,
134 bt1: i16,
135 bt2: i16,
136 bp1: i16,
137 b11: i16,
138 bp2: i16,
139 b12: i16,
140 b21: i16,
141 bp3: i16,
142}
143
144impl From<&[u8; 25]> for Coe {
145 fn from(value: &[u8; 25]) -> Self {
146 Coe {
147 a0: ((((value[18] as u32) << 12 | (value[19] as u32) << 4 | (value[24] as u32) & 0x0f)
148 << 12) as i32)
149 >> 12,
150 a1: ((value[20] as u16) << 8 | (value[21] as u16)) as i16,
151 a2: ((value[22] as u16) << 8 | (value[23] as u16)) as i16,
152 b00: ((((value[0] as u32) << 12
153 | (value[1] as u32) << 4
154 | ((value[24] as u32) & 0xf0) >> 4)
155 << 12) as i32)
156 >> 12,
157 bt1: ((value[2] as u16) << 8 | (value[3] as u16)) as i16,
158 bt2: ((value[4] as u16) << 8 | (value[5] as u16)) as i16,
159 bp1: ((value[6] as u16) << 8 | (value[7] as u16)) as i16,
160 b11: ((value[8] as u16) << 8 | (value[9] as u16)) as i16,
161 bp2: ((value[10] as u16) << 8 | (value[11] as u16)) as i16,
162 b12: ((value[12] as u16) << 8 | (value[13] as u16)) as i16,
163 b21: ((value[14] as u16) << 8 | (value[15] as u16)) as i16,
164 bp3: ((value[16] as u16) << 8 | (value[17] as u16)) as i16,
165 }
166 }
167}
168
169#[derive(Debug, Default)]
170struct K {
171 a0: f32,
172 a1: f32,
173 a2: f32,
174 b00: f32,
175 bt1: f32,
176 bt2: f32,
177 bp1: f32,
178 b11: f32,
179 bp2: f32,
180 b12: f32,
181 b21: f32,
182 bp3: f32,
183}
184
185impl From<&Coe> for K {
186 fn from(value: &Coe) -> Self {
187 K {
188 a0: value.a0 as f32 / 16.0,
189 a1: -6.30E-03 + ((4.30E-04 * value.a1 as f32) / 32_767.0),
190 a2: -1.90E-11 + ((1.20E-10 * value.a2 as f32) / 32_767.0),
191 b00: value.b00 as f32 / 16.0,
192 bt1: 1.00E-01 + ((9.10E-02 * value.bt1 as f32) / 32_767.0),
193 bt2: 1.20E-08 + ((1.20E-06 * value.bt2 as f32) / 32_767.0),
194 bp1: 3.30E-02 + ((1.90E-02 * value.bp1 as f32) / 32_767.0),
195 b11: 2.10E-07 + ((1.40E-07 * value.b11 as f32) / 32_767.0),
196 bp2: -6.30E-10 + ((3.50E-10 * value.bp2 as f32) / 32_767.0),
197 b12: 2.90E-13 + ((7.60E-13 * value.b12 as f32) / 32_767.0),
198 b21: 2.10E-15 + ((1.20E-14 * value.b21 as f32) / 32_767.0),
199 bp3: 1.30E-16 + ((7.90E-17 * value.bp3 as f32) / 32_767.0),
200 }
201 }
202}
203
204#[derive(Debug)]
206pub struct Qmp6988<I2C, D> {
207 address: SevenBitAddress,
208 coe: Coe,
209 delay: D,
210 filter: IirFilter,
211 i2c: I2C,
212 k: K,
213 oversampling_setting: OverSamplingSetting,
214}
215
216impl<I2C, D> Qmp6988<I2C, D>
217where
218 I2C: hal::i2c::I2c,
219 D: hal::delay::DelayNs,
220{
221 #[maybe_async_cfg::maybe(
227 sync(not(feature = "async"), keep_self),
228 async(feature = "async", keep_self)
229 )]
230 pub async fn measure(
231 &mut self,
232 ) -> Result<TemperatureAndBarometricPressure<Celsius>, Error<I2C::Error>> {
233 self.apply_power_mode(PowerMode::Forced).await?;
234 self.delay.delay_ms(self.get_measurement_duration()).await;
235 let mut data = [0u8; 6];
236 let mut operations = [Operation::Write(&[PRESS_TXD2]), Operation::Read(&mut data)];
237 self.i2c.transaction(self.address, &mut operations).await?;
238 let dp: &[u8; 3] = &data[0..3].try_into().unwrap();
239 let dt: &[u8; 3] = &data[3..6].try_into().unwrap();
240 let dp = Self::get_i32_value(dp) - 8_388_608;
241 let dt = Self::get_i32_value(dt) - 8_388_608;
242 let temperature = self.compensate_temperature(dt);
243 let pressure = self.compensate_pressure(dp, temperature);
244 Ok(TemperatureAndBarometricPressure {
245 temperature: Celsius(temperature / 256.0),
246 barometric_pressure: BarometricPressure(pressure / 100.0),
247 })
248 }
249
250 #[maybe_async_cfg::maybe(
252 sync(not(feature = "async"), keep_self),
253 async(feature = "async", keep_self)
254 )]
255 pub async fn new(
256 i2c: I2C,
257 address: SevenBitAddress,
258 delay: D,
259 ) -> Result<Self, Error<I2C::Error>> {
260 let mut device = Self {
261 address,
262 coe: Coe::default(),
263 delay,
264 filter: IirFilter::default(),
265 i2c,
266 k: K::default(),
267 oversampling_setting: OverSamplingSetting::default(),
268 };
269 device.check_device().await?;
270 device.get_calibration_data().await?;
271 device.apply_filter().await?;
272 device.apply_measure_control_parameters().await?;
273 Ok(device)
274 }
275
276 #[maybe_async_cfg::maybe(
278 sync(not(feature = "async"), keep_self),
279 async(feature = "async", keep_self)
280 )]
281 pub async fn reset(&mut self) -> Result<(), Error<I2C::Error>> {
282 self.i2c.write(self.address, &[RESET_REGISTER]).await?;
283 self.delay.delay_ms(10).await;
284 Ok(())
285 }
286
287 #[maybe_async_cfg::maybe(
290 sync(not(feature = "async"), keep_self),
291 async(feature = "async", keep_self)
292 )]
293 pub async fn set_filter(&mut self, filter: IirFilter) -> Result<(), Error<I2C::Error>> {
294 self.filter = filter;
295 self.apply_filter().await
296 }
297
298 #[maybe_async_cfg::maybe(
300 sync(not(feature = "async"), keep_self),
301 async(feature = "async", keep_self)
302 )]
303 pub async fn set_oversampling_setting(
304 &mut self,
305 oversampling_setting: OverSamplingSetting,
306 ) -> Result<(), Error<I2C::Error>> {
307 self.oversampling_setting = oversampling_setting;
308 self.apply_measure_control_parameters().await
309 }
310
311 #[maybe_async_cfg::maybe(
312 sync(not(feature = "async"), keep_self),
313 async(feature = "async", keep_self)
314 )]
315 async fn apply_filter(&mut self) -> Result<(), Error<I2C::Error>> {
316 let data = [IIR_CNT_REGISTER, self.filter as u8];
317 self.i2c.write(self.address, &data).await?;
318 self.delay.delay_ms(20).await;
319 Ok(())
320 }
321
322 #[maybe_async_cfg::maybe(
323 sync(not(feature = "async"), keep_self),
324 async(feature = "async", keep_self)
325 )]
326 async fn apply_measure_control_parameters(&mut self) -> Result<(), Error<I2C::Error>> {
327 let (pressure_oversampling, temperature_oversampling) = self.get_oversamplings();
328 let data = [
329 CTRL_MEAS_REGISTER,
330 (temperature_oversampling as u8) << 5
331 | (pressure_oversampling as u8) << 2
332 | (PowerMode::Sleep as u8),
333 ];
334 self.i2c.write(self.address, &data).await?;
335 self.delay.delay_ms(20).await;
336 Ok(())
337 }
338
339 #[maybe_async_cfg::maybe(
340 sync(not(feature = "async"), keep_self),
341 async(feature = "async", keep_self)
342 )]
343 async fn apply_power_mode(&mut self, power_mode: PowerMode) -> Result<(), Error<I2C::Error>> {
344 let mut data = [0u8; 1];
345 let mut operations = [
346 Operation::Write(&[CTRL_MEAS_REGISTER]),
347 Operation::Read(&mut data),
348 ];
349 self.i2c.transaction(self.address, &mut operations).await?;
350 let data = [CTRL_MEAS_REGISTER, (data[0] & 0xfc) | power_mode as u8];
351 self.i2c.write(self.address, &data).await?;
352 self.delay.delay_ms(20).await;
353 Ok(())
354 }
355
356 #[maybe_async_cfg::maybe(
357 sync(not(feature = "async"), keep_self),
358 async(feature = "async", keep_self)
359 )]
360 async fn check_device(&mut self) -> Result<(), Error<I2C::Error>> {
361 let mut chip_id = [0u8; 1];
362 let mut operations = [
363 Operation::Write(&[CHIP_ID_REGISTER]),
364 Operation::Read(&mut chip_id),
365 ];
366 self.i2c.transaction(self.address, &mut operations).await?;
367 if chip_id[0] == 0x5c {
368 Ok(())
369 } else {
370 Err(Error::ChipNotDetected)
371 }
372 }
373
374 fn compensate_pressure(&self, dp: i32, temperature: f32) -> f32 {
375 let dp = dp as f32;
376 self.k.b00
377 + self.k.bt1 * temperature
378 + self.k.bp1 * dp
379 + self.k.b11 * temperature * dp
380 + self.k.bt2 * temperature.powf(2.0)
381 + self.k.bp2 * dp.powf(2.0)
382 + self.k.b12 * dp * temperature.powf(2.0)
383 + self.k.b21 * dp.powf(2.0) * temperature
384 + self.k.bp3 * dp.powf(3.0)
385 }
386
387 fn compensate_temperature(&self, dt: i32) -> f32 {
388 let dt = dt as f32;
389 self.k.a0 + self.k.a1 * dt + self.k.a2 * dt.powf(2.0)
390 }
391
392 #[maybe_async_cfg::maybe(
393 sync(not(feature = "async"), keep_self),
394 async(feature = "async", keep_self)
395 )]
396 async fn get_calibration_data(&mut self) -> Result<(), Error<I2C::Error>> {
397 let mut coe = [0u8; 25];
398 let mut operations = [
399 Operation::Write(&[COE_B00_1_REGISTER]),
400 Operation::Read(&mut coe),
401 ];
402 self.i2c.transaction(self.address, &mut operations).await?;
403 self.coe = (&coe).into();
404 self.k = (&self.coe).into();
405 Ok(())
406 }
407
408 fn get_measurement_duration(&self) -> u32 {
409 match self.oversampling_setting {
410 OverSamplingSetting::HighSpeed => 6,
411 OverSamplingSetting::LowPower => 8,
412 OverSamplingSetting::Standard => 11,
413 OverSamplingSetting::HighAccuracy => 19,
414 OverSamplingSetting::UltraHighAccuracy => 34,
415 }
416 }
417
418 fn get_oversamplings(&self) -> (OverSampling, OverSampling) {
419 match self.oversampling_setting {
420 OverSamplingSetting::HighSpeed => (OverSampling::X2, OverSampling::X1),
421 OverSamplingSetting::LowPower => (OverSampling::X4, OverSampling::X1),
422 OverSamplingSetting::Standard => (OverSampling::X8, OverSampling::X1),
423 OverSamplingSetting::HighAccuracy => (OverSampling::X16, OverSampling::X2),
424 OverSamplingSetting::UltraHighAccuracy => (OverSampling::X32, OverSampling::X4),
425 }
426 }
427
428 #[inline]
429 fn get_i32_value(data: &[u8; 3]) -> i32 {
430 ((data[0] as u32) << 16 | (data[1] as u32) << 8 | (data[2] as u32)) as i32
431 }
432}
433
434#[cfg(test)]
435mod tests {
436 use embedded_hal::i2c::ErrorKind;
437 use embedded_hal_mock::eh1::delay::StdSleep as Delay;
438 use embedded_hal_mock::eh1::i2c::{Mock as I2cMock, Transaction as I2cTransaction};
439 use rstest::rstest;
440
441 use weather_utils::Altitude;
442
443 use crate::*;
444
445 fn create_device() -> Qmp6988<I2cMock, Delay> {
446 let expectations = [
447 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
448 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [CHIP_ID_REGISTER].to_vec()),
449 I2cTransaction::read(DEFAULT_I2C_ADDRESS, [0x5c].to_vec()),
450 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
451 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
452 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [COE_B00_1_REGISTER].to_vec()),
453 I2cTransaction::read(
454 DEFAULT_I2C_ADDRESS,
455 [
456 0x48, 0xE3, 0xF7, 0xD5, 0x04, 0x50, 0xFD, 0x02, 0xF3, 0xCB, 0x0A, 0x5D, 0x1F,
457 0x8C, 0x09, 0x13, 0xF9, 0xB6, 0xF7, 0x68, 0xD1, 0x62, 0xEB, 0xF2, 0x4E,
458 ]
459 .to_vec(),
460 ),
461 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
462 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [IIR_CNT_REGISTER, 0x02].to_vec()),
463 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [CTRL_MEAS_REGISTER, 0x30].to_vec()),
464 ];
465 let i2c = I2cMock::new(&expectations);
466 let mut device = Qmp6988::new(i2c, DEFAULT_I2C_ADDRESS, Delay {}).unwrap();
467 device.i2c.done();
468 device
469 }
470
471 #[test]
472 fn chip_not_detected() {
473 let expectations = [
474 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
475 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [CHIP_ID_REGISTER].to_vec()),
476 I2cTransaction::read(DEFAULT_I2C_ADDRESS, [0x2a].to_vec()),
477 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
478 ];
479 let mut i2c = I2cMock::new(&expectations);
480 assert!(matches!(
481 Qmp6988::new(i2c.by_ref(), DEFAULT_I2C_ADDRESS, Delay {}),
482 Err(Error::ChipNotDetected)
483 ));
484 i2c.done();
485 }
486
487 #[test]
488 fn measure() {
489 let expectations = [
490 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
491 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [CTRL_MEAS_REGISTER].to_vec()),
492 I2cTransaction::read(DEFAULT_I2C_ADDRESS, [0x30].to_vec()),
493 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
494 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [CTRL_MEAS_REGISTER, 0x31].to_vec()),
495 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
496 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [PRESS_TXD2].to_vec()),
497 I2cTransaction::read(
498 DEFAULT_I2C_ADDRESS,
499 [0xA4, 0x92, 0xF1, 0x6E, 0x0D, 0x98].to_vec(),
500 ),
501 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
502 ];
503 let mut device = create_device();
504 device.i2c.update_expectations(&expectations);
505 let measure = device.measure();
506 assert!(matches!(measure, Ok(_)));
507 let measure = measure.unwrap();
508 assert_eq!(
509 measure,
510 TemperatureAndBarometricPressure {
511 temperature: Celsius(20.87),
512 barometric_pressure: BarometricPressure(981.19),
513 }
514 );
515 assert_eq!(measure.altitude(), Altitude(277.31));
516 device.i2c.done();
517 }
518
519 #[test]
520 fn reset() {
521 let expectations = [I2cTransaction::write(
522 DEFAULT_I2C_ADDRESS,
523 [RESET_REGISTER].to_vec(),
524 )];
525 let mut device = create_device();
526 device.i2c.update_expectations(&expectations);
527 assert!(matches!(device.reset(), Ok(())));
528 device.i2c.done();
529 }
530
531 #[test]
532 fn reset_with_arbitration_loss_error() {
533 let expectations = [
534 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [RESET_REGISTER].to_vec())
535 .with_error(ErrorKind::ArbitrationLoss),
536 ];
537 let mut device = create_device();
538 device.i2c.update_expectations(&expectations);
539 assert!(matches!(device.reset(), Err(Error::I2c(_))));
540 device.i2c.done();
541 }
542
543 #[test]
544 fn set_filter() {
545 let expectations = [I2cTransaction::write(
546 DEFAULT_I2C_ADDRESS,
547 [IIR_CNT_REGISTER, 0x05].to_vec(),
548 )];
549 let mut device = create_device();
550 device.i2c.update_expectations(&expectations);
551 assert!(matches!(device.set_filter(IirFilter::Coeff32), Ok(())));
552 device.i2c.done();
553 }
554
555 #[rstest]
556 #[case(OverSamplingSetting::HighSpeed, 0x28, 6)]
557 #[case(OverSamplingSetting::LowPower, 0x2C, 8)]
558 #[case(OverSamplingSetting::Standard, 0x30, 11)]
559 #[case(OverSamplingSetting::HighAccuracy, 0x54, 19)]
560 #[case(OverSamplingSetting::UltraHighAccuracy, 0x78, 34)]
561 fn set_oversampling_setting(
562 #[case] oversampling_setting: OverSamplingSetting,
563 #[case] expected_ctrl_meas_value: u8,
564 #[case] expected_measurement_duration: u32,
565 ) {
566 let expectations = [I2cTransaction::write(
567 DEFAULT_I2C_ADDRESS,
568 [CTRL_MEAS_REGISTER, expected_ctrl_meas_value].to_vec(),
569 )];
570 let mut device = create_device();
571 device.i2c.update_expectations(&expectations);
572 assert!(matches!(
573 device.set_oversampling_setting(oversampling_setting),
574 Ok(())
575 ));
576 assert_eq!(
577 device.get_measurement_duration(),
578 expected_measurement_duration
579 );
580 device.i2c.done();
581 }
582}