1use core::cell::Cell;
52use kernel::hil::i2c::{self, I2CClient, I2CDevice};
53use kernel::hil::sensors::{HumidityClient, HumidityDriver, TemperatureClient, TemperatureDriver};
54use kernel::utilities::cells::{OptionalCell, TakeCell};
55use kernel::ErrorCode;
56
57pub struct Hs3003<'a, I: I2CDevice> {
58    buffer: TakeCell<'static, [u8]>,
59    i2c: &'a I,
60    temperature_client: OptionalCell<&'a dyn TemperatureClient>,
61    humidity_client: OptionalCell<&'a dyn HumidityClient>,
62    state: Cell<State>,
63    pending_temperature: Cell<bool>,
64    pending_humidity: Cell<bool>,
65}
66
67impl<'a, I: I2CDevice> Hs3003<'a, I> {
68    pub fn new(i2c: &'a I, buffer: &'static mut [u8]) -> Self {
69        Hs3003 {
70            buffer: TakeCell::new(buffer),
71            i2c,
72            temperature_client: OptionalCell::empty(),
73            humidity_client: OptionalCell::empty(),
74            state: Cell::new(State::Sleep),
75            pending_temperature: Cell::new(false),
76            pending_humidity: Cell::new(false),
77        }
78    }
79
80    pub fn start_reading(&self) -> Result<(), ErrorCode> {
81        self.buffer
82            .take()
83            .map(|buffer| {
84                self.i2c.enable();
85                if let State::Sleep = self.state.get() {
86                    if let Err((_error, buffer)) = self.i2c.write(buffer, 1) {
87                        self.buffer.replace(buffer);
88                        self.i2c.disable();
89                    } else {
90                        self.state.set(State::InitiateReading);
91                    }
92                }
93            })
94            .ok_or(ErrorCode::BUSY)
95    }
96}
97
98impl<'a, I: I2CDevice> TemperatureDriver<'a> for Hs3003<'a, I> {
99    fn set_client(&self, client: &'a dyn TemperatureClient) {
100        self.temperature_client.set(client);
101    }
102
103    fn read_temperature(&self) -> Result<(), ErrorCode> {
104        self.pending_temperature.set(true);
105        if !self.pending_humidity.get() {
106            self.start_reading()
107        } else {
108            Ok(())
109        }
110    }
111}
112
113impl<'a, I: I2CDevice> HumidityDriver<'a> for Hs3003<'a, I> {
114    fn set_client(&self, client: &'a dyn HumidityClient) {
115        self.humidity_client.set(client);
116    }
117
118    fn read_humidity(&self) -> Result<(), ErrorCode> {
119        self.pending_humidity.set(true);
120        if !self.pending_temperature.get() {
121            self.start_reading()
122        } else {
123            Ok(())
124        }
125    }
126}
127
128#[derive(Clone, Copy, Debug)]
129enum State {
130    Sleep,
131    InitiateReading,
132    Read,
133}
134
135impl<I: I2CDevice> I2CClient for Hs3003<'_, I> {
136    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
137        if let Err(i2c_err) = status {
138            self.state.set(State::Sleep);
139            self.buffer.replace(buffer);
140            self.temperature_client
141                .map(|client| client.callback(Err(i2c_err.into())));
142            self.humidity_client.map(|client| client.callback(0));
143            return;
144        }
145
146        match self.state.get() {
147            State::InitiateReading => {
148                if let Err((i2c_err, buffer)) = self.i2c.read(buffer, 4) {
149                    self.state.set(State::Sleep);
150                    self.buffer.replace(buffer);
151                    self.temperature_client
152                        .map(|client| client.callback(Err(i2c_err.into())));
153                    self.humidity_client.map(|client| client.callback(0));
154                } else {
155                    self.state.set(State::Read);
156                }
157            }
158            State::Read => {
159                let humidity_raw = (((buffer[0] & 0x3F) as u16) << 8) | buffer[1] as u16;
160                let humidity = ((humidity_raw as f32 / ((1 << 14) - 1) as f32) * 100.0) as usize;
161
162                let temperature_raw = ((buffer[2] as u16) << 8) | (buffer[3] as u16 >> 2);
163                let temperature = ((((temperature_raw as f32 / ((1 << 14) - 1) as f32) * 165.0)
166                    - 40.0)
167                    / 10.0) as i32;
168
169                self.buffer.replace(buffer);
170                self.i2c.disable();
171                if self.pending_temperature.get() {
172                    self.pending_temperature.set(false);
173                    self.temperature_client
174                        .map(|client| client.callback(Ok(temperature)));
175                }
176                if self.pending_humidity.get() {
177                    self.pending_humidity.set(false);
178                    self.humidity_client.map(|client| client.callback(humidity));
179                }
180
181                self.state.set(State::Sleep);
182            }
183            State::Sleep => {} }
185    }
186}