1#![no_std]
20#![deny(missing_docs)]
21#![allow(clippy::trivially_copy_pass_by_ref, clippy::new_ret_no_self)]
22
23use core::mem;
24
25use cast::{i16, i32, u16, u32};
26use generic_array::typenum::consts::*;
27use generic_array::{ArrayLength, GenericArray};
28use hal::blocking::delay::DelayUs;
29use hal::blocking::i2c::{Write, WriteRead};
30
31#[allow(clippy::unreadable_literal)]
36const ADDRESS: u8 = 0b1110111; #[allow(non_camel_case_types)]
40#[derive(Copy, Clone)]
41enum Register {
42 COEFF_AC1 = 0xAA,
43 COEFF_AC2 = 0xAC,
44 COEFF_AC3 = 0xAE,
45 COEFF_AC4 = 0xB0,
46 COEFF_AC5 = 0xB2,
47 COEFF_AC6 = 0xB4,
48 COEFF_B1 = 0xB6,
49 COEFF_B2 = 0xB8,
50 COEFF_MB = 0xBA,
51 COEFF_MC = 0xBC,
52 COEFF_MD = 0xBE,
53 CONTROL_REG = 0xF4,
55 VALUE_REG = 0xF6,
57}
58
59impl Register {
60 pub fn addr(&self) -> u8 {
61 *self as u8
62 }
63}
64
65#[allow(non_camel_case_types)]
70#[derive(Copy, Clone)]
71enum ControlRegisterValue {
72 CONTROL_VALUE_TEMPERATURE = 0x2E, CONTROL_VALUE_PRESSURE_OSRS_0 = 0x34, CONTROL_VALUE_PRESSURE_OSRS_1 = 0x74, CONTROL_VALUE_PRESSURE_OSRS_2 = 0xB4, CONTROL_VALUE_PRESSURE_OSRS_3 = 0xF4, }
78
79impl ControlRegisterValue {
80 pub fn addr(&self) -> u8 {
81 *self as u8
82 }
83}
84
85impl From<Oversampling> for ControlRegisterValue {
86 fn from(oss: Oversampling) -> Self {
87 match oss {
88 Oversampling::UltraLowPower => ControlRegisterValue::CONTROL_VALUE_PRESSURE_OSRS_0,
89 Oversampling::Standard => ControlRegisterValue::CONTROL_VALUE_PRESSURE_OSRS_1,
90 Oversampling::HighResolution => ControlRegisterValue::CONTROL_VALUE_PRESSURE_OSRS_2,
91 Oversampling::UltraHighResolution => {
92 ControlRegisterValue::CONTROL_VALUE_PRESSURE_OSRS_3
93 }
94 }
95 }
96}
97
98struct Coefficients {
102 pub ac1: i16,
103 pub ac2: i16,
104 pub ac3: i16,
105 pub ac4: u16,
106 pub ac5: u16,
107 pub ac6: u16,
108 pub b1: i16,
109 pub b2: i16,
110 pub mb: i16,
111 pub mc: i16,
112 pub md: i16,
113}
114
115impl Coefficients {
116 fn new() -> Self {
117 Coefficients {
118 ac1: 0,
119 ac2: 0,
120 ac3: 0,
121 ac4: 0,
122 ac5: 0,
123 ac6: 0,
124 b1: 0,
125 b2: 0,
126 mb: 0,
127 mc: 0,
128 md: 0,
129 }
130 }
131}
132
133#[derive(Copy, Clone)]
135pub enum Oversampling {
136 UltraLowPower = 0,
138 Standard = 1,
140 HighResolution = 2,
142 UltraHighResolution = 3,
144}
145
146impl Oversampling {
147 fn value(&self) -> u8 {
148 *self as u8
149 }
150}
151
152pub struct Bmp085<I2C, TIMER: DelayUs<u16>> {
154 i2c: I2C,
155 timer: TIMER,
156 coeff: Coefficients,
157 oss: Oversampling,
158}
159
160pub type DeciCelcius = i32;
162
163pub type Pascal = i32;
165
166pub struct PT {
168 pub temperature: DeciCelcius,
170 pub pressure: Pascal,
176}
177
178impl<I2C, TIMER, E> Bmp085<I2C, TIMER>
179where
180 I2C: WriteRead<Error = E> + Write<Error = E>,
181 TIMER: DelayUs<u16>,
182{
183 pub fn new(i2c: I2C, timer: TIMER, oss: Oversampling) -> Result<Self, E> {
185 let mut bmp085 = Bmp085 {
186 i2c,
187 timer,
188 coeff: Coefficients::new(),
189 oss,
190 };
191
192 bmp085.coeff.ac1 = bmp085.read_i16(Register::COEFF_AC1)?;
194 bmp085.coeff.ac2 = bmp085.read_i16(Register::COEFF_AC2)?;
195 bmp085.coeff.ac3 = bmp085.read_i16(Register::COEFF_AC3)?;
196 bmp085.coeff.ac4 = bmp085.read_u16(Register::COEFF_AC4)?;
197 bmp085.coeff.ac5 = bmp085.read_u16(Register::COEFF_AC5)?;
198 bmp085.coeff.ac6 = bmp085.read_u16(Register::COEFF_AC6)?;
199 bmp085.coeff.b1 = bmp085.read_i16(Register::COEFF_B1)?;
200 bmp085.coeff.b2 = bmp085.read_i16(Register::COEFF_B2)?;
201 bmp085.coeff.mb = bmp085.read_i16(Register::COEFF_MB)?;
202 bmp085.coeff.mc = bmp085.read_i16(Register::COEFF_MC)?;
203 bmp085.coeff.md = bmp085.read_i16(Register::COEFF_MD)?;
204
205 Ok(bmp085)
206 }
207
208 fn read_u16(&mut self, reg: Register) -> Result<u16, E> {
209 let buf: GenericArray<u8, U2> = self.read_register(reg)?;
210 Ok((u16(buf[0]) << 8) + u16(buf[1]))
211 }
212
213 fn read_i16(&mut self, reg: Register) -> Result<i16, E> {
214 let buf: GenericArray<u8, U2> = self.read_register(reg)?;
215 Ok((i16(buf[0]) << 8) + i16(buf[1]))
216 }
217
218 fn read_register<N>(&mut self, reg: Register) -> Result<GenericArray<u8, N>, E>
219 where
220 N: ArrayLength<u8>,
221 {
222 let mut buffer: GenericArray<u8, N> = unsafe { mem::uninitialized() };
223 {
224 let buffer: &mut [u8] = &mut buffer;
225 self.i2c.write_read(ADDRESS, &[reg.addr()], buffer)?;
226 }
227 Ok(buffer)
228 }
229
230 fn write_register(&mut self, reg: Register, byte: u8) -> Result<(), E> {
231 self.i2c.write(ADDRESS, &[reg.addr(), byte])
232 }
233
234 pub fn read(&mut self) -> Result<PT, E> {
236 self.write_register(
238 Register::CONTROL_REG,
239 ControlRegisterValue::CONTROL_VALUE_TEMPERATURE.addr(),
240 )?;
241 self.timer.delay_us(4500);
242 let ut = self.read_i16(Register::VALUE_REG)?;
243 let (temperature, b5) = calculate_temperature(i32(ut), &self.coeff);
244
245 let press_reg_value = ControlRegisterValue::from(self.oss);
247 self.write_register(Register::CONTROL_REG, press_reg_value.addr())?;
248 self.timer.delay_us(1000 * (2 + (3 << self.oss.value())));
249 let up: GenericArray<u8, U3> = self.read_register(Register::VALUE_REG)?;
250 let up: i32 =
251 ((i32(up[0]) << 16) + (i32(up[1]) << 8) + i32(up[2])) >> (8 - self.oss.value());
252 let pressure: Pascal = calculate_true_pressure(up, b5, self.oss, &self.coeff);
253
254 Ok(PT {
255 temperature,
256 pressure,
257 })
258 }
259}
260
261fn calculate_temperature(ut: i32, coeff: &Coefficients) -> (DeciCelcius, i32) {
263 let x1: i32 = ((ut - i32(coeff.ac6)) * i32(coeff.ac5)) >> 15;
264 let x2: i32 = (i32(coeff.mc) << 11) / (x1 + i32(coeff.md));
265 let b5: i32 = x1 + x2; let t: DeciCelcius = (b5 + 8) >> 4;
267 (t, b5)
268}
269
270fn calculate_true_pressure(up: i32, b5: i32, oss: Oversampling, coeff: &Coefficients) -> Pascal {
272 let b6: i32 = b5 - 4000;
273
274 let x1: i32 = ((i32(coeff.b2) * (b6 * b6)) >> 12) >> 11;
276 let x2: i32 = (i32(coeff.ac2) * b6) >> 11;
277 let x3: i32 = x1 + x2;
278 let b3: i32 = (((i32(coeff.ac1) * 4 + x3) << oss.value()) + 2) >> 2;
279
280 let x1: i32 = (i32(coeff.ac3) * b6) >> 13;
282 let x2: i32 = (i32(coeff.b1) * ((b6 * b6) >> 12)) >> 16;
283 let x3: i32 = (x1 + x2 + 2) >> 2;
284 let b4: u32 = (u32(coeff.ac4) * ((x3 as u32) + 32768)) >> 15;
285
286 let b7: u32 = ((up - b3) as u32) * (50000u32 >> oss.value());
288
289 let p: i32 = if b7 < 0x8000_0000 {
290 b7 * 2 / b4
291 } else {
292 b7 / b4 * 2
293 } as i32;
294
295 let x1: i32 = (p >> 8) * (p >> 8);
296 let x1: i32 = (x1 * 3038) >> 16;
297 let x2: i32 = (-7357 * p) >> 16;
298 p + ((x1 + x2 + 3791) >> 4)
299}
300
301#[cfg(feature = "default")]
310pub fn pressure_to_normal_null(p: Pascal, altitude: u16) -> u16 {
311 let z = (p as f32) / libm::powf(1f32 - (f32::from(altitude) / 44330f32), 5.255f32);
312 libm::roundf(z / 100f32) as u16
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318
319 #[test]
320 fn calculate_temp_pressure() {
321 let coeff = Coefficients {
323 ac1: 408,
324 ac2: -72,
325 ac3: -14383,
326 ac4: 32741,
327 ac5: 32757,
328 ac6: 23153,
329 b1: 6190,
330 b2: 4,
331 mb: -32767,
332 mc: -8711,
333 md: 2868,
334 };
335
336 let ut: i32 = 27898; let up: i32 = 23843; let oss = Oversampling::UltraLowPower;
339 assert_eq!(oss.value(), 0);
340
341 let (deci_c, b5) = calculate_temperature(ut, &coeff);
342 assert_eq!(deci_c, 150);
343 assert_eq!(b5, 2400); let pressure: Pascal = calculate_true_pressure(up, b5, oss, &coeff);
346 assert_eq!(pressure, 69964); }
348
349 #[test]
350 #[cfg(feature = "default")]
351 fn calculate_pressure_to_normal_null() {
352 let p: Pascal = 93728;
353 let alt: u16 = 691; let pnn = pressure_to_normal_null(p, alt);
355 assert_eq!(1018, pnn);
356 }
357}