1#![no_std]
11#![allow(unused)]
12use embedded_hal::blocking::{i2c, delay::DelayMs};
13
14
15#[derive(Debug)]
17pub enum Error<E> {
18 CommunicationError(E),
19 SensorDetectFailed,
20 RegisterReadFailed,
21 RegisterWriteFailed,
22 CrcCheckFailed,
23 InvalidResolution,
24}
25
26impl<E> From<E> for Error<E> {
28 fn from(e: E) -> Self {
29 Error::CommunicationError(e)
30 }
31}
32pub struct MS8607<I2C>
47{
48 i2c: I2C,
49 press_sens: u16,
51 press_offset: u16,
52 press_sens_temp_coeff: u16,
53 press_offset_temp_coeff: u16,
54 ref_temp: u16,
55 temp_temp_coeff: u16,
56 hum_sensor_i2c_read_mode: Ms8607HumidityClockStretch,
58 psensor_resolution_osr: Ms8607PressureResolution,
59 _pressure: f64,
61 _temperature: f64,
63 _humidity: f64,
65}
66
67impl<I2C, E> MS8607<I2C>
68where
69 I2C: i2c::Write<Error = E> + i2c::WriteRead<Error = E>,
70{
71 pub fn new(i2c:I2C) -> Self {
73 MS8607 {
74 i2c,
75 press_sens: 0,
76 press_offset: 0,
77 press_sens_temp_coeff: 0,
78 press_offset_temp_coeff: 0,
79 ref_temp: 0,
80 temp_temp_coeff: 0,
81 hum_sensor_i2c_read_mode: Ms8607HumidityClockStretch::Ms8607I2cHold,
82 psensor_resolution_osr: Ms8607PressureResolution::Osr4096,
83 _pressure: 0.0,
84 _temperature: 0.0,
85 _humidity: 0.0,
86 }
87 }
88
89 pub fn begin<Delay>(&mut self, delay:&mut Delay) -> Result<(), Error<E>> where
91 Delay: DelayMs<u16> {
92 self.reset(delay)?;
93 self.init()?;
94 Ok(())
95 }
96
97 pub fn init(&mut self) -> Result<(), Error<E>>{
99 self._fetch_temp_calibration_values()?;
100 self.enable_humidity_clock_stretching(false);
101
102 self.set_humidity_resolution( Ms8607HumidityResolution::Osr12b)?;
103
104 self.set_pressure_resolution(Ms8607PressureResolution::Osr4096);
105
106 Ok(())
107 }
108
109 pub fn enable_humidity_clock_stretching(&mut self, enable_stretching: bool) {
115 if enable_stretching {
116 self.hum_sensor_i2c_read_mode = Ms8607HumidityClockStretch::Ms8607I2cHold;
117 } else {
118 self.hum_sensor_i2c_read_mode = Ms8607HumidityClockStretch::Ms8607I2cNoHold;
119 }
120 }
121
122 pub fn set_humidity_resolution(
127 &mut self,
128 resolution: Ms8607HumidityResolution,
129 ) -> Result<(), Error<E>> {
130 let mut reg_value = self._read_humidity_user_register()?;
131
132 reg_value &= _MS8607::HSENSOR_USER_REG_RESOLUTION_MASK;
134 reg_value |= resolution as u8 & _MS8607::HSENSOR_USER_REG_RESOLUTION_MASK;
136
137 self._write_humidity_user_register( reg_value)
138 }
139
140 pub fn set_pressure_resolution(&mut self, resolution: Ms8607PressureResolution) {
145 self.psensor_resolution_osr = resolution;
146 }
147
148 pub fn get_humidity_resolution(&mut self) -> Result<Ms8607HumidityResolution, Error<E>>{
150 let reg_value = self._read_humidity_user_register()?;
151 let resolution = reg_value & _MS8607::HSENSOR_USER_REG_RESOLUTION_MASK;
152 match resolution {
153 0 => Ok(Ms8607HumidityResolution::Osr12b),
154 1 => Ok(Ms8607HumidityResolution::Osr8b),
155 2 => Ok(Ms8607HumidityResolution::Osr10b),
156 3 => Ok(Ms8607HumidityResolution::Osr11b),
157 _ => Err(Error::InvalidResolution),
158 }
159 }
160
161 pub fn get_pressure_resolution(&self) -> Ms8607PressureResolution {
163 self.psensor_resolution_osr
164 }
165
166 pub fn get_measurements<Delay>(&mut self,delay:&mut Delay) -> Result<(f64, f64, f64), Error<E>> where
167 Delay: DelayMs<u16> {
168 self._read( delay)?;
169 self._read_humidity()?;
170 Ok((self._pressure, self._temperature, self._humidity))
171 }
172
173 fn _read<Delay>(&mut self, delay:&mut Delay) -> Result<(), Error<E>> where
177 Delay: DelayMs<u16> {
178 let mut cmd = [0u8; 1];
179 let mut buffer = [0u8; 3];
180
181 cmd[0] = self.psensor_resolution_osr as u8 * 2;
183 cmd[0] |= _MS8607::PSENSOR_START_TEMPERATURE_ADC_CONVERSION;
184 self.i2c.write(_MS8607::PT_ADDRESS, &cmd).map_err(Error::from)?;
185
186 delay.delay_ms(20);
188
189 cmd = [_MS8607::PSENSOR_READ_ADC];
190 self.i2c.write_read(_MS8607::PT_ADDRESS, &cmd, &mut buffer).map_err(Error::from)?;
191
192 let raw_temp = ((buffer[0] as u32) << 16) | ((buffer[1] as u32) << 8) | (buffer[2] as u32);
193 delay.delay_ms(20);
194 cmd[0] = self.psensor_resolution_osr as u8 * 2;
196 cmd[0] |= _MS8607::PSENSOR_START_PRESSURE_ADC_CONVERSION;
197 self.i2c.write(_MS8607::PT_ADDRESS, &cmd).map_err(Error::from)?;
198
199 delay.delay_ms(20);
201 buffer = [0u8; 3];
202
203 cmd = [_MS8607::PSENSOR_READ_ADC];
204 self.i2c.write_read(_MS8607::PT_ADDRESS, &cmd, &mut buffer).map_err(Error::from)?;
205
206 let raw_pressure =
207 ((buffer[0] as u32) << 16) | ((buffer[1] as u32) << 8) | (buffer[2] as u32);
208 self._apply_ptcorrections(raw_temp as i32, raw_pressure as i32);
209 Ok(())
210 }
211
212 fn _read_humidity(&mut self) -> Result<(), Error<E>> {
220 let mut buffer = [0u8; 3];
221 self.get_humidity_resolution()?;
222 let cmd = [Ms8607HumidityClockStretch::Ms8607I2cHold as u8];
223 self.i2c.write_read(_MS8607::HUM_ADDRESS, &cmd, &mut buffer).map_err(Error::from)?;
224
225 let raw_hum: u16 = (buffer[0] as u16) << 8 | (buffer[1] as u16);
226 let crc = buffer[2];
227 self._hsensor_crc_check(raw_hum, crc)?;
228 self._humidity = ((raw_hum as f32) * _MS8607::MS8607_RH_LSB) as f64;
229 self._humidity -= 6.0;
230 Ok(())
231 }
232
233 fn _apply_ptcorrections(&mut self, raw_temp: i32, raw_pressure: i32) {
241 let mut off: i64;
242 let mut sens: i64;
243 let t2: i64;
244 let mut off2: i64;
245 let mut sens2: i64;
246
247 let d_t = raw_temp - ((self.ref_temp as i32) << 8);
248
249 let temp = (2000 + (((d_t as i64) * (self.temp_temp_coeff as i64)) >> 23)) as i32;
251
252 if temp < 2000 {
254 t2 = (3 * ((d_t as i64) * (d_t as i64))) >> 33;
255 off2 = 61 * ((temp as i64) - 2000) * ((temp as i64) - 2000) / 16;
256 sens2 = 29 * ((temp as i64) - 2000) * ((temp as i64) - 2000) / 16;
257
258 if temp < -1500 {
259 off2 += 17 * ((temp as i64) + 1500) * ((temp as i64) + 1500);
260 sens2 += 9 * ((temp as i64) + 1500) * ((temp as i64) + 1500);
261 }
262 } else {
263 t2 = (5 * ((d_t as i64) * (d_t as i64))) >> 38;
264 off2 = 0;
265 sens2 = 0;
266 }
267
268 off = ((self.press_offset as i64) << 17)
270 + (((self.press_offset_temp_coeff as i64) * (d_t as i64)) >> 6);
271 off -= off2;
272
273 sens = ((self.press_sens as i64) << 16)
275 + (((self.press_sens_temp_coeff as i64) * (d_t as i64)) >> 7);
276 sens -= sens2;
277
278 let p = ((((raw_pressure as i64) * sens) >> 21) - off) >> 15;
280
281 self._temperature = ((temp as f64) - t2 as f64) / 100.0;
282 self._pressure = p as f64 / 100.0;
283 }
284
285 fn _write_humidity_user_register(&mut self, new_reg_value: u8) -> Result<(), Error<E>>{
297 let buffer = [_MS8607::HSENSOR_WRITE_USER_REG_COMMAND, new_reg_value];
298 self.i2c.write(_MS8607::HUM_ADDRESS, &buffer).map_err(Error::from)?;
299 Ok(())
300 }
301
302 fn _read_humidity_user_register(&mut self) -> Result<u8, Error<E>> {
311 let mut cmd = [_MS8607::HSENSOR_READ_USER_REG_COMMAND];
312 let mut buffer = [0u8; 1];
313
314
315 self.i2c.write_read(_MS8607::HUM_ADDRESS, &cmd, &mut buffer).map_err(Error::from)?;
316
317 Ok(buffer[0])
318 }
319
320 fn _fetch_temp_calibration_values(&mut self) -> Result<(), Error<E>> {
329 let mut offset: u8 = 0;
330 let mut buffer = [0u16; 8];
331 let mut tmp_buffer = [0u8; 2];
332
333 buffer
334 .iter_mut()
335 .enumerate()
336 .take(7usize)
337 .for_each(|(i, v)| {
338 offset = 2 * (i as u8);
339 let cmd = [_MS8607::PROM_ADDRESS_READ_ADDRESS_0 + offset];
340 let req = self.i2c.write_read(_MS8607::PT_ADDRESS, &cmd,&mut tmp_buffer);
341 if req.is_err() {
342 return;
343 }
344 *v = (tmp_buffer[0] as u16) << 8;
345 *v |= tmp_buffer[1] as u16;
346 });
347 if offset != 12 {
349 return Err(Error::RegisterReadFailed);
350 }
351 self._psensor_crc_check(&mut buffer)?;
353
354 self.press_sens = buffer[1];
355 self.press_offset = buffer[2];
356 self.press_sens_temp_coeff = buffer[3];
357 self.press_offset_temp_coeff = buffer[4];
358 self.ref_temp = buffer[5];
359 self.temp_temp_coeff = buffer[6];
360 Ok(())
361 }
362
363 fn _psensor_crc_check(&mut self, n_prom: &mut [u16; 8]) -> Result<(), Error<E>> {
381 let mut n_rem = 0;
382 let crc = ((n_prom[0] & 0xF000) >> 12) as u8;
383 n_prom[0] &= 0x0FFF; n_prom[7] = 0; for cnt in 0..16 {
386 if cnt % 2 == 1 {
389 n_rem ^= (n_prom[cnt >> 1] & 0x00FF);
390 } else {
391 n_rem ^= n_prom[cnt >> 1] >> 8;
392 }
393 for n_bit in 0..8 {
394 if n_rem & 0x8000 != 0 {
395 n_rem = (n_rem << 1) ^ 0x3000;
396 } else {
397 n_rem <<= 1;
398 }
399 }
400 }
401 n_rem = (n_rem >> 12) & 0x000F; if n_rem != crc as u16 {
403 return Err(Error::CrcCheckFailed);
404 }
405 Ok(())
406 }
407
408 fn _hsensor_crc_check(&mut self, value: u16, crc: u8) -> Result<(), Error<E>> {
419 let mut polynom: u32 = 0x988000; let mut msb: u32 = 0x800000;
421 let mut mask: u32 = 0xFF8000;
422 let mut result: u32 = (value as u32) << 8; while msb != 0x80 {
425 if result & msb != 0 {
427 result = ((result ^ polynom) & mask) | (result & !mask);
428 }
429
430 msb >>= 1;
432 mask >>= 1;
433 polynom >>= 1;
434 }
435 if (result) as u8 != crc {
436 return Err(Error::CrcCheckFailed);
437 }
438 Ok(())
439 }
440
441 pub fn reset<Delay>(&mut self, delay: &mut Delay) -> Result<(), Error<E>> where Delay: DelayMs<u16> {
443 let cmd = [_MS8607::P_T_RESET];
444 self.i2c.write(_MS8607::PT_ADDRESS, &cmd).map_err(Error::from)?;
445
446 let cmd = [_MS8607::HSENSOR_RESET_COMMAND];
447 self.i2c.write(_MS8607::HUM_ADDRESS, &cmd).map_err(Error::from)?;
448
449 delay.delay_ms(15);
451 Ok(())
452 }
453}
454
455struct _MS8607 {}
456
457impl _MS8607 {
458 pub const PT_ADDRESS: u8 = 0x76;
462 pub const HUM_ADDRESS: u8 = 0x40;
464
465 pub const HSENSOR_RESET_COMMAND: u8 = 0xFE;
468 pub const HSENSOR_READ_HUMIDITY_W_HOLD_COMMAND: u8 = 0xE5;
470 pub const HSENSOR_READ_HUMIDITY_WO_HOLD_COMMAND: u8 = 0xF5;
472 pub const HSENSOR_READ_SERIAL_FIRST_8BYTES_COMMAND: u16 = 0xFA0F;
474 pub const HSENSOR_READ_SERIAL_LAST_6BYTES_COMMAND: u16 = 0xFCC9;
476 pub const HSENSOR_WRITE_USER_REG_COMMAND: u8 = 0xE6;
478 pub const HSENSOR_READ_USER_REG_COMMAND: u8 = 0xE7;
480
481 pub const HSENSOR_TEMPERATURE_COEFFICIENT: f32 = -0.15;
484 pub const HSENSOR_CONSTANT_A: f32 = 8.1332;
486 pub const HSENSOR_CONSTANT_B: f32 = 1762.39;
488 pub const HSENSOR_CONSTANT_C: f32 = 235.66;
490
491 pub const TEMPERATURE_COEFF_MUL: f32 = 175.72;
494 pub const TEMPERATURE_COEFF_ADD: f32 = -46.85;
496
497 pub const HUMIDITY_COEFF_MUL: f32 = 125.0;
500 pub const HUMIDITY_COEFF_ADD: f32 = -6.0;
502
503 pub const HSENSOR_CONVERSION_TIME_12B: u8 = 16;
506 pub const HSENSOR_CONVERSION_TIME_10B: u8 = 5;
508 pub const HSENSOR_CONVERSION_TIME_8B: u8 = 3;
510 pub const HSENSOR_CONVERSION_TIME_11B: u8 = 9;
512
513 pub const HSENSOR_USER_REG_RESOLUTION_MASK: u8 = 0x81;
516 pub const HSENSOR_USER_REG_END_OF_BATTERY_MASK: u8 = 0x40;
518 pub const HSENSOR_USER_REG_ENABLE_ONCHIP_HEATER_MASK: u8 = 0x4;
520 pub const HSENSOR_USER_REG_DISABLE_OTP_RELOAD_MASK: u8 = 0x2;
522
523 pub const RH_ADDRESS: u8 = 0x40;
525
526 pub const MS8607_RH_LSB: f32 = 0.001_907_348_6;
529
530 pub const PROM_ADDRESS_READ_ADDRESS_0: u8 = 0xA0;
533
534 pub const P_T_RESET: u8 = 0x1E;
537 pub const CONVERT_D1_OSR_256: u8 = 0x40;
539 pub const CONVERT_D1_OSR_512: u8 = 0x42;
541 pub const CONVERT_D1_OSR_1024: u8 = 0x44;
543 pub const CONVERT_D1_OSR_2048: u8 = 0x46;
545 pub const CONVERT_D1_OSR_4096: u8 = 0x48;
547 pub const CONVERT_D1_OSR_8192: u8 = 0x4A;
549 pub const CONVERT_D2_OSR_256: u8 = 0x50;
551 pub const CONVERT_D2_OSR_512: u8 = 0x52;
553 pub const CONVERT_D2_OSR_1024: u8 = 0x54;
555 pub const CONVERT_D2_OSR_2048: u8 = 0x56;
557 pub const CONVERT_D2_OSR_4096: u8 = 0x58;
559 pub const CONVERT_D2_OSR_8192: u8 = 0x5A;
561 pub const ADC_READ: u8 = 0x00;
563 pub const HUMIDITY_RESET: u8 = 0xFE;
568 pub const HUMIDITY_WRITE_REGISTER: u8 = 0xE6;
570 pub const HUMIDITY_READ_REGISTER: u8 = 0xE7;
572 pub const HUM_MEASURE_RH_HOLD: u8 = 0xE5;
574 pub const HUM_MEASURE_RH_NO_HOLD: u8 = 0xF5;
576 pub const PSENSOR_RESET_COMMAND: u8 = 0x1E;
580 pub const PSENSOR_START_PRESSURE_ADC_CONVERSION: u8 = 0x40;
582 pub const PSENSOR_START_TEMPERATURE_ADC_CONVERSION: u8 = 0x50;
584 pub const PSENSOR_READ_ADC: u8 = 0x00;
586}
587
588#[derive(Clone, Copy)]
590pub enum Ms8607PressureResolution {
591 Osr256,
593 Osr512,
595 Osr1024,
597 Osr2048,
599 Osr4096,
601 Osr8192,
603}
604
605pub enum Ms8607HumidityResolution {
607 Osr12b = 0x00,
608 Osr11b = 0x81,
609 Osr10b = 0x80,
610 Osr8b = 0x01,
611}
612
613pub enum Ms8607HumidityClockStretch {
615 Ms8607I2cHold = 0xE5,
616 Ms8607I2cNoHold = 0xF5,
617}