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 upcalls.schedule_upcall(0, (0, 0, 0)).ok();
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 upcalls
212 .schedule_upcall(0, (into_statuscode(Err(error.into())), 0, 0))
213 .ok();
214 });
215 });
216 } else {
217 self.state.set(State::TakeMeasurementClear);
218 }
219 }
220 State::TakeMeasurementClear => {
221 if let Err((error, buffer)) = self.i2c.read(buffer, 3) {
222 self.state.set(State::Idle);
223 self.buffer.replace(buffer);
224 self.owning_process.map(|pid| {
225 let _ = self.apps.enter(pid, |_app, upcalls| {
226 upcalls
227 .schedule_upcall(0, (into_statuscode(Err(error.into())), 0, 0))
228 .ok();
229 });
230 });
231 } else {
232 self.state.set(State::TakeMeasurementConfigure);
233 }
234 }
235 State::TakeMeasurementConfigure => {
236 buffer[0] = Registers::CtrlReg1 as u8 | REGISTER_AUTO_INCREMENT;
237 buffer[1] = CTRL_REG1_POWER_ON | CTRL_REG1_BLOCK_DATA_ENABLE;
238 buffer[2] = CTRL_REG2_ONE_SHOT;
239
240 if let Err((error, buffer)) = self.i2c.write(buffer, 3) {
241 self.state.set(State::Idle);
242 self.buffer.replace(buffer);
243 self.owning_process.map(|pid| {
244 let _ = self.apps.enter(pid, |_app, upcalls| {
245 upcalls
246 .schedule_upcall(0, (into_statuscode(Err(error.into())), 0, 0))
247 .ok();
248 });
249 });
250 } else {
251 self.state.set(State::Done);
252 }
253 }
254 State::ReadMeasurement => {
255 if let Err((error, buffer)) = self.i2c.read(buffer, 3) {
256 self.state.set(State::Idle);
257 self.buffer.replace(buffer);
258 self.owning_process.map(|pid| {
259 let _ = self.apps.enter(pid, |_app, upcalls| {
260 upcalls
261 .schedule_upcall(0, (into_statuscode(Err(error.into())), 0, 0))
262 .ok();
263 });
264 });
265 } else {
266 self.state.set(State::GotMeasurement);
267 }
268 }
269 State::GotMeasurement => {
270 let pressure =
271 ((buffer[2] as u32) << 16) | ((buffer[1] as u32) << 8) | (buffer[0] as u32);
272
273 let pressure_ubar = (pressure * 1000) / 4096;
275
276 self.owning_process.map(|pid| {
277 let _ = self.apps.enter(pid, |_app, upcalls| {
278 upcalls
279 .schedule_upcall(0, (pressure_ubar as usize, 0, 0))
280 .ok();
281 });
282 });
283
284 buffer[0] = Registers::CtrlReg1 as u8;
285 buffer[1] = 0;
286
287 if let Err((error, buffer)) = self.i2c.write(buffer, 2) {
288 self.state.set(State::Idle);
289 self.buffer.replace(buffer);
290 self.owning_process.map(|pid| {
291 let _ = self.apps.enter(pid, |_app, upcalls| {
292 upcalls
293 .schedule_upcall(0, (into_statuscode(Err(error.into())), 0, 0))
294 .ok();
295 });
296 });
297 } else {
298 self.interrupt_pin.disable_interrupts();
299 self.state.set(State::Done);
300 }
301 }
302 State::Done => {
303 self.buffer.replace(buffer);
304 self.i2c.disable();
305 self.state.set(State::Idle);
306 }
307 _ => {}
308 }
309 }
310}
311
312impl<I: i2c::I2CDevice> gpio::Client for LPS25HB<'_, I> {
313 fn fired(&self) {
314 self.buffer.take().map(|buf| {
315 self.i2c.enable();
317
318 buf[0] = Registers::PressOutXl as u8 | REGISTER_AUTO_INCREMENT;
320
321 if let Err((_error, buf)) = self.i2c.write(buf, 1) {
322 self.buffer.replace(buf);
323 self.i2c.disable();
324 } else {
325 self.state.set(State::ReadMeasurement);
326 }
327 });
328 }
329}
330
331impl<I: i2c::I2CDevice> SyscallDriver for LPS25HB<'_, I> {
332 fn command(
333 &self,
334 command_num: usize,
335 _: usize,
336 _: usize,
337 process_id: ProcessId,
338 ) -> CommandReturn {
339 if command_num == 0 {
340 return CommandReturn::success();
343 }
344 let match_or_empty_or_nonexistant = self.owning_process.map_or(true, |current_process| {
347 self.apps
348 .enter(current_process, |_, _| current_process == process_id)
349 .unwrap_or(true)
350 });
351 if match_or_empty_or_nonexistant {
352 self.owning_process.set(process_id);
353 } else {
354 return CommandReturn::failure(ErrorCode::NOMEM);
355 }
356 match command_num {
357 1 => match self.take_measurement() {
359 Ok(()) => CommandReturn::success(),
360 Err(error) => CommandReturn::failure(error),
361 },
362 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
364 }
365 }
366
367 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
368 self.apps.enter(processid, |_, _| {})
369 }
370}