1use core::cell::Cell;
46use kernel::hil::i2c;
47use kernel::hil::time::{self, ConvertTicks};
48use kernel::utilities::cells::{OptionalCell, TakeCell};
49use kernel::ErrorCode;
50
51#[allow(dead_code)]
52enum Registers {
53 MeasRelativeHumidityHoldMode = 0xe5,
54 MeasRelativeHumidityNoHoldMode = 0xf5,
55 MeasTemperatureHoldMode = 0xe3,
56 MeasTemperatureNoHoldMode = 0xf3,
57 ReadTemperaturePreviousRHMeasurement = 0xe0,
58 Reset = 0xfe,
59 WriteRHTUserRegister1 = 0xe6,
60 ReadRHTUserRegister1 = 0xe7,
61 WriteHeaterControlRegister = 0x51,
62 ReadHeaterControlRegister = 0x11,
63 ReadElectronicIdByteOneA = 0xfa,
64 ReadElectronicIdByteOneB = 0x0f,
65 ReadElectronicIdByteTwoA = 0xfc,
66 ReadElectronicIdByteTwoB = 0xc9,
67 ReadFirmwareVersionA = 0x84,
68 ReadFirmwareVersionB = 0xb8,
69}
70
71#[derive(Clone, Copy, PartialEq)]
73enum State {
74 Idle,
75 WaitTemp,
76 WaitRh,
77
78 SelectElectronicId1,
80 ReadElectronicId1,
81 SelectElectronicId2,
82 ReadElectronicId2,
83
84 TakeTempMeasurementInit,
86 TakeRhMeasurementInit,
87 ReadRhMeasurement,
88 ReadTempMeasurement,
89 GotTempMeasurement,
90 GotRhMeasurement,
91}
92
93#[derive(PartialEq, Eq, Copy, Clone)]
94enum OnDeck {
95 Nothing,
96 Temperature,
97 Humidity,
98}
99
100pub struct SI7021<'a, A: time::Alarm<'a>, I: i2c::I2CDevice> {
101 i2c: &'a I,
102 alarm: &'a A,
103 temp_callback: OptionalCell<&'a dyn kernel::hil::sensors::TemperatureClient>,
104 humidity_callback: OptionalCell<&'a dyn kernel::hil::sensors::HumidityClient>,
105 state: Cell<State>,
106 on_deck: Cell<OnDeck>,
107 buffer: TakeCell<'static, [u8]>,
108}
109
110impl<'a, A: time::Alarm<'a>, I: i2c::I2CDevice> SI7021<'a, A, I> {
111 pub fn new(i2c: &'a I, alarm: &'a A, buffer: &'static mut [u8]) -> SI7021<'a, A, I> {
112 SI7021 {
114 i2c,
115 alarm,
116 temp_callback: OptionalCell::empty(),
117 humidity_callback: OptionalCell::empty(),
118 state: Cell::new(State::Idle),
119 on_deck: Cell::new(OnDeck::Nothing),
120 buffer: TakeCell::new(buffer),
121 }
122 }
123
124 pub fn read_id(&self) {
125 self.buffer.take().map(|buffer| {
126 self.i2c.enable();
128
129 buffer[0] = Registers::ReadElectronicIdByteOneA as u8;
130 buffer[1] = Registers::ReadElectronicIdByteOneB as u8;
131 let _ = self.i2c.write(buffer, 2);
133 self.state.set(State::SelectElectronicId1);
134 });
135 }
136
137 fn init_measurement(&self, buffer: &'static mut [u8]) {
138 let delay = self.alarm.ticks_from_ms(20);
139 self.alarm.set_alarm(self.alarm.now(), delay);
140
141 self.buffer.replace(buffer);
143 self.i2c.disable();
144 }
145
146 fn set_idle(&self, buffer: &'static mut [u8]) {
147 self.buffer.replace(buffer);
148 self.i2c.disable();
149 self.state.set(State::Idle);
150 }
151}
152
153impl<'a, A: time::Alarm<'a>, I: i2c::I2CDevice> i2c::I2CClient for SI7021<'a, A, I> {
154 fn command_complete(&self, buffer: &'static mut [u8], _status: Result<(), i2c::Error>) {
155 match self.state.get() {
156 State::SelectElectronicId1 => {
157 let _ = self.i2c.read(buffer, 8);
159 self.state.set(State::ReadElectronicId1);
160 }
161 State::ReadElectronicId1 => {
162 buffer[6] = buffer[0];
163 buffer[7] = buffer[1];
164 buffer[8] = buffer[2];
165 buffer[9] = buffer[3];
166 buffer[10] = buffer[4];
167 buffer[11] = buffer[5];
168 buffer[12] = buffer[6];
169 buffer[13] = buffer[7];
170 buffer[0] = Registers::ReadElectronicIdByteTwoA as u8;
171 buffer[1] = Registers::ReadElectronicIdByteTwoB as u8;
172 let _ = self.i2c.write(buffer, 2);
174 self.state.set(State::SelectElectronicId2);
175 }
176 State::SelectElectronicId2 => {
177 let _ = self.i2c.read(buffer, 6);
179 self.state.set(State::ReadElectronicId2);
180 }
181 State::ReadElectronicId2 => {
182 self.set_idle(buffer);
183 }
184 State::TakeTempMeasurementInit => {
185 self.init_measurement(buffer);
186 self.state.set(State::WaitTemp);
187 }
188 State::TakeRhMeasurementInit => {
189 self.init_measurement(buffer);
190 self.state.set(State::WaitRh);
191 }
192 State::ReadRhMeasurement => {
193 let _ = self.i2c.read(buffer, 2);
195 self.state.set(State::GotRhMeasurement);
196 }
197 State::ReadTempMeasurement => {
198 let _ = self.i2c.read(buffer, 2);
200 self.state.set(State::GotTempMeasurement);
201 }
202 State::GotTempMeasurement => {
203 let temp_raw = ((buffer[0] as u32) << 8) | (buffer[1] as u32);
205 let temp = ((temp_raw * 17572) / 65536) as i32 - 4685;
206
207 self.temp_callback.map(|cb| cb.callback(Ok(temp)));
208
209 match self.on_deck.get() {
210 OnDeck::Humidity => {
211 self.on_deck.set(OnDeck::Nothing);
212 buffer[0] = Registers::MeasRelativeHumidityNoHoldMode as u8;
213 let _ = self.i2c.write(buffer, 1);
215 self.state.set(State::TakeRhMeasurementInit);
216 }
217 _ => {
218 self.set_idle(buffer);
219 }
220 }
221 }
222 State::GotRhMeasurement => {
223 let humidity_raw = ((buffer[0] as u32) << 8) | (buffer[1] as u32);
225 let humidity = (((humidity_raw * 125 * 100) / 65536) - 600) as u16;
226
227 self.humidity_callback
228 .map(|cb| cb.callback(humidity as usize));
229 match self.on_deck.get() {
230 OnDeck::Temperature => {
231 self.on_deck.set(OnDeck::Nothing);
232 buffer[0] = Registers::MeasTemperatureNoHoldMode as u8;
233 let _ = self.i2c.write(buffer, 1);
235 self.state.set(State::TakeTempMeasurementInit);
236 }
237 _ => {
238 self.set_idle(buffer);
239 }
240 }
241 }
242 _ => {}
243 }
244 }
245}
246
247impl<'a, A: time::Alarm<'a>, I: i2c::I2CDevice> kernel::hil::sensors::TemperatureDriver<'a>
248 for SI7021<'a, A, I>
249{
250 fn read_temperature(&self) -> Result<(), ErrorCode> {
251 if self.state.get() == State::Idle {
256 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
257 self.i2c.enable();
259
260 buffer[0] = Registers::MeasTemperatureNoHoldMode as u8;
261 let _ = self.i2c.write(buffer, 1);
263 self.state.set(State::TakeTempMeasurementInit);
264 Ok(())
265 })
266 } else {
267 if self.on_deck.get() == OnDeck::Nothing {
269 self.on_deck.set(OnDeck::Temperature);
270 Ok(())
271 } else {
272 Err(ErrorCode::BUSY)
273 }
274 }
275 }
276
277 fn set_client(&self, client: &'a dyn kernel::hil::sensors::TemperatureClient) {
278 self.temp_callback.set(client);
279 }
280}
281
282impl<'a, A: time::Alarm<'a>, I: i2c::I2CDevice> kernel::hil::sensors::HumidityDriver<'a>
283 for SI7021<'a, A, I>
284{
285 fn read_humidity(&self) -> Result<(), ErrorCode> {
286 if self.state.get() == State::Idle {
291 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
292 self.i2c.enable();
294
295 buffer[0] = Registers::MeasRelativeHumidityNoHoldMode as u8;
296 let _ = self.i2c.write(buffer, 1);
298 self.state.set(State::TakeRhMeasurementInit);
299 Ok(())
300 })
301 } else {
302 if self.on_deck.get() == OnDeck::Nothing {
305 self.on_deck.set(OnDeck::Humidity);
306 Ok(())
307 } else {
308 Err(ErrorCode::BUSY)
309 }
310 }
311 }
312
313 fn set_client(&self, client: &'a dyn kernel::hil::sensors::HumidityClient) {
314 self.humidity_callback.set(client);
315 }
316}
317
318impl<'a, A: time::Alarm<'a>, I: i2c::I2CDevice> time::AlarmClient for SI7021<'a, A, I> {
319 fn alarm(&self) {
320 self.buffer.take().map(|buffer| {
321 self.i2c.enable();
323
324 let _ = self.i2c.read(buffer, 2);
326 match self.state.get() {
327 State::WaitRh => self.state.set(State::ReadRhMeasurement),
328 State::WaitTemp => self.state.set(State::ReadTempMeasurement),
329 _ => (),
330 }
331 });
332 }
333}