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