1use core::cell::Cell;
12use kernel::ErrorCode;
13use kernel::hil::i2c;
14use kernel::hil::time::{self, Alarm, ConvertTicks};
15use kernel::utilities::cells::{OptionalCell, TakeCell};
16
17pub const BASE_ADDR: u8 = 0x70;
19
20mod command {
23 pub const WAKEUP: u16 = 0x3517;
26 pub const SLEEP: u16 = 0xB098;
28 pub const MEASURE_NORMAL_T_FIRST_NO_STRETCH: u16 = 0x7866;
34}
35
36const WAKE_UP_DELAY_MS: u32 = 1;
42
43const MEASURING_DELAY_MS: u32 = 15;
47
48const MEASUREMENT_LEN: usize = 6;
51
52fn crc8(data: &[u8]) -> u8 {
56 let polynomial = 0x31;
57 let mut crc = 0xff;
58
59 for &byte in data {
60 crc ^= byte;
61 for _ in 0..8 {
62 if (crc & 0x80) != 0 {
63 crc = crc << 1 ^ polynomial;
64 } else {
65 crc <<= 1;
66 }
67 }
68 }
69 crc
70}
71
72#[derive(Clone, Copy, PartialEq)]
73enum State {
74 Idle,
75 Waking,
77 WakeDelay,
80 Measuring,
82 MeasuringDelay,
84 ReadingMeasurement,
86 Sleeping,
88}
89
90pub struct Shtc3<'a, A: Alarm<'a>, I: i2c::I2CDevice<'a>> {
91 i2c: &'a I,
92 alarm: &'a A,
93 humidity_client: OptionalCell<&'a dyn kernel::hil::sensors::HumidityClient>,
94 temperature_client: OptionalCell<&'a dyn kernel::hil::sensors::TemperatureClient>,
95 state: Cell<State>,
96 buffer: TakeCell<'static, [u8]>,
97
98 temperature_wanted: Cell<bool>,
100 humidity_wanted: Cell<bool>,
102 pending_temperature: Cell<Option<Result<i32, ErrorCode>>>,
104 pending_humidity: Cell<Option<usize>>,
106}
107
108impl<'a, A: Alarm<'a>, I: i2c::I2CDevice<'a>> Shtc3<'a, A, I> {
109 pub fn new(i2c: &'a I, buffer: &'static mut [u8], alarm: &'a A) -> Shtc3<'a, A, I> {
110 Shtc3 {
111 i2c,
112 alarm,
113 humidity_client: OptionalCell::empty(),
114 temperature_client: OptionalCell::empty(),
115 state: Cell::new(State::Idle),
116 buffer: TakeCell::new(buffer),
117 temperature_wanted: Cell::new(false),
118 humidity_wanted: Cell::new(false),
119 pending_temperature: Cell::new(None),
120 pending_humidity: Cell::new(None),
121 }
122 }
123
124 fn read_temperature(&self) -> Result<(), ErrorCode> {
125 if self.temperature_wanted.get() {
126 Err(ErrorCode::BUSY)
127 } else if self.state.get() == State::Idle {
128 let result = self.start_measurement();
129 if result.is_ok() {
130 self.temperature_wanted.set(true);
131 }
132 result
133 } else {
134 self.temperature_wanted.set(true);
135 Ok(())
136 }
137 }
138
139 fn read_humidity(&self) -> Result<(), ErrorCode> {
140 if self.humidity_wanted.get() {
141 Err(ErrorCode::BUSY)
142 } else if self.state.get() == State::Idle {
143 let result = self.start_measurement();
144 if result.is_ok() {
145 self.humidity_wanted.set(true);
146 }
147 result
148 } else {
149 self.humidity_wanted.set(true);
150 Ok(())
151 }
152 }
153
154 fn write_command(&self, command: u16) -> Result<(), ErrorCode> {
157 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
158 buffer[0] = (command >> 8) as u8;
159 buffer[1] = (command & 0xff) as u8;
160
161 match self.i2c.write(buffer, 2) {
162 Ok(()) => Ok(()),
163 Err((error, data)) => {
164 self.buffer.replace(data);
165 Err(error.into())
166 }
167 }
168 })
169 }
170
171 fn read_measurement(&self) -> Result<(), ErrorCode> {
172 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
173 match self.i2c.read(buffer, MEASUREMENT_LEN) {
174 Ok(()) => Ok(()),
175 Err((error, data)) => {
176 self.buffer.replace(data);
177 Err(error.into())
178 }
179 }
180 })
181 }
182
183 fn start_measurement(&self) -> Result<(), ErrorCode> {
184 self.i2c.enable();
185 self.state.set(State::Waking);
186
187 let result = self.write_command(command::WAKEUP);
188 if result.is_err() {
189 self.state.set(State::Idle);
190 self.i2c.disable();
191 }
192 result
193 }
194
195 fn abort(&self, error: ErrorCode) {
199 if self.temperature_wanted.get() {
200 self.pending_temperature.set(Some(Err(error)));
201 }
202 if self.humidity_wanted.get() {
203 self.pending_humidity.set(Some(usize::MAX));
204 }
205
206 self.finish();
207 }
208
209 fn store_measurement(&self) {
212 self.buffer.map(|buffer| {
213 let result = if crc8(&buffer[0..2]) == buffer[2] {
214 let raw = ((buffer[0] as u32) << 8) | (buffer[1] as u32);
215 Ok(((4375 * raw) >> 14) as i32 - 4500)
217 } else {
218 Err(ErrorCode::FAIL)
219 };
220 self.pending_temperature.set(Some(result));
221
222 let value = if crc8(&buffer[3..5]) == buffer[5] {
223 let raw = ((buffer[3] as u32) << 8) | (buffer[4] as u32);
224 ((625 * raw) >> 12) as usize
226 } else {
227 usize::MAX
228 };
229 self.pending_humidity.set(Some(value));
230 });
231 }
232
233 fn deliver_pending(&self) {
236 if self.temperature_wanted.get() {
237 self.temperature_wanted.set(false);
238 if let Some(result) = self.pending_temperature.take() {
239 self.temperature_client
240 .map(|client| client.callback(result));
241 }
242 }
243 if self.humidity_wanted.get() {
244 self.humidity_wanted.set(false);
245 if let Some(value) = self.pending_humidity.take() {
246 self.humidity_client.map(|client| client.callback(value));
247 }
248 }
249 }
250
251 fn finish(&self) {
254 self.i2c.disable();
255 self.state.set(State::Idle);
256 self.deliver_pending();
257 }
258
259 fn continue_state_machine(&self) {
260 match self.state.get() {
261 State::Idle => {}
262 State::Waking => {
263 self.state.set(State::WakeDelay);
264 self.alarm
265 .set_alarm(self.alarm.now(), self.alarm.ticks_from_ms(WAKE_UP_DELAY_MS));
266 }
267 State::WakeDelay => {
268 let res = self.write_command(command::MEASURE_NORMAL_T_FIRST_NO_STRETCH);
269 if let Err(error) = res {
270 self.abort(error);
271 } else {
272 self.state.set(State::Measuring);
273 }
274 }
275 State::Measuring => {
276 self.state.set(State::MeasuringDelay);
277 self.alarm.set_alarm(
278 self.alarm.now(),
279 self.alarm.ticks_from_ms(MEASURING_DELAY_MS),
280 );
281 }
282 State::MeasuringDelay => {
283 let res = self.read_measurement();
284 if let Err(error) = res {
285 self.abort(error);
286 } else {
287 self.state.set(State::ReadingMeasurement);
288 }
289 }
290 State::ReadingMeasurement => {
291 self.store_measurement();
292
293 let res = self.write_command(command::SLEEP);
294 if let Err(_error) = res {
295 self.finish();
296 } else {
297 self.state.set(State::Sleeping);
298 }
299 }
300 State::Sleeping => {
301 self.finish();
302 }
303 }
304 }
305}
306
307impl<'a, A: Alarm<'a>, I: i2c::I2CDevice<'a>> time::AlarmClient for Shtc3<'a, A, I> {
308 fn alarm(&self) {
309 self.continue_state_machine();
310 }
311}
312
313impl<'a, A: Alarm<'a>, I: i2c::I2CDevice<'a>> i2c::I2CClient for Shtc3<'a, A, I> {
314 fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
315 self.buffer.replace(buffer);
316
317 if let Err(error) = status {
318 if self.state.get() == State::Sleeping {
319 self.finish();
323 } else {
324 self.abort(error.into());
325 }
326 } else {
327 self.continue_state_machine();
328 }
329 }
330}
331
332impl<'a, A: Alarm<'a>, I: i2c::I2CDevice<'a>> kernel::hil::sensors::TemperatureDriver<'a>
333 for Shtc3<'a, A, I>
334{
335 fn set_client(&self, client: &'a dyn kernel::hil::sensors::TemperatureClient) {
336 self.temperature_client.set(client);
337 }
338
339 fn read_temperature(&self) -> Result<(), ErrorCode> {
340 self.read_temperature()
341 }
342}
343
344impl<'a, A: Alarm<'a>, I: i2c::I2CDevice<'a>> kernel::hil::sensors::HumidityDriver<'a>
345 for Shtc3<'a, A, I>
346{
347 fn set_client(&self, client: &'a dyn kernel::hil::sensors::HumidityClient) {
348 self.humidity_client.set(client);
349 }
350
351 fn read_humidity(&self) -> Result<(), ErrorCode> {
352 self.read_humidity()
353 }
354}