1#![allow(non_camel_case_types)]
84
85use core::cell::Cell;
86
87use enum_primitive::cast::FromPrimitive;
88use enum_primitive::enum_from_primitive;
89
90use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
91use kernel::hil::i2c;
92use kernel::hil::sensors;
93use kernel::syscall::{CommandReturn, SyscallDriver};
94use kernel::utilities::cells::{OptionalCell, TakeCell};
95use kernel::{ErrorCode, ProcessId};
96
97use crate::lsm303xx::{
98 AccelerometerRegisters, Lsm303AccelDataRate, Lsm303MagnetoDataRate, Lsm303Range, Lsm303Scale,
99 CTRL_REG1, CTRL_REG4, RANGE_FACTOR_X_Y, RANGE_FACTOR_Z, SCALE_FACTOR,
100};
101
102use capsules_core::driver;
103
104pub const DRIVER_NUM: usize = driver::NUM::Lsm303dlch as usize;
106
107const REGISTER_AUTO_INCREMENT: u8 = 0x80;
109
110enum_from_primitive! {
111 enum MagnetometerRegisters {
112 CRA_REG_M = 0x00,
113 CRB_REG_M = 0x01,
114 OUT_X_H_M = 0x03,
115 OUT_X_L_M = 0x04,
116 OUT_Z_H_M = 0x05,
117 OUT_Z_L_M = 0x06,
118 OUT_Y_H_M = 0x07,
119 OUT_Y_L_M = 0x08,
120 TEMP_OUT_H_M = 0x31,
121 TEMP_OUT_L_M = 0x32,
122 }
123}
124
125const TEMP_OFFSET: i32 = 17;
127
128#[derive(Clone, Copy, PartialEq)]
129enum State {
130 Idle,
131 IsPresent,
132 SetPowerMode,
133 SetScaleAndResolution,
134 ReadAccelerationXYZ,
135 SetTemperatureDataRate,
136 SetRange,
137 ReadTemperature,
138 ReadMagnetometerXYZ,
139}
140
141pub struct Lsm303dlhcI2C<'a, I: i2c::I2CDevice> {
142 config_in_progress: Cell<bool>,
143 i2c_accelerometer: &'a I,
144 i2c_magnetometer: &'a I,
145 state: Cell<State>,
146 accel_scale: Cell<Lsm303Scale>,
147 mag_range: Cell<Lsm303Range>,
148 accel_high_resolution: Cell<bool>,
149 mag_data_rate: Cell<Lsm303MagnetoDataRate>,
150 accel_data_rate: Cell<Lsm303AccelDataRate>,
151 low_power: Cell<bool>,
152 temperature: Cell<bool>,
153 buffer: TakeCell<'static, [u8]>,
154 nine_dof_client: OptionalCell<&'a dyn sensors::NineDofClient>,
155 temperature_client: OptionalCell<&'a dyn sensors::TemperatureClient>,
156 current_process: OptionalCell<ProcessId>,
157 apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
158}
159
160#[derive(Default)]
161pub struct App {}
162
163impl<'a, I: i2c::I2CDevice> Lsm303dlhcI2C<'a, I> {
164 pub fn new(
165 i2c_accelerometer: &'a I,
166 i2c_magnetometer: &'a I,
167 buffer: &'static mut [u8],
168 grant: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
169 ) -> Lsm303dlhcI2C<'a, I> {
170 Lsm303dlhcI2C {
172 config_in_progress: Cell::new(false),
173 i2c_accelerometer,
174 i2c_magnetometer,
175 state: Cell::new(State::Idle),
176 accel_scale: Cell::new(Lsm303Scale::Scale2G),
177 mag_range: Cell::new(Lsm303Range::Range1G),
178 accel_high_resolution: Cell::new(false),
179 mag_data_rate: Cell::new(Lsm303MagnetoDataRate::DataRate0_75Hz),
180 accel_data_rate: Cell::new(Lsm303AccelDataRate::DataRate1Hz),
181 low_power: Cell::new(false),
182 temperature: Cell::new(false),
183 buffer: TakeCell::new(buffer),
184 nine_dof_client: OptionalCell::empty(),
185 temperature_client: OptionalCell::empty(),
186 current_process: OptionalCell::empty(),
187 apps: grant,
188 }
189 }
190
191 pub fn configure(
192 &self,
193 accel_data_rate: Lsm303AccelDataRate,
194 low_power: bool,
195 accel_scale: Lsm303Scale,
196 accel_high_resolution: bool,
197 temperature: bool,
198 mag_data_rate: Lsm303MagnetoDataRate,
199 mag_range: Lsm303Range,
200 ) -> Result<(), ErrorCode> {
201 if self.state.get() == State::Idle {
202 self.config_in_progress.set(true);
203
204 self.accel_scale.set(accel_scale);
205 self.accel_high_resolution.set(accel_high_resolution);
206 self.temperature.set(temperature);
207 self.mag_data_rate.set(mag_data_rate);
208 self.mag_range.set(mag_range);
209 self.accel_data_rate.set(accel_data_rate);
210 self.low_power.set(low_power);
211
212 self.set_power_mode(accel_data_rate, low_power)
213 } else {
214 Err(ErrorCode::BUSY)
215 }
216 }
217
218 fn is_present(&self) -> Result<(), ErrorCode> {
219 if self.state.get() != State::Idle {
220 self.state.set(State::IsPresent);
221 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
222 buf[0] = 0x0F;
224 self.i2c_magnetometer.enable();
225 if let Err((error, buf)) = self.i2c_magnetometer.write_read(buf, 1, 1) {
226 self.buffer.replace(buf);
227 self.state.set(State::Idle);
228 Err(error.into())
229 } else {
230 Ok(())
231 }
232 })
233 } else {
234 Err(ErrorCode::BUSY)
235 }
236 }
237
238 fn set_power_mode(
239 &self,
240 data_rate: Lsm303AccelDataRate,
241 low_power: bool,
242 ) -> Result<(), ErrorCode> {
243 if self.state.get() == State::Idle {
244 self.state.set(State::SetPowerMode);
245 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
246 buf[0] = AccelerometerRegisters::CTRL_REG1 as u8;
247 buf[1] = (CTRL_REG1::ODR.val(data_rate as u8)
248 + CTRL_REG1::LPEN.val(low_power as u8)
249 + CTRL_REG1::ZEN::SET
250 + CTRL_REG1::YEN::SET
251 + CTRL_REG1::XEN::SET)
252 .value;
253 self.i2c_accelerometer.enable();
254 if let Err((error, buf)) = self.i2c_accelerometer.write(buf, 2) {
255 self.state.set(State::Idle);
256 self.buffer.replace(buf);
257 Err(error.into())
258 } else {
259 Ok(())
260 }
261 })
262 } else {
263 Err(ErrorCode::BUSY)
264 }
265 }
266
267 fn set_scale_and_resolution(
268 &self,
269 scale: Lsm303Scale,
270 high_resolution: bool,
271 ) -> Result<(), ErrorCode> {
272 if self.state.get() == State::Idle {
273 self.state.set(State::SetScaleAndResolution);
274 self.accel_scale.set(scale);
276 self.accel_high_resolution.set(high_resolution);
277 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
278 buf[0] = AccelerometerRegisters::CTRL_REG4 as u8;
279 buf[1] = (CTRL_REG4::FS.val(scale as u8)
280 + CTRL_REG4::HR.val(high_resolution as u8))
281 .value;
282 self.i2c_accelerometer.enable();
283 if let Err((error, buf)) = self.i2c_accelerometer.write(buf, 2) {
284 self.state.set(State::Idle);
285 self.buffer.replace(buf);
286 Err(error.into())
287 } else {
288 Ok(())
289 }
290 })
291 } else {
292 Err(ErrorCode::BUSY)
293 }
294 }
295
296 fn read_acceleration_xyz(&self) -> Result<(), ErrorCode> {
297 if self.state.get() == State::Idle {
298 self.state.set(State::ReadAccelerationXYZ);
299 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
300 buf[0] = AccelerometerRegisters::OUT_X_L_A as u8 | REGISTER_AUTO_INCREMENT;
301 self.i2c_accelerometer.enable();
302 if let Err((error, buf)) = self.i2c_accelerometer.write_read(buf, 1, 6) {
303 self.state.set(State::Idle);
304 self.buffer.replace(buf);
305 Err(error.into())
306 } else {
307 Ok(())
308 }
309 })
310 } else {
311 Err(ErrorCode::BUSY)
312 }
313 }
314
315 fn set_temperature_and_magneto_data_rate(
316 &self,
317 temperature: bool,
318 data_rate: Lsm303MagnetoDataRate,
319 ) -> Result<(), ErrorCode> {
320 if self.state.get() == State::Idle {
321 self.state.set(State::SetTemperatureDataRate);
322 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
323 buf[0] = MagnetometerRegisters::CRA_REG_M as u8;
324 buf[1] = ((data_rate as u8) << 2) | if temperature { 1 << 7 } else { 0 };
325 self.i2c_magnetometer.enable();
326 if let Err((error, buf)) = self.i2c_magnetometer.write(buf, 2) {
327 self.state.set(State::Idle);
328 self.buffer.replace(buf);
329 Err(error.into())
330 } else {
331 Ok(())
332 }
333 })
334 } else {
335 Err(ErrorCode::BUSY)
336 }
337 }
338
339 fn set_range(&self, range: Lsm303Range) -> Result<(), ErrorCode> {
340 if self.state.get() == State::Idle {
341 self.state.set(State::SetRange);
342 self.mag_range.set(range);
344 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
345 buf[0] = MagnetometerRegisters::CRB_REG_M as u8;
346 buf[1] = (range as u8) << 5;
347 buf[2] = 0;
348 self.i2c_magnetometer.enable();
349 if let Err((error, buf)) = self.i2c_magnetometer.write(buf, 3) {
350 self.state.set(State::Idle);
351 self.buffer.replace(buf);
352 Err(error.into())
353 } else {
354 Ok(())
355 }
356 })
357 } else {
358 Err(ErrorCode::BUSY)
359 }
360 }
361
362 fn read_temperature(&self) -> Result<(), ErrorCode> {
363 if self.state.get() == State::Idle {
364 self.state.set(State::ReadTemperature);
365 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
366 buf[0] = MagnetometerRegisters::TEMP_OUT_H_M as u8;
367 self.i2c_magnetometer.enable();
368 if let Err((error, buf)) = self.i2c_magnetometer.write_read(buf, 1, 2) {
369 self.state.set(State::Idle);
370 self.buffer.replace(buf);
371 Err(error.into())
372 } else {
373 Ok(())
374 }
375 })
376 } else {
377 Err(ErrorCode::BUSY)
378 }
379 }
380
381 fn read_magnetometer_xyz(&self) -> Result<(), ErrorCode> {
382 if self.state.get() == State::Idle {
383 self.state.set(State::ReadMagnetometerXYZ);
384 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
385 buf[0] = MagnetometerRegisters::OUT_X_H_M as u8;
386 self.i2c_magnetometer.enable();
387 if let Err((error, buf)) = self.i2c_magnetometer.write_read(buf, 1, 6) {
388 self.state.set(State::Idle);
389 self.buffer.replace(buf);
390 Err(error.into())
391 } else {
392 Ok(())
393 }
394 })
395 } else {
396 Err(ErrorCode::BUSY)
397 }
398 }
399}
400
401impl<I: i2c::I2CDevice> i2c::I2CClient for Lsm303dlhcI2C<'_, I> {
402 fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
403 match self.state.get() {
404 State::IsPresent => {
405 let present = status.is_ok() && buffer[0] == 60;
406
407 self.current_process.map(|process_id| {
408 let _ = self.apps.enter(process_id, |_grant, upcalls| {
409 upcalls
410 .schedule_upcall(0, (usize::from(present), 0, 0))
411 .ok();
412 });
413 });
414
415 self.buffer.replace(buffer);
416 self.i2c_magnetometer.disable();
417 self.state.set(State::Idle);
418 }
419 State::SetPowerMode => {
420 let set_power = status == Ok(());
421
422 self.current_process.map(|process_id| {
423 let _ = self.apps.enter(process_id, |_grant, upcalls| {
424 upcalls
425 .schedule_upcall(0, (usize::from(set_power), 0, 0))
426 .ok();
427 });
428 });
429
430 self.buffer.replace(buffer);
431 self.i2c_accelerometer.disable();
432 self.state.set(State::Idle);
433 if self.config_in_progress.get() {
434 let _ = self.set_scale_and_resolution(
435 self.accel_scale.get(),
436 self.accel_high_resolution.get(),
437 );
438 }
439 }
440 State::SetScaleAndResolution => {
441 let set_scale_and_resolution = status == Ok(());
442
443 self.current_process.map(|process_id| {
444 let _ = self.apps.enter(process_id, |_grant, upcalls| {
445 upcalls
446 .schedule_upcall(0, (usize::from(set_scale_and_resolution), 0, 0))
447 .ok();
448 });
449 });
450
451 self.buffer.replace(buffer);
452 self.i2c_accelerometer.disable();
453 self.state.set(State::Idle);
454 if self.config_in_progress.get() {
455 if let Err(_error) = self.set_temperature_and_magneto_data_rate(
456 self.temperature.get(),
457 self.mag_data_rate.get(),
458 ) {
459 self.config_in_progress.set(false);
460 }
461 }
462 }
463 State::ReadAccelerationXYZ => {
464 let mut x: usize = 0;
465 let mut y: usize = 0;
466 let mut z: usize = 0;
467 let values = if status == Ok(()) {
468 self.nine_dof_client.map(|client| {
469 let scale_factor = self.accel_scale.get() as usize;
471 x = (((buffer[0] as i16 | ((buffer[1] as i16) << 8)) as i32)
472 * (SCALE_FACTOR[scale_factor] as i32)
473 * 1000
474 / 32768) as usize;
475 y = (((buffer[2] as i16 | ((buffer[3] as i16) << 8)) as i32)
476 * (SCALE_FACTOR[scale_factor] as i32)
477 * 1000
478 / 32768) as usize;
479 z = (((buffer[4] as i16 | ((buffer[5] as i16) << 8)) as i32)
480 * (SCALE_FACTOR[scale_factor] as i32)
481 * 1000
482 / 32768) as usize;
483 client.callback(x, y, z);
484 });
485
486 x = (buffer[0] as i16 | ((buffer[1] as i16) << 8)) as usize;
487 y = (buffer[2] as i16 | ((buffer[3] as i16) << 8)) as usize;
488 z = (buffer[4] as i16 | ((buffer[5] as i16) << 8)) as usize;
489 true
490 } else {
491 self.nine_dof_client.map(|client| {
492 client.callback(0, 0, 0);
493 });
494 false
495 };
496
497 self.current_process.map(|process_id| {
498 let _ = self.apps.enter(process_id, |_grant, upcalls| {
499 if values {
500 upcalls.schedule_upcall(0, (x, y, z)).ok();
501 } else {
502 upcalls.schedule_upcall(0, (0, 0, 0)).ok();
503 }
504 });
505 });
506
507 self.buffer.replace(buffer);
508 self.i2c_accelerometer.disable();
509 self.state.set(State::Idle);
510 }
511 State::SetTemperatureDataRate => {
512 let set_temperature_and_magneto_data_rate = status == Ok(());
513
514 self.current_process.map(|process_id| {
515 let _ = self.apps.enter(process_id, |_grant, upcalls| {
516 upcalls
517 .schedule_upcall(
518 0,
519 (usize::from(set_temperature_and_magneto_data_rate), 0, 0),
520 )
521 .ok();
522 });
523 });
524
525 self.buffer.replace(buffer);
526 self.i2c_magnetometer.disable();
527 self.state.set(State::Idle);
528 if self.config_in_progress.get() {
529 if let Err(_error) = self.set_range(self.mag_range.get()) {
530 self.config_in_progress.set(false);
531 }
532 }
533 }
534 State::SetRange => {
535 let set_range = status == Ok(());
536
537 self.current_process.map(|process_id| {
538 let _ = self.apps.enter(process_id, |_grant, upcalls| {
539 upcalls
540 .schedule_upcall(0, (usize::from(set_range), 0, 0))
541 .ok();
542 });
543 });
544
545 if self.config_in_progress.get() {
546 self.config_in_progress.set(false);
547 }
548 self.buffer.replace(buffer);
549 self.i2c_magnetometer.disable();
550 self.state.set(State::Idle);
551 }
552 State::ReadTemperature => {
553 let values = match status {
554 Ok(()) => Ok(
555 ((buffer[1] as i16 | ((buffer[0] as i16) << 8)) >> 4) as i32 / 8
556 + TEMP_OFFSET,
557 ),
558 Err(i2c_error) => Err(i2c_error.into()),
559 };
560 self.temperature_client.map(|client| {
561 client.callback(values);
562 });
563
564 self.current_process.map(|process_id| {
565 let _ = self.apps.enter(process_id, |_grant, upcalls| {
566 if let Ok(temp) = values {
567 upcalls.schedule_upcall(0, (temp as usize, 0, 0)).ok();
568 } else {
569 upcalls.schedule_upcall(0, (0, 0, 0)).ok();
570 }
571 });
572 });
573
574 self.buffer.replace(buffer);
575 self.i2c_magnetometer.disable();
576 self.state.set(State::Idle);
577 }
578 State::ReadMagnetometerXYZ => {
579 let mut x: usize = 0;
580 let mut y: usize = 0;
581 let mut z: usize = 0;
582 let values = if status == Ok(()) {
583 self.nine_dof_client.map(|client| {
584 let range = self.mag_range.get() as usize;
586 x = (((buffer[1] as i16 | ((buffer[0] as i16) << 8)) as i32) * 100
587 / RANGE_FACTOR_X_Y[range] as i32) as usize;
588 z = (((buffer[3] as i16 | ((buffer[2] as i16) << 8)) as i32) * 100
589 / RANGE_FACTOR_X_Y[range] as i32) as usize;
590 y = (((buffer[5] as i16 | ((buffer[4] as i16) << 8)) as i32) * 100
591 / RANGE_FACTOR_Z[range] as i32) as usize;
592 client.callback(x, y, z);
593 });
594
595 x = ((buffer[1] as u16 | ((buffer[0] as u16) << 8)) as i16) as usize;
596 z = ((buffer[3] as u16 | ((buffer[2] as u16) << 8)) as i16) as usize;
597 y = ((buffer[5] as u16 | ((buffer[4] as u16) << 8)) as i16) as usize;
598 true
599 } else {
600 self.nine_dof_client.map(|client| {
601 client.callback(0, 0, 0);
602 });
603 false
604 };
605
606 self.current_process.map(|process_id| {
607 let _ = self.apps.enter(process_id, |_grant, upcalls| {
608 if values {
609 upcalls.schedule_upcall(0, (x, y, z)).ok();
610 } else {
611 upcalls.schedule_upcall(0, (0, 0, 0)).ok();
612 }
613 });
614 });
615
616 self.buffer.replace(buffer);
617 self.i2c_magnetometer.disable();
618 self.state.set(State::Idle);
619 }
620 _ => {
621 self.i2c_magnetometer.disable();
622 self.i2c_accelerometer.disable();
623 self.buffer.replace(buffer);
624 }
625 }
626 }
627}
628
629impl<I: i2c::I2CDevice> SyscallDriver for Lsm303dlhcI2C<'_, I> {
630 fn command(
631 &self,
632 command_num: usize,
633 data1: usize,
634 data2: usize,
635 process_id: ProcessId,
636 ) -> CommandReturn {
637 if command_num == 0 {
638 return CommandReturn::success();
641 }
642
643 let match_or_empty_or_nonexistant = self.current_process.map_or(true, |current_process| {
646 self.apps
647 .enter(current_process, |_, _| current_process == process_id)
648 .unwrap_or(true)
649 });
650
651 if match_or_empty_or_nonexistant {
652 self.current_process.set(process_id);
653 } else {
654 return CommandReturn::failure(ErrorCode::NOMEM);
655 }
656
657 match command_num {
658 1 => {
660 if self.state.get() == State::Idle {
661 match self.is_present() {
662 Ok(()) => CommandReturn::success(),
663 Err(error) => CommandReturn::failure(error),
664 }
665 } else {
666 CommandReturn::failure(ErrorCode::BUSY)
667 }
668 }
669 2 => {
671 if self.state.get() == State::Idle {
672 if let Some(data_rate) = Lsm303AccelDataRate::from_usize(data1) {
673 match self.set_power_mode(data_rate, data2 != 0) {
674 Ok(()) => CommandReturn::success(),
675 Err(error) => CommandReturn::failure(error),
676 }
677 } else {
678 CommandReturn::failure(ErrorCode::INVAL)
679 }
680 } else {
681 CommandReturn::failure(ErrorCode::BUSY)
682 }
683 }
684 3 => {
686 if self.state.get() == State::Idle {
687 if let Some(scale) = Lsm303Scale::from_usize(data1) {
688 match self.set_scale_and_resolution(scale, data2 != 0) {
689 Ok(()) => CommandReturn::success(),
690 Err(error) => CommandReturn::failure(error),
691 }
692 } else {
693 CommandReturn::failure(ErrorCode::INVAL)
694 }
695 } else {
696 CommandReturn::failure(ErrorCode::BUSY)
697 }
698 }
699 4 => {
701 if self.state.get() == State::Idle {
702 if let Some(data_rate) = Lsm303MagnetoDataRate::from_usize(data1) {
703 match self.set_temperature_and_magneto_data_rate(data2 != 0, data_rate) {
704 Ok(()) => CommandReturn::success(),
705 Err(error) => CommandReturn::failure(error),
706 }
707 } else {
708 CommandReturn::failure(ErrorCode::INVAL)
709 }
710 } else {
711 CommandReturn::failure(ErrorCode::BUSY)
712 }
713 }
714 5 => {
716 if self.state.get() == State::Idle {
717 if let Some(range) = Lsm303Range::from_usize(data1) {
718 match self.set_range(range) {
719 Ok(()) => CommandReturn::success(),
720 Err(error) => CommandReturn::failure(error),
721 }
722 } else {
723 CommandReturn::failure(ErrorCode::INVAL)
724 }
725 } else {
726 CommandReturn::failure(ErrorCode::BUSY)
727 }
728 }
729 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
731 }
732 }
733
734 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
735 self.apps.enter(processid, |_, _| {})
736 }
737}
738
739impl<'a, I: i2c::I2CDevice> sensors::NineDof<'a> for Lsm303dlhcI2C<'a, I> {
740 fn set_client(&self, nine_dof_client: &'a dyn sensors::NineDofClient) {
741 self.nine_dof_client.replace(nine_dof_client);
742 }
743
744 fn read_accelerometer(&self) -> Result<(), ErrorCode> {
745 self.read_acceleration_xyz()
746 }
747
748 fn read_magnetometer(&self) -> Result<(), ErrorCode> {
749 self.read_magnetometer_xyz()
750 }
751}
752
753impl<'a, I: i2c::I2CDevice> sensors::TemperatureDriver<'a> for Lsm303dlhcI2C<'a, I> {
754 fn set_client(&self, temperature_client: &'a dyn sensors::TemperatureClient) {
755 self.temperature_client.replace(temperature_client);
756 }
757
758 fn read_temperature(&self) -> Result<(), ErrorCode> {
759 self.read_temperature()
760 }
761}