tof_control/device/
bme280.rs

1#![allow(unused)]
2use crate::constant::*;
3
4use i2cdev::core::*;
5use i2cdev::linux::{LinuxI2CDevice, LinuxI2CError};
6
7// BME280 Register
8const ID: u16 = 0xD0;
9const RESET: u16 = 0xE0;
10const RESET_CODE: u16 = 0xB6;
11const CONFIG: u16 = 0xF5;
12const CTRL_HUM: u16 = 0xF2;
13const STATUS: u16 = 0xF3;
14const CTRL_MEAS: u16 = 0xF4;
15const HUM_LSB: u16 = 0xFE;
16const HUM_MSB: u16 = 0xFD;
17const TEMP_XLSB: u16 = 0xFC;
18const TEMP_LSB: u16 = 0xFB;
19const TEMP_MSB: u16 = 0xFA;
20const PRESS_XLSB: u16 = 0xF9;
21const PRESS_LSB: u16 = 0xF8;
22const PRESS_MSB: u16 = 0xF7;
23const TEMP_COMP: u16 = 0x88;
24const PRESS_COMP: u16 = 0x8E;
25const HUM_COMP_1: u16 = 0xA1;
26const HUM_COMP_2: u16 = 0xE1;
27// BME280 Configuration Register
28const T_SB_0_5: u16 = 0x00; // T standby 0.5ms
29const T_SB_62_5: u16 = 0x20; // T standby 62.5ms
30const T_SB_125: u16 = 0x40; // T standby 125ms
31const T_SB_250: u16 = 0x60; // T standby 250ms
32const T_SB_500: u16 = 0x80; // T standby 500ms
33const T_SB_1000: u16 = 0xA0; // T standby 1000ms
34const T_SB_10: u16 = 0xC0; // T standby 10ms
35const T_SB_20: u16 = 0xE0; // T standby 20ms
36const FILTER_OFF: u16 = 0x00; // Filter off
37const FILTER_2: u16 = 0x04; // Filter coefficient 2
38const FILTER_4: u16 = 0x08; // Filter coefficient 4
39const FILTER_8: u16 = 0x0C; // Filter coefficient 8
40const FILTER_16: u16 = 0x10; // Filter coefficient 16
41const SPI3W_DI: u16 = 0x00; // SPI interface disabled
42const SPI3W_EN: u16 = 0x01; // SPI interface enabled
43                            // BME280 Humidity Control Register
44const OSRS_H_S: u16 = 0x00; // Oversampling skipped
45const OSRS_H_1: u16 = 0x01; // Oversampling x1
46const OSRS_H_2: u16 = 0x02; // Oversampling x2
47const OSRS_H_4: u16 = 0x03; // Oversampling x4
48const OSRS_H_8: u16 = 0x04; // Oversampling x8
49const OSRS_H_16: u16 = 0x05; // Oversampling x16
50                             // BME280 Temperature and Pressure Control Register
51const OSRS_T_S: u16 = 0x00; // Oversampling skipped
52const OSRS_T_1: u16 = 0x20; // Oversampling x1
53const OSRS_T_2: u16 = 0x40; // Oversampling x2
54const OSRS_T_4: u16 = 0x60; // Oversampling x4
55const OSRS_T_8: u16 = 0x80; // Oversampling x8
56const OSRS_T_16: u16 = 0xA0; // Oversampling x16
57const OSRS_P_S: u16 = 0x00; // Oversampling skipped
58const OSRS_P_1: u16 = 0x04; // Oversampling x1
59const OSRS_P_2: u16 = 0x08; // Oversampling x2
60const OSRS_P_4: u16 = 0x0C; // Oversampling x4
61const OSRS_P_8: u16 = 0x10; // Oversampling x8
62const OSRS_P_16: u16 = 0x14; // Oversampling x16
63const MODE_S: u16 = 0x00; // Sleep mode
64const MODE_F: u16 = 0x01; // Forced mode
65const MODE_N: u16 = 0x03; // Normal mode
66
67pub struct BME280 {
68    bus: u8,
69    address: u16,
70}
71struct CompensateData {
72    dig_t: Vec<u16>,
73    dig_p: Vec<u16>,
74    dig_h: Vec<u16>,
75}
76
77impl BME280 {
78    pub fn new(bus: u8, address: u16) -> Self {
79        Self { bus, address }
80    }
81    pub fn configure(&self) -> Result<(), LinuxI2CError> {
82        let mut dev = LinuxI2CDevice::new(&format!("/dev/i2c-{}", self.bus), self.address)?;
83
84        self.ctrl_humidity(&mut dev)?;
85        self.ctrl_measurement(&mut dev)?;
86
87        let config = T_SB_250 | FILTER_OFF | SPI3W_DI;
88        dev.smbus_write_byte_data(CONFIG as u8, config as u8)?;
89
90        Ok(())
91    }
92    fn ctrl_humidity(&self, dev: &mut LinuxI2CDevice) -> Result<(), LinuxI2CError> {
93        dev.smbus_write_byte_data(CTRL_HUM as u8, OSRS_H_1 as u8)?;
94
95        Ok(())
96    }
97    fn ctrl_measurement(&self, dev: &mut LinuxI2CDevice) -> Result<(), LinuxI2CError> {
98        let config = OSRS_T_1 | OSRS_P_1 | MODE_N;
99        dev.smbus_write_byte_data(CTRL_MEAS as u8, config as u8)?;
100
101        Ok(())
102    }
103    fn reset(&self, dev: &mut LinuxI2CDevice) -> Result<(), LinuxI2CError> {
104        dev.smbus_write_byte_data(RESET as u8, RESET_CODE as u8)?;
105
106        Ok(())
107    }
108    fn read_compensate(&self, dev: &mut LinuxI2CDevice) -> Result<CompensateData, LinuxI2CError> {
109        let mut dig_t = Vec::new();
110        let mut dig_p = Vec::new();
111        let mut dig_h = Vec::new();
112
113        let dat_t = dev.smbus_read_i2c_block_data(TEMP_COMP as u8, 6)?;
114        dig_t.push(((dat_t[1] as u16) << 8) | (dat_t[0] as u16));
115        dig_t.push(((dat_t[3] as u16) << 8) | (dat_t[2] as u16));
116        dig_t.push(((dat_t[5] as u16) << 8) | (dat_t[4] as u16));
117        for i in 1..3 {
118            if dig_t[i] >= 0x8000 {
119                dig_t[i] = 0xFFFF - dig_t[i];
120            }
121        }
122
123        let dat_p = dev.smbus_read_i2c_block_data(PRESS_COMP as u8, 18)?;
124        dig_p.push(((dat_p[1] as u16) << 8) | (dat_p[0] as u16));
125        dig_p.push(((dat_p[3] as u16) << 8) | (dat_p[2] as u16));
126        dig_p.push(((dat_p[5] as u16) << 8) | (dat_p[4] as u16));
127        dig_p.push(((dat_p[7] as u16) << 8) | (dat_p[6] as u16));
128        dig_p.push(((dat_p[9] as u16) << 8) | (dat_p[8] as u16));
129        dig_p.push(((dat_p[11] as u16) << 8) | (dat_p[10] as u16));
130        dig_p.push(((dat_p[13] as u16) << 8) | (dat_p[12] as u16));
131        dig_p.push(((dat_p[15] as u16) << 8) | (dat_p[14] as u16));
132        dig_p.push(((dat_p[17] as u16) << 8) | (dat_p[16] as u16));
133        for i in 1..9 {
134            if dig_p[i] >= 0x8000 {
135                dig_p[i] = 0xFFFF - dig_p[i];
136            }
137        }
138
139        let dh = dev.smbus_read_byte_data(HUM_COMP_1 as u8)?;
140        dig_h.push(dh as u16);
141        let dat_h = dev.smbus_read_i2c_block_data(HUM_COMP_2 as u8, 8)?;
142        dig_h.push(((dat_h[1] as u16) << 8) | (dat_h[0] as u16));
143        dig_h.push(dat_h[2] as u16);
144        dig_h.push(((dat_h[3] as u16) << 4) | 0x0F & (dat_h[4] as u16));
145        dig_h.push(((dat_h[5] as u16) << 4) | (((dat_h[4] as u16) >> 4) & 0x0F));
146        dig_h.push(dat_h[6] as u16);
147        if dig_h[1] >= 0x8000 {
148            dig_h[1] = 0xFFFF - dig_h[1];
149        };
150        for i in 3..5 {
151            if dig_h[i] >= 0x800 {
152                dig_h[i] = 0xFFF - dig_h[i];
153            }
154        }
155        if dig_h[5] >= 0x80 {
156            dig_h[5] = 0xFF - dig_h[5];
157        };
158
159        Ok(
160            CompensateData {
161                dig_t,
162                dig_p,
163                dig_h,
164            }
165        )
166    }
167    pub fn read(&self) -> Result<[f32; 2], LinuxI2CError> {
168        let mut dev = LinuxI2CDevice::new(&format!("/dev/i2c-{}", self.bus), self.address)?;
169
170        let compensate_data = self.read_compensate(&mut dev)?;
171
172        let temp_measurement = self.read_temperature(&mut dev, compensate_data.dig_t)?;
173        let _temperature = temp_measurement[0];
174        let t_fine = temp_measurement[1];
175
176        let pressure = self
177            .read_pressure(&mut dev, t_fine, compensate_data.dig_p)
178            .expect("cannot read pressure from BME280");
179
180        let humidity = self
181            .read_humidity(&mut dev, t_fine, compensate_data.dig_h)
182            .expect("cannot read humidity from BME280");
183
184        let ph = [pressure, humidity];
185
186        Ok(ph)
187    }
188    pub fn read_all(&self) -> Result<[f32; 3], LinuxI2CError> {
189        let mut dev = LinuxI2CDevice::new(&format!("/dev/i2c-{}", self.bus), self.address)?;
190
191        let compensate_data = self.read_compensate(&mut dev)?;
192
193        let temp_measurement = self.read_temperature(&mut dev, compensate_data.dig_t)?;
194        let temperature = temp_measurement[0];
195        let t_fine = temp_measurement[1];
196
197        let pressure = self
198            .read_pressure(&mut dev, t_fine, compensate_data.dig_p)
199            .expect("cannot read pressure from BME280");
200
201        let humidity = self
202            .read_humidity(&mut dev, t_fine, compensate_data.dig_h)
203            .expect("cannot read humidity from BME280");
204
205        let tph = [temperature, pressure, humidity];
206
207        Ok(tph)
208    }
209    fn read_temperature(
210        &self,
211        dev: &mut LinuxI2CDevice,
212        dig_t: Vec<u16>,
213    ) -> Result<[f32; 2], LinuxI2CError> {
214        let temp_msb = dev.smbus_read_byte_data(TEMP_MSB as u8)?;
215        let temp_lsb = dev.smbus_read_byte_data(TEMP_LSB as u8)?;
216        let temp_xlsb = dev.smbus_read_byte_data(TEMP_XLSB as u8)?;
217
218        let temp_adc =
219            ((temp_msb as u32) << 12) | ((temp_lsb as u32) << 4) | ((temp_xlsb as u32) >> 4);
220        let temp_result = self.compensate_temperature(temp_adc, dig_t);
221        let temp = temp_result[0];
222        let t_fine = temp_result[1];
223
224        Ok([temp, t_fine])
225    }
226    fn compensate_temperature(&self, adc: u32, dig_t: Vec<u16>) -> [f32; 2] {
227        let var1 = ((adc as f32) / 8.0 - (dig_t[0] as f32) * 2.0) * (dig_t[1] as f32) / 2048.0;
228        let var2 = ((adc as f32) / 16.0 - (dig_t[0] as f32))
229            * ((adc as f32) / 16.0 - (dig_t[0] as f32))
230            / 4096.0
231            * (dig_t[2] as f32)
232            / 16384.0;
233        let t_fine = var1 + var2;
234
235        let temp = ((t_fine * 5.0 + 128.0) / 256.0) / 100.0;
236
237        [temp, t_fine]
238    }
239    fn read_pressure(
240        &self,
241        dev: &mut LinuxI2CDevice,
242        t_fine: f32,
243        dig_p: Vec<u16>,
244    ) -> Result<f32, LinuxI2CError> {
245        let press_msb = dev.smbus_read_byte_data(PRESS_MSB as u8)?;
246        let press_lsb = dev.smbus_read_byte_data(PRESS_LSB as u8)?;
247        let press_xlsb = dev.smbus_read_byte_data(PRESS_XLSB as u8)?;
248
249        let press_adc =
250            ((press_msb as u32) << 12) | ((press_lsb as u32) << 4) | ((press_xlsb as u32) >> 4);
251        let press = self.compensate_pressure(t_fine, press_adc, dig_p);
252
253        Ok(press)
254    }
255    fn compensate_pressure(&self, t_fine: f32, adc: u32, dig_p: Vec<u16>) -> f32 {
256        let mut var1 = t_fine - 128000.0;
257        let mut var2 = var1 * var1 * (dig_p[5] as f32);
258        var2 = var2 + ((var1 * (dig_p[4] as f32)) * 131072.0);
259        var2 = var2 + ((dig_p[3] as f32) * 34359738370.0);
260        var1 = ((var1 * var1 * (dig_p[2] as f32)) / 256.0) + (var1 * (dig_p[1] as f32)) * 4096.0;
261        var1 = (140737488400000.0 + var1) * ((dig_p[0] as f32) / 8589934592.0);
262
263        if var1 == 0.0 {
264            return 0.0;
265        }
266
267        let mut p = 1048576.0 - (adc as f32);
268        p = ((p * 2147483648.0 - var2) * 3125.0) / var1;
269
270        var1 = ((dig_p[8] as f32) * (p / 8192.0) * (p / 8192.0)) / 33554432.0;
271        var2 = ((dig_p[7] as f32) * p) / 524288.0;
272
273        p = (p + var1 + var2) / 256.0 + (dig_p[6] as f32) * 16.0;
274        p = p / 256.0 / 100.0;
275
276        p
277    }
278    fn read_humidity(
279        &self,
280        dev: &mut LinuxI2CDevice,
281        t_fine: f32,
282        dig_h: Vec<u16>,
283    ) -> Result<f32, LinuxI2CError> {
284        let hum_msb = dev.smbus_read_byte_data(HUM_MSB as u8)?;
285        let hum_lsb = dev.smbus_read_byte_data(HUM_LSB as u8)?;
286
287        let hum_adc = ((hum_msb as u16) << 8) | (hum_lsb as u16);
288        let humidity = self.compensate_humidity(t_fine, hum_adc, dig_h);
289
290        Ok(humidity)
291    }
292    fn compensate_humidity(&self, t_fine: f32, adc: u16, dig_h: Vec<u16>) -> f32 {
293        let mut var_h = t_fine - 76800.0;
294        var_h = ((adc as f32) - ((dig_h[3] as f32) * 64.0 + (dig_h[4] as f32) / 16384.0 * var_h))
295            * ((dig_h[1] as f32) / 65536.0
296                * (1.0
297                    + (dig_h[5] as f32) / 67108864.0
298                        * var_h
299                        * (1.0 + (dig_h[2] as f32) / 67108864.0 * var_h)));
300        var_h = var_h * (1.0 - (dig_h[0] as f32) * var_h / 524288.0);
301
302        var_h
303    }
304}