1use core::cell::Cell;
25
26use kernel::errorcode::into_statuscode;
27use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
28use kernel::hil::gpio;
29use kernel::hil::i2c;
30use kernel::syscall::{CommandReturn, SyscallDriver};
31use kernel::utilities::cells::{OptionalCell, TakeCell};
32use kernel::{ErrorCode, ProcessId};
33
34use capsules_core::driver;
36pub const DRIVER_NUM: usize = driver::NUM::Lps25hb as usize;
37
38pub const BUF_LEN: usize = 5;
40
41const REGISTER_AUTO_INCREMENT: u8 = 0x80;
43
44const CTRL_REG1_POWER_ON: u8 = 0x80;
45const CTRL_REG1_BLOCK_DATA_ENABLE: u8 = 0x04;
46const CTRL_REG2_ONE_SHOT: u8 = 0x01;
47const CTRL_REG4_INTERRUPT1_DATAREADY: u8 = 0x01;
48
49#[allow(dead_code)]
50enum Registers {
51 RefPXl = 0x08,
52 RefPL = 0x09,
53 RefPH = 0x0a,
54 WhoAmI = 0x0f,
55 ResConf = 0x10,
56 CtrlReg1 = 0x20,
57 CtrlReg2 = 0x21,
58 CtrlReg3 = 0x22,
59 CtrlReg4 = 0x23,
60 IntCfgReg = 0x24,
61 IntSourceReg = 0x25,
62 StatusReg = 0x27,
63 PressOutXl = 0x28,
64 PressOutL = 0x29,
65 PressOutH = 0x2a,
66 TempOutL = 0x2b,
67 TempOutH = 0x2c,
68 FifoCtrl = 0x2e,
69 FifoStatus = 0x2f,
70 ThsPL = 0x30,
71 ThsPH = 0x31,
72 RpdsL = 0x39,
73 RpdsH = 0x3a,
74}
75
76#[derive(Clone, Copy, PartialEq)]
78enum State {
79 Idle,
80
81 SelectWhoAmI,
83 ReadingWhoAmI,
84
85 TakeMeasurementInit,
88 TakeMeasurementClear,
91 TakeMeasurementConfigure,
93
94 ReadMeasurement,
96 GotMeasurement,
98
99 Done,
101}
102
103#[derive(Default)]
104pub struct App {}
105
106pub struct LPS25HB<'a, I: i2c::I2CDevice> {
107 i2c: &'a I,
108 interrupt_pin: &'a dyn gpio::InterruptPin<'a>,
109 state: Cell<State>,
110 buffer: TakeCell<'static, [u8]>,
111 apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
112 owning_process: OptionalCell<ProcessId>,
113}
114
115impl<'a, I: i2c::I2CDevice> LPS25HB<'a, I> {
116 pub fn new(
117 i2c: &'a I,
118 interrupt_pin: &'a dyn gpio::InterruptPin<'a>,
119 buffer: &'static mut [u8],
120 apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
121 ) -> Self {
122 Self {
124 i2c,
125 interrupt_pin,
126 state: Cell::new(State::Idle),
127 buffer: TakeCell::new(buffer),
128 apps,
129 owning_process: OptionalCell::empty(),
130 }
131 }
132
133 pub fn read_whoami(&self) -> Result<(), ErrorCode> {
134 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
135 self.i2c.enable();
137
138 buf[0] = Registers::WhoAmI as u8;
139
140 if let Err((_error, buf)) = self.i2c.write(buf, 1) {
141 self.buffer.replace(buf);
142 self.i2c.disable();
143 Err(_error.into())
144 } else {
145 self.state.set(State::SelectWhoAmI);
146 Ok(())
147 }
148 })
149 }
150
151 pub fn take_measurement(&self) -> Result<(), ErrorCode> {
152 self.interrupt_pin.make_input();
153 self.interrupt_pin
154 .enable_interrupts(gpio::InterruptEdge::RisingEdge);
155
156 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
157 self.i2c.enable();
159
160 buf[0] = Registers::CtrlReg1 as u8 | REGISTER_AUTO_INCREMENT;
161 buf[1] = 0;
162 buf[2] = 0;
163 buf[3] = 0;
164 buf[4] = CTRL_REG4_INTERRUPT1_DATAREADY;
165
166 if let Err((_error, buf)) = self.i2c.write(buf, 5) {
167 self.buffer.replace(buf);
168 self.i2c.disable();
169 Err(_error.into())
170 } else {
171 self.state.set(State::TakeMeasurementInit);
172 Ok(())
173 }
174 })
175 }
176}
177
178impl<I: i2c::I2CDevice> i2c::I2CClient for LPS25HB<'_, I> {
179 fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
180 if status != Ok(()) {
181 self.state.set(State::Idle);
182 self.buffer.replace(buffer);
183 self.owning_process.map(|pid| {
184 let _ = self.apps.enter(pid, |_app, upcalls| {
185 let _ = upcalls.schedule_upcall(0, (0, 0, 0));
186 });
187 });
188 return;
189 }
190 match self.state.get() {
191 State::SelectWhoAmI => {
192 if let Err((_error, buffer)) = self.i2c.read(buffer, 1) {
193 self.state.set(State::Idle);
194 self.buffer.replace(buffer);
195 } else {
196 self.state.set(State::ReadingWhoAmI);
197 }
198 }
199 State::ReadingWhoAmI => {
200 self.buffer.replace(buffer);
201 self.i2c.disable();
202 self.state.set(State::Idle);
203 }
204 State::TakeMeasurementInit => {
205 buffer[0] = Registers::PressOutXl as u8 | REGISTER_AUTO_INCREMENT;
206 if let Err((error, buffer)) = self.i2c.write(buffer, 1) {
207 self.state.set(State::Idle);
208 self.buffer.replace(buffer);
209 self.owning_process.map(|pid| {
210 let _ = self.apps.enter(pid, |_app, upcalls| {
211 let _ = upcalls
212 .schedule_upcall(0, (into_statuscode(Err(error.into())), 0, 0));
213 });
214 });
215 } else {
216 self.state.set(State::TakeMeasurementClear);
217 }
218 }
219 State::TakeMeasurementClear => {
220 if let Err((error, buffer)) = self.i2c.read(buffer, 3) {
221 self.state.set(State::Idle);
222 self.buffer.replace(buffer);
223 self.owning_process.map(|pid| {
224 let _ = self.apps.enter(pid, |_app, upcalls| {
225 let _ = upcalls
226 .schedule_upcall(0, (into_statuscode(Err(error.into())), 0, 0));
227 });
228 });
229 } else {
230 self.state.set(State::TakeMeasurementConfigure);
231 }
232 }
233 State::TakeMeasurementConfigure => {
234 buffer[0] = Registers::CtrlReg1 as u8 | REGISTER_AUTO_INCREMENT;
235 buffer[1] = CTRL_REG1_POWER_ON | CTRL_REG1_BLOCK_DATA_ENABLE;
236 buffer[2] = CTRL_REG2_ONE_SHOT;
237
238 if let Err((error, buffer)) = self.i2c.write(buffer, 3) {
239 self.state.set(State::Idle);
240 self.buffer.replace(buffer);
241 self.owning_process.map(|pid| {
242 let _ = self.apps.enter(pid, |_app, upcalls| {
243 let _ = upcalls
244 .schedule_upcall(0, (into_statuscode(Err(error.into())), 0, 0));
245 });
246 });
247 } else {
248 self.state.set(State::Done);
249 }
250 }
251 State::ReadMeasurement => {
252 if let Err((error, buffer)) = self.i2c.read(buffer, 3) {
253 self.state.set(State::Idle);
254 self.buffer.replace(buffer);
255 self.owning_process.map(|pid| {
256 let _ = self.apps.enter(pid, |_app, upcalls| {
257 let _ = upcalls
258 .schedule_upcall(0, (into_statuscode(Err(error.into())), 0, 0));
259 });
260 });
261 } else {
262 self.state.set(State::GotMeasurement);
263 }
264 }
265 State::GotMeasurement => {
266 let pressure =
267 ((buffer[2] as u32) << 16) | ((buffer[1] as u32) << 8) | (buffer[0] as u32);
268
269 let pressure_ubar = (pressure * 1000) / 4096;
271
272 self.owning_process.map(|pid| {
273 let _ = self.apps.enter(pid, |_app, upcalls| {
274 let _ = upcalls.schedule_upcall(0, (pressure_ubar as usize, 0, 0));
275 });
276 });
277
278 buffer[0] = Registers::CtrlReg1 as u8;
279 buffer[1] = 0;
280
281 if let Err((error, buffer)) = self.i2c.write(buffer, 2) {
282 self.state.set(State::Idle);
283 self.buffer.replace(buffer);
284 self.owning_process.map(|pid| {
285 let _ = self.apps.enter(pid, |_app, upcalls| {
286 let _ = upcalls
287 .schedule_upcall(0, (into_statuscode(Err(error.into())), 0, 0));
288 });
289 });
290 } else {
291 self.interrupt_pin.disable_interrupts();
292 self.state.set(State::Done);
293 }
294 }
295 State::Done => {
296 self.buffer.replace(buffer);
297 self.i2c.disable();
298 self.state.set(State::Idle);
299 }
300 _ => {}
301 }
302 }
303}
304
305impl<I: i2c::I2CDevice> gpio::Client for LPS25HB<'_, I> {
306 fn fired(&self) {
307 self.buffer.take().map(|buf| {
308 self.i2c.enable();
310
311 buf[0] = Registers::PressOutXl as u8 | REGISTER_AUTO_INCREMENT;
313
314 if let Err((_error, buf)) = self.i2c.write(buf, 1) {
315 self.buffer.replace(buf);
316 self.i2c.disable();
317 } else {
318 self.state.set(State::ReadMeasurement);
319 }
320 });
321 }
322}
323
324impl<I: i2c::I2CDevice> SyscallDriver for LPS25HB<'_, I> {
325 fn command(
326 &self,
327 command_num: usize,
328 _: usize,
329 _: usize,
330 process_id: ProcessId,
331 ) -> CommandReturn {
332 if command_num == 0 {
333 return CommandReturn::success();
336 }
337 let match_or_empty_or_nonexistant = self.owning_process.map_or(true, |current_process| {
340 self.apps
341 .enter(current_process, |_, _| current_process == process_id)
342 .unwrap_or(true)
343 });
344 if match_or_empty_or_nonexistant {
345 self.owning_process.set(process_id);
346 } else {
347 return CommandReturn::failure(ErrorCode::NOMEM);
348 }
349 match command_num {
350 1 => match self.take_measurement() {
352 Ok(()) => CommandReturn::success(),
353 Err(error) => CommandReturn::failure(error),
354 },
355 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
357 }
358 }
359
360 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
361 self.apps.enter(processid, |_, _| {})
362 }
363}