1#![forbid(unsafe_code)]
43#![warn(missing_docs)]
44#![warn(missing_debug_implementations)]
45#![cfg_attr(not(any(test, doctest)), no_std)]
46
47extern crate embedded_hal as hal;
48extern crate libm;
49
50use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
51
52const ADDR: u8 = 0x76;
53const PRS: u8 = 0x00;
54const TMP: u8 = 0x03;
55const PRS_CFG: u8 = 0x06;
56const TMP_CFG: u8 = 0x07;
57const MEAS_CFG: u8 = 0x08;
58const CFG_REG: u8 = 0x09;
59const RESET: u8 = 0x0C;
62const ID: u8 = 0x0D;
63const COEF: u8 = 0x10;
64
65#[derive(Clone, Copy, PartialEq, Eq, Debug)]
77pub enum Mode {
78 Standby = 0b000,
81 Pressure = 0b001,
83 Temperature = 0b010,
85 ContinuousPressure = 0b101,
89 ContinuousTemperature = 0b110,
91 ContinuousPressureTemperature = 0b111,
93}
94
95#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
102pub enum SampleRate {
103 One = 0b000,
105 Two = 0b001,
108 Four = 0b010,
110 Eight = 0b011,
113 Sixteen = 0b100,
116 ThirtyTwo = 0b101,
118 SixtyFour = 0b110,
121 OneTwentyEight = 0b111,
124}
125
126#[derive(Debug)]
136pub struct Barometer<'a, I2C>
137where
138 I2C: Read + Write + WriteRead,
139{
140 i2c: &'a mut I2C,
141 calibration_data: CalibrationData,
142 temperature_oversample: SampleRate,
143 pressure_oversample: SampleRate,
144 mode: Mode,
145}
146
147impl<'a, I2C, E> Barometer<'a, I2C>
148where
149 I2C: Read<Error = E> + Write<Error = E> + WriteRead<Error = E>,
150{
151 pub fn new(i2c: &'a mut I2C) -> Result<Self, E> {
162 let mut barometer = Barometer {
163 i2c,
164 calibration_data: CalibrationData::default(),
165 temperature_oversample: SampleRate::Eight,
166 pressure_oversample: SampleRate::Eight,
167 mode: Mode::Standby,
168 };
169 while (barometer.read8(MEAS_CFG)? >> 7) != 1 {}
170 barometer.calibration_data = barometer.get_calibration_data()?;
171 barometer.init()?;
172 Ok(barometer)
173 }
174
175 fn init(&mut self) -> Result<(), E> {
176 self.set_pressure_config(SampleRate::One, SampleRate::Eight)?;
177 self.set_temperature_config(SampleRate::One, SampleRate::Eight)?;
178 self.set_mode(Mode::ContinuousPressureTemperature)?;
179 self.write(&[CFG_REG, 0x00])?; Ok(())
181 }
182
183 pub fn sensor_id(&mut self) -> Result<u8, E> {
186 self.read8(ID)
187 }
188
189 pub fn get_temperature(&mut self) -> Result<f32, E> {
196 if self.mode == Mode::Standby || self.mode == Mode::ContinuousPressure {
197 while !self.new_data_is_available()?.0 {
198 self.set_mode(Mode::Temperature)?
199 }
200 }
201 let cal = self.calibration_data;
202 Ok(cal.c0 as f32 / 2.0 + cal.c1 as f32 * self.traw_sc()?)
203 }
204
205 pub fn get_pressure(&mut self) -> Result<f32, E> {
212 if self.mode == Mode::Standby {
213 self.get_temperature()?;
214 }
215 if self.mode == Mode::Standby || self.mode == Mode::ContinuousTemperature {
216 while !self.new_data_is_available()?.1 {
217 self.set_mode(Mode::Pressure)?
218 }
219 }
220
221 let cal = self.calibration_data;
222 let traw_sc = self.traw_sc()?;
223 let praw_sc = self.praw_sc()?;
224
225 let pcomp = cal.c00 as f32
226 + praw_sc * (cal.c10 as f32 + praw_sc * (cal.c20 as f32 + praw_sc * cal.c30 as f32))
227 + traw_sc * cal.c01 as f32
228 + traw_sc * praw_sc * (cal.c11 as f32 + praw_sc * cal.c21 as f32);
229 Ok(pcomp / 100.0)
230 }
231
232 pub fn altitude(&mut self, sea_level_hpa: f32) -> Result<f32, E> {
234 Ok(44330.0 * (1.0 - libm::powf(self.get_pressure()? / sea_level_hpa, 0.1903)))
235 }
236
237 fn traw_sc(&mut self) -> Result<f32, E> {
238 let mut temp = self.read24(TMP)?;
239 if self.temperature_oversample > SampleRate::Eight {
240 temp <<= 1;
241 }
242 Ok(temp as f32 / self.temperature_oversample.scale_factor())
243 }
244
245 fn praw_sc(&mut self) -> Result<f32, E> {
246 let mut pressure = self.read24(PRS)?;
247 if self.pressure_oversample > SampleRate::Eight {
248 pressure <<= 1;
249 }
250 Ok(pressure as f32 / self.pressure_oversample.scale_factor())
251 }
252
253 pub fn sensor_data_is_ready(&mut self) -> Result<bool, E> {
256 Ok(((self.read8(MEAS_CFG)? >> 6) & 0b1) == 1)
257 }
258
259 pub fn new_data_is_available(&mut self) -> Result<(bool, bool), E> {
261 let byte = self.read8(MEAS_CFG)?;
262 Ok((((byte >> 5) & 1) == 1, ((byte >> 4) & 1) == 1))
263 }
264
265 fn set_pressure_shift(&mut self, value: bool) -> Result<(), E> {
290 let mut reg = self.read8(CFG_REG)? & 0b11111011;
291 reg |= (value as u8) << 2;
292 self.write(&[CFG_REG, reg])
293 }
294
295 fn set_temp_shift(&mut self, value: bool) -> Result<(), E> {
296 let mut reg = self.read8(CFG_REG)? & 0b11110111;
297 reg |= (value as u8) << 3;
298 self.write(&[CFG_REG, reg])
299 }
300
301 pub fn soft_reset(&mut self) -> Result<(), E> {
303 self.write(&[RESET, 0x09])?;
304 self.init()
305 }
306
307 pub fn set_temperature_config(
311 &mut self,
312 sample: SampleRate,
313 oversample: SampleRate,
314 ) -> Result<(), E> {
315 self.set_temp_shift(oversample > SampleRate::Eight)?;
316 self.temperature_oversample = oversample;
317 let byte = 0x80 | (sample as u8) << 4 | oversample as u8;
318 self.write(&[TMP_CFG, byte])
319 }
320
321 pub fn set_pressure_config(
328 &mut self,
329 sample: SampleRate,
330 oversample: SampleRate,
331 ) -> Result<(), E> {
332 self.set_pressure_shift(oversample > SampleRate::Eight)?;
333 self.pressure_oversample = oversample;
334 let byte = (sample as u8) << 4 | oversample as u8;
335 self.write(&[PRS_CFG, byte])
336 }
337
338 pub fn set_mode(&mut self, mode: Mode) -> Result<(), E> {
340 self.mode = match mode {
341 Mode::Standby | Mode::Pressure | Mode::Temperature => Mode::Standby,
342 _ => mode,
343 };
344 self.write(&[MEAS_CFG, mode as u8])
345 }
346
347 fn get_calibration_data(&mut self) -> Result<CalibrationData, E> {
348 let mut data = [0; 2];
349
350 self.read(COEF, &mut data)?;
351 let mut c0 = ((data[0] as u16) << 4) | data[1] as u16 >> 4;
352 if c0 & (1 << 11) != 0 {
353 c0 |= 0xF000;
354 }
355
356 self.read(COEF + 1, &mut data)?;
358 let mut c1 = (((data[0] & 0xF) as u16) << 8) | data[1] as u16;
359 if c1 & (1 << 11) != 0 {
360 c1 |= 0xF000;
361 }
362
363 let mut data = [0; 3];
365 self.read(COEF + 3, &mut data)?;
366 let c00 = if data[0] & 0x80 != 0 { 0xFFF00000 } else { 0 }
367 | ((data[0] as u32) << 12)
368 | ((data[1] as u32) << 4)
369 | ((data[2] as u32) & 0xF0) >> 4;
370
371 self.read(COEF + 5, &mut data)?;
373 let c10 = if data[0] & 0x8 != 0 { 0xFFF00000 } else { 0 }
374 | ((data[0] as u32) & 0x0F) << 16
375 | (data[1] as u32) << 8
376 | data[2] as u32;
377
378 Ok(CalibrationData {
379 c0: c0 as i16,
380 c1: c1 as i16,
381 c00: c00 as i32,
382 c10: c10 as i32,
383 c01: self.read16(COEF + 8)? as i32,
384 c11: self.read16(COEF + 10)? as i32,
385 c20: self.read16(COEF + 12)? as i32,
386 c21: self.read16(COEF + 14)? as i32,
387 c30: self.read16(COEF + 16)? as i32,
388 })
389 }
390
391 fn write(&mut self, data: &[u8]) -> Result<(), E> {
392 self.i2c.write(ADDR, data)
393 }
394
395 fn read(&mut self, reg: u8, buffer: &mut [u8]) -> Result<(), E> {
396 self.i2c.write_read(ADDR, &[reg], buffer)
397 }
398
399 fn read8(&mut self, reg: u8) -> Result<u8, E> {
400 let mut buffer = [0u8];
401 match self.read(reg, &mut buffer) {
402 Ok(_) => Ok(buffer[0]),
403 Err(res) => Err(res),
404 }
405 }
406
407 fn read16(&mut self, reg: u8) -> Result<i16, E> {
408 let mut buffer = [0u8; 2];
409 match self.read(reg, &mut buffer) {
410 Ok(_) => Ok((((buffer[0] as u16) << 8) | buffer[1] as u16) as i16),
411 Err(res) => Err(res),
412 }
413 }
414
415 fn read24(&mut self, reg: u8) -> Result<i32, E> {
416 let mut buffer = [0; 3];
417 self.read(reg, &mut buffer)?;
418 let [msb, lsb, xlsb] = buffer.map(|x| x as u32);
419 let res: u32 =
420 if msb & 0x80 != 0 { 0xFF << 24 } else { 0x00 } | (msb << 16) | (lsb << 8) | xlsb;
421 Ok(res as i32)
422 }
423}
424
425#[derive(Debug, Clone, Copy, Default)]
426struct CalibrationData {
427 c0: i16,
428 c1: i16,
429 c00: i32,
430 c10: i32,
431 c01: i32,
432 c11: i32,
433 c20: i32,
434 c21: i32,
435 c30: i32,
436}
437
438impl SampleRate {
439 fn scale_factor(&self) -> f32 {
440 match self {
441 Self::One => 524288.0,
442 Self::Two => 1572864.0,
443 Self::Four => 3670016.0,
444 Self::Eight => 7864320.0,
445 Self::Sixteen => 253952.0,
446 Self::ThirtyTwo => 516096.0,
447 Self::SixtyFour => 1040384.0,
448 Self::OneTwentyEight => 2088960.0,
449 }
450 }
451}
452
453#[cfg(test)]
454mod tests {
455 use super::*;
456 use embedded_hal_mock::i2c::{Mock as I2cMock, Transaction};
457
458 fn expectations(to_add: Vec<Transaction>) -> Vec<Transaction> {
459 [
460 Transaction::write_read(ADDR, vec![MEAS_CFG], vec![0x80]),
462 Transaction::write_read(ADDR, vec![COEF], vec![0xc, 0xbe]),
463 Transaction::write_read(ADDR, vec![COEF + 1], vec![0xbe, 0xfc]),
464 Transaction::write_read(ADDR, vec![COEF + 3], vec![0x13, 0xd9, 0xaf]),
465 Transaction::write_read(ADDR, vec![COEF + 5], vec![0xaf, 0x2b, 0x34]),
466 Transaction::write_read(ADDR, vec![COEF + 8], vec![0xf3, 0xf7]),
467 Transaction::write_read(ADDR, vec![COEF + 10], vec![0x4, 0xff]),
468 Transaction::write_read(ADDR, vec![COEF + 12], vec![0xda, 0x5a]),
469 Transaction::write_read(ADDR, vec![COEF + 14], vec![0x0, 0xa]),
470 Transaction::write_read(ADDR, vec![COEF + 16], vec![0xfb, 0x1b]),
471 Transaction::write_read(ADDR, vec![CFG_REG], vec![0]),
472 Transaction::write(ADDR, vec![CFG_REG, 0]),
473 Transaction::write(ADDR, vec![PRS_CFG, SampleRate::Eight as u8]),
474 Transaction::write_read(ADDR, vec![CFG_REG], vec![0]),
475 Transaction::write(ADDR, vec![CFG_REG, 0]),
476 Transaction::write(ADDR, vec![TMP_CFG, 0x80 | SampleRate::Eight as u8]),
477 Transaction::write(
478 ADDR,
479 vec![MEAS_CFG, Mode::ContinuousPressureTemperature as u8],
480 ),
481 Transaction::write(ADDR, vec![CFG_REG, 0x00]),
482 ]
483 .to_vec()
484 .into_iter()
485 .chain(to_add)
486 .collect::<std::vec::Vec<_>>()
487 }
488
489 #[test]
490 fn test_barometer_new_init() {
491 let expectations = expectations(vec![]);
492 let mut i2c = I2cMock::new(&expectations);
493 Barometer::new(&mut i2c).unwrap();
494 }
495
496 #[test]
497 fn test_barometer_read() {
498 let expectations = expectations(vec![
499 Transaction::write_read(ADDR, vec![0], vec![0, 1, 2]),
500 Transaction::write_read(ADDR, vec![0], vec![0]),
501 Transaction::write_read(ADDR, vec![0], vec![0, 1]),
502 Transaction::write_read(ADDR, vec![0], vec![0, 1, 2]),
503 ]);
504 let mut i2c = I2cMock::new(&expectations);
505 let mut barometer = Barometer::new(&mut i2c).unwrap();
506
507 let mut buffer = [0; 3];
508 barometer.read(0, &mut buffer).unwrap();
509 barometer.read8(0).unwrap();
510 barometer.read16(0).unwrap();
511 barometer.read24(0).unwrap();
512 assert_eq!(buffer, [0, 1, 2]);
513 }
514
515 #[test]
516 fn test_barometer_get_calibration_data() {
517 let expectations = expectations(vec![]);
518 let mut i2c = I2cMock::new(&expectations);
519 let mut barometer = Barometer {
520 i2c: &mut i2c,
521 calibration_data: CalibrationData::default(),
522 temperature_oversample: SampleRate::Eight,
523 pressure_oversample: SampleRate::Eight,
524 mode: Mode::Standby,
525 };
526 barometer.read8(MEAS_CFG).unwrap();
528 let cal_data = barometer.get_calibration_data().unwrap();
529 assert_eq!(cal_data.c0, 203, "c0");
530 assert_eq!(cal_data.c1, -260, "c1");
531 assert_eq!(cal_data.c00, 81306, "c00");
532 assert_eq!(cal_data.c10, -54476, "c10");
533 assert_eq!(cal_data.c01, -3081, "c01");
534 assert_eq!(cal_data.c11, 1279, "c11");
535 assert_eq!(cal_data.c20, -9638, "c20");
536 assert_eq!(cal_data.c21, 10, "c21");
537 assert_eq!(cal_data.c30, -1253, "c30");
538 }
539
540 #[test]
541 fn test_barometer_get_temperature() {
542 let expectations = expectations(vec![
543 Transaction::write_read(ADDR, vec![TMP], vec![0, 1, 2]),
544 Transaction::write_read(ADDR, vec![MEAS_CFG], vec![0]),
545 Transaction::write(ADDR, vec![MEAS_CFG, Mode::Temperature as u8]),
546 Transaction::write_read(ADDR, vec![MEAS_CFG], vec![0]),
547 Transaction::write(ADDR, vec![MEAS_CFG, Mode::Temperature as u8]),
548 Transaction::write_read(ADDR, vec![MEAS_CFG], vec![0b100000]),
549 Transaction::write_read(ADDR, vec![TMP], vec![0, 1, 2]),
550 ]);
551 let mut i2c = I2cMock::new(&expectations);
552 let mut barometer = Barometer::new(&mut i2c).unwrap();
553 barometer.mode = Mode::ContinuousPressureTemperature;
554 barometer.get_temperature().unwrap(); barometer.mode = Mode::Standby;
556 barometer.get_temperature().unwrap(); }
558
559 #[test]
560 fn test_barometer_get_pressure() {
561 let expectations = expectations(vec![
562 Transaction::write_read(ADDR, vec![TMP], vec![0, 1, 2]),
563 Transaction::write_read(ADDR, vec![PRS], vec![0, 1, 2]),
564 Transaction::write_read(ADDR, vec![MEAS_CFG], vec![0]),
565 Transaction::write(ADDR, vec![MEAS_CFG, Mode::Temperature as u8]),
566 Transaction::write_read(ADDR, vec![MEAS_CFG], vec![0]),
567 Transaction::write(ADDR, vec![MEAS_CFG, Mode::Temperature as u8]),
568 Transaction::write_read(ADDR, vec![MEAS_CFG], vec![0b100000]),
569 Transaction::write_read(ADDR, vec![TMP], vec![0, 1, 2]),
570 Transaction::write_read(ADDR, vec![MEAS_CFG], vec![0]),
571 Transaction::write(ADDR, vec![MEAS_CFG, Mode::Pressure as u8]),
572 Transaction::write_read(ADDR, vec![MEAS_CFG], vec![0b100000]),
573 Transaction::write(ADDR, vec![MEAS_CFG, Mode::Pressure as u8]),
574 Transaction::write_read(ADDR, vec![MEAS_CFG], vec![0b010000]),
575 Transaction::write_read(ADDR, vec![TMP], vec![0, 1, 2]),
576 Transaction::write_read(ADDR, vec![PRS], vec![0, 1, 2]),
577 ]);
578 let mut i2c = I2cMock::new(&expectations);
579 let mut barometer = Barometer::new(&mut i2c).unwrap();
580 barometer.mode = Mode::ContinuousPressureTemperature;
581 barometer.get_pressure().unwrap(); barometer.mode = Mode::Standby;
583 barometer.get_pressure().unwrap(); }
585
586 #[test]
587 fn test_barometer_altitude() {
588 let expectations = expectations(vec![
589 Transaction::write_read(ADDR, vec![TMP], vec![0, 1, 2]),
590 Transaction::write_read(ADDR, vec![PRS], vec![0, 1, 2]),
591 ]);
592 let mut i2c = I2cMock::new(&expectations);
593 let mut barometer = Barometer::new(&mut i2c).unwrap();
594 barometer.mode = Mode::ContinuousPressureTemperature;
595 let altitude = barometer.altitude(1000.0).unwrap();
596 assert_eq!(altitude, 1712.0905); }
598}