1use core::cell::Cell;
12use kernel::hil::i2c::{self, I2CClient, I2CDevice};
13use kernel::hil::sensors::{HumidityClient, HumidityDriver, TemperatureClient, TemperatureDriver};
14use kernel::utilities::cells::{OptionalCell, TakeCell};
15use kernel::ErrorCode;
16
17const HUM_MSB: u8 = 0xFD;
18const TEMP_MSB: u8 = 0xFA;
19#[allow(dead_code)]
20const PRESS_MSB: u8 = 0xF7;
21#[allow(dead_code)]
22const CONFIG: u8 = 0xF5;
23const CTRL_MEAS: u8 = 0xF4;
24#[allow(dead_code)]
25const STATUS: u8 = 0xF3;
26const CTRL_HUM: u8 = 0xF2;
27#[allow(dead_code)]
28const CALIB41: u8 = 0xF0;
29const CALIB26: u8 = 0xE1;
30#[allow(dead_code)]
31const RESET: u8 = 0xE0;
32const ID: u8 = 0xD0;
33#[allow(dead_code)]
34const CALIB25: u8 = 0xA1;
35const CALIB00: u8 = 0x88;
36
37#[derive(Clone, Copy, PartialEq)]
38enum DeviceState {
39 Identify,
40 CalibrationLow,
41 CalibrationHigh,
42 Start,
43 Normal,
44}
45
46#[allow(dead_code)]
47#[derive(Clone, Copy, PartialEq)]
48enum Operation {
49 None,
50 Temp,
51 Pressure,
52 Humidity,
53}
54
55#[derive(Clone, Copy, PartialEq, Default)]
56struct CalibrationData {
57 temp1: u16,
58 temp2: u16,
59 temp3: u16,
60
61 press1: u16,
62 press2: u16,
63 press3: u16,
64 press4: u16,
65 press5: u16,
66 press6: u16,
67 press7: u16,
68 press8: u16,
69 press9: u16,
70
71 hum1: u16,
72 hum2: u16,
73 hum3: u16,
74 hum4: u16,
75 hum5: u16,
76 hum6: u16,
77}
78
79pub struct Bme280<'a, I: I2CDevice> {
80 buffer: TakeCell<'static, [u8]>,
81 i2c: &'a I,
82 calibration: Cell<CalibrationData>,
83 temperature_client: OptionalCell<&'a dyn TemperatureClient>,
84 humidity_client: OptionalCell<&'a dyn HumidityClient>,
85 state: Cell<DeviceState>,
86 op: Cell<Operation>,
87 t_fine: Cell<i32>,
88}
89
90impl<'a, I: I2CDevice> Bme280<'a, I> {
91 pub fn new(i2c: &'a I, buffer: &'static mut [u8]) -> Self {
92 Bme280 {
93 buffer: TakeCell::new(buffer),
94 i2c,
95 calibration: Cell::new(CalibrationData::default()),
96 temperature_client: OptionalCell::empty(),
97 humidity_client: OptionalCell::empty(),
98 state: Cell::new(DeviceState::Identify),
99 op: Cell::new(Operation::None),
100 t_fine: Cell::new(0),
101 }
102 }
103
104 pub fn startup(&self) {
105 self.buffer.take().map(|buffer| {
106 if self.state.get() == DeviceState::Identify {
107 buffer[0] = ID;
109 self.i2c.write_read(buffer, 1, 1).unwrap();
110 }
111 });
112 }
113}
114
115impl<'a, I: I2CDevice> TemperatureDriver<'a> for Bme280<'a, I> {
116 fn set_client(&self, client: &'a dyn TemperatureClient) {
117 self.temperature_client.set(client);
118 }
119
120 fn read_temperature(&self) -> Result<(), ErrorCode> {
121 if self.state.get() != DeviceState::Normal {
122 return Err(ErrorCode::BUSY);
123 }
124
125 if self.op.get() != Operation::None {
126 return Err(ErrorCode::BUSY);
127 }
128
129 self.buffer.take().map(|buffer| {
130 buffer[0] = TEMP_MSB;
131
132 self.op.set(Operation::Temp);
133 self.i2c.write_read(buffer, 1, 3).unwrap();
134 });
135
136 Ok(())
137 }
138}
139
140impl<'a, I: I2CDevice> HumidityDriver<'a> for Bme280<'a, I> {
141 fn set_client(&self, client: &'a dyn HumidityClient) {
142 self.humidity_client.set(client);
143 }
144
145 fn read_humidity(&self) -> Result<(), ErrorCode> {
146 if self.state.get() != DeviceState::Normal {
147 return Err(ErrorCode::BUSY);
148 }
149
150 if self.op.get() != Operation::None {
151 return Err(ErrorCode::BUSY);
152 }
153
154 self.buffer.take().map(|buffer| {
155 buffer[0] = HUM_MSB;
156
157 self.op.set(Operation::Humidity);
158 self.i2c.write_read(buffer, 1, 3).unwrap();
159 });
160
161 Ok(())
162 }
163}
164
165impl<I: I2CDevice> I2CClient for Bme280<'_, I> {
166 fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
167 if let Err(i2c_err) = status {
168 match self.op.get() {
170 Operation::None => (),
171 Operation::Temp => {
172 self.temperature_client
173 .map(|client| client.callback(Err(i2c_err.into())));
174 }
175 Operation::Pressure => {
176 unimplemented!();
177 }
178 Operation::Humidity => {
179 self.humidity_client.map(|client| client.callback(0));
180 }
181 }
182 self.buffer.replace(buffer);
183 self.op.set(Operation::None);
184 return;
185 }
186
187 match self.state.get() {
188 DeviceState::Identify => {
189 if buffer[0] != 0x60 {
190 self.buffer.replace(buffer);
193 return;
194 }
195
196 buffer[0] = CALIB00;
197 self.i2c.write_read(buffer, 1, 26).unwrap();
198 self.state.set(DeviceState::CalibrationLow);
199 }
200 DeviceState::CalibrationLow => {
201 let mut calib = self.calibration.take();
202 calib.temp1 = buffer[0] as u16 | (buffer[1] as u16) << 8;
203 calib.temp2 = buffer[2] as u16 | (buffer[3] as u16) << 8;
204 calib.temp3 = buffer[4] as u16 | (buffer[5] as u16) << 8;
205 calib.press1 = buffer[6] as u16 | (buffer[7] as u16) << 8;
206 calib.press2 = buffer[8] as u16 | (buffer[9] as u16) << 8;
207 calib.press3 = buffer[10] as u16 | (buffer[11] as u16) << 8;
208 calib.press4 = buffer[12] as u16 | (buffer[13] as u16) << 8;
209 calib.press5 = buffer[14] as u16 | (buffer[15] as u16) << 8;
210 calib.press6 = buffer[16] as u16 | (buffer[17] as u16) << 8;
211 calib.press7 = buffer[18] as u16 | (buffer[19] as u16) << 8;
212 calib.press8 = buffer[20] as u16 | (buffer[21] as u16) << 8;
213 calib.press9 = buffer[22] as u16 | (buffer[23] as u16) << 8;
214 calib.hum1 = buffer[25] as u16;
215 self.calibration.set(calib);
216
217 if calib.temp1 == 0 || calib.temp2 == 0 || calib.temp3 == 0 {
218 buffer[0] = CALIB00;
221 self.i2c.write_read(buffer, 1, 26).unwrap();
222 self.state.set(DeviceState::CalibrationLow);
223 return;
224 }
225
226 buffer[0] = CALIB26;
227 self.i2c.write_read(buffer, 1, 8).unwrap();
228
229 self.state.set(DeviceState::CalibrationHigh);
230 }
231 DeviceState::CalibrationHigh => {
232 let mut calib = self.calibration.take();
233 calib.hum2 = buffer[0] as u16 | (buffer[1] as u16) << 8;
234 calib.hum3 = buffer[3] as u16;
235 calib.hum4 = buffer[4] as u16 | (buffer[5] as u16) << 4;
236 calib.hum5 = (buffer[6] as u16 >> 4) | (buffer[7] as u16) << 4;
237 calib.hum6 = buffer[8] as u16;
238 self.calibration.set(calib);
239
240 buffer[0] = CTRL_HUM;
242 buffer[1] = 1;
243 self.i2c.write(buffer, 2).unwrap();
244 self.state.set(DeviceState::Start);
245 }
246 DeviceState::Start => {
247 buffer[0] = CTRL_MEAS;
249 buffer[1] = 0x11 | 1 << 5 | 1 << 2;
250 self.i2c.write(buffer, 2).unwrap();
251
252 self.state.set(DeviceState::Normal);
253 }
254 DeviceState::Normal => {
255 match self.op.get() {
256 Operation::None => (),
257 Operation::Temp => {
258 let calib = self.calibration.get();
259
260 let adc_temperature: i32 = ((buffer[0] as usize) << 12
261 | (buffer[1] as usize) << 4
262 | (((buffer[2] as usize) >> 4) & 0x0F))
263 as i32;
264
265 if adc_temperature == 0 {
266 self.buffer.replace(buffer);
268 self.op.set(Operation::None);
269 let _ = self.read_temperature();
270 return;
271 }
272
273 let var1 = (((adc_temperature >> 3) - ((calib.temp1 as i32) << 1))
274 * (calib.temp2 as i32))
275 >> 11;
276 let var2 = (((((adc_temperature >> 4) - (calib.temp1 as i32))
277 * ((adc_temperature >> 4) - (calib.temp1 as i32)))
278 >> 12)
279 * (calib.temp3 as i32))
280 >> 14;
281
282 self.t_fine.set(var1 + var2);
283
284 let temperature = (self.t_fine.get() * 5 + 128) >> 8;
285
286 self.temperature_client
287 .map(|client| client.callback(Ok(temperature)));
288 }
289 Operation::Pressure => {
290 unimplemented!();
291 }
292 Operation::Humidity => {
293 let calib = self.calibration.get();
294 let adc_hum = (((buffer[0] as u32) << 8) | (buffer[1] as u32)) as i32;
295
296 if adc_hum == 0 {
297 self.buffer.replace(buffer);
299 self.op.set(Operation::None);
300 let _ = self.read_humidity();
301 return;
302 }
303
304 let t_fine_offset = self.t_fine.get() - 76800;
305
306 let var1 = ((((adc_hum << 14)
308 - ((calib.hum4 as i32) << 20)
309 - ((calib.hum5 as i32) * t_fine_offset))
310 + 16384)
311 >> 15)
312 * (((((((t_fine_offset * (calib.hum6 as i32)) >> 10)
313 * (((t_fine_offset * (calib.hum3 as i32)) >> 11) + 32768))
314 >> 10)
315 + 2097152)
316 * (calib.hum2 as i32)
317 + 8192)
318 >> 14);
319 let var2 = var1
320 - (((((var1 >> 15) * (var1 >> 15)) >> 7) * (calib.hum1 as i32)) >> 4);
321
322 let var3 = if var2 < 0 { 0 } else { var2 };
323 let var6 = if var3 > 419430400 { 419430400 } else { var3 };
324
325 let hum = (((var6 >> 12) * 100) / 1024) as usize;
326
327 self.humidity_client.map(|client| client.callback(hum));
328 }
329 }
330 self.buffer.replace(buffer);
331 self.op.set(Operation::None);
332 }
333 }
334 }
335}