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 let _ = upcalls.schedule_upcall(0, (usize::from(present), 0, 0));
416 });
417 });
418 self.buffer.replace(buffer);
419 self.i2c_magnetometer.disable();
420 self.state.set(State::Idle);
421 }
422 State::SetPowerMode => {
423 let set_power = status == Ok(());
424 self.owning_process.map(|pid| {
425 let _res = self.apps.enter(pid, |_app, upcalls| {
426 let _ = upcalls.schedule_upcall(0, (usize::from(set_power), 0, 0));
427 });
428 });
429 self.buffer.replace(buffer);
430 self.i2c_accelerometer.disable();
431 self.state.set(State::Idle);
432 if self.config_in_progress.get() {
433 if let Err(_error) = self.set_scale_and_resolution(
434 self.accel_scale.get(),
435 self.accel_high_resolution.get(),
436 ) {
437 self.config_in_progress.set(false);
438 }
439 }
440 }
441 State::SetScaleAndResolution => {
442 let set_scale_and_resolution = status == Ok(());
443 self.owning_process.map(|pid| {
444 let _res = self.apps.enter(pid, |_app, upcalls| {
445 let _ = upcalls
446 .schedule_upcall(0, (usize::from(set_scale_and_resolution), 0, 0));
447 });
448 });
449 self.buffer.replace(buffer);
450 self.i2c_accelerometer.disable();
451 self.state.set(State::Idle);
452 if self.config_in_progress.get() {
453 if let Err(_error) = self.set_magneto_data_rate(self.mag_data_rate.get()) {
454 self.config_in_progress.set(false);
455 }
456 }
457 }
458 State::ReadAccelerationXYZ => {
459 let mut x: usize = 0;
460 let mut y: usize = 0;
461 let mut z: usize = 0;
462 let values = if status == Ok(()) {
463 self.nine_dof_client.map(|client| {
464 let scale_factor = self.accel_scale.get() as usize;
466 x = (((buffer[0] as i16 | ((buffer[1] as i16) << 8)) as i32)
467 * (SCALE_FACTOR[scale_factor] as i32)
468 * 1000
469 / 32768) as usize;
470 y = (((buffer[2] as i16 | ((buffer[3] as i16) << 8)) as i32)
471 * (SCALE_FACTOR[scale_factor] as i32)
472 * 1000
473 / 32768) as usize;
474 z = (((buffer[4] as i16 | ((buffer[5] as i16) << 8)) as i32)
475 * (SCALE_FACTOR[scale_factor] as i32)
476 * 1000
477 / 32768) as usize;
478 client.callback(x, y, z);
479 });
480
481 x = (buffer[0] as i16 | ((buffer[1] as i16) << 8)) as usize;
482 y = (buffer[2] as i16 | ((buffer[3] as i16) << 8)) as usize;
483 z = (buffer[4] as i16 | ((buffer[5] as i16) << 8)) as usize;
484 true
485 } else {
486 self.nine_dof_client.map(|client| {
487 client.callback(0, 0, 0);
488 });
489 false
490 };
491 self.owning_process.map(|pid| {
492 let _res = self.apps.enter(pid, |_app, upcalls| {
493 if values {
494 let _ = upcalls.schedule_upcall(0, (x, y, z));
495 } else {
496 let _ = upcalls.schedule_upcall(0, (0, 0, 0));
497 }
498 });
499 });
500 self.buffer.replace(buffer);
501 self.i2c_accelerometer.disable();
502 self.state.set(State::Idle);
503 }
504 State::SetDataRate => {
505 let set_magneto_data_rate = status == Ok(());
506 self.owning_process.map(|pid| {
507 let _res = self.apps.enter(pid, |_app, upcalls| {
508 let _ =
509 upcalls.schedule_upcall(0, (usize::from(set_magneto_data_rate), 0, 0));
510 });
511 });
512 self.buffer.replace(buffer);
513 self.i2c_magnetometer.disable();
514 self.state.set(State::Idle);
515 if self.config_in_progress.get() {
516 if let Err(_error) = self.set_range(self.mag_range.get()) {
517 self.config_in_progress.set(false);
518 }
519 }
520 }
521 State::SetRange => {
522 let set_range = status == Ok(());
523 self.owning_process.map(|pid| {
524 let _res = self.apps.enter(pid, |_app, upcalls| {
525 let _ = upcalls.schedule_upcall(0, (usize::from(set_range), 0, 0));
526 });
527 });
528 if self.config_in_progress.get() {
529 self.config_in_progress.set(false);
530 }
531 self.buffer.replace(buffer);
532 self.i2c_magnetometer.disable();
533 self.state.set(State::Idle);
534 }
535 State::ReadTemperature => {
536 let values = match status {
537 Ok(()) => Ok((buffer[1] as u16 as i16 | ((buffer[0] as i16) << 8)) as i32 / 8),
538 Err(i2c_err) => Err(i2c_err.into()),
539 };
540 self.temperature_client.map(|client| {
541 client.callback(values);
542 });
543 self.owning_process.map(|pid| {
544 let _res = self.apps.enter(pid, |_app, upcalls| {
545 if let Ok(temp) = values {
546 let _ = upcalls.schedule_upcall(0, (temp as usize, 0, 0));
547 } else {
548 let _ = upcalls.schedule_upcall(0, (0, 0, 0));
549 }
550 });
551 });
552 self.buffer.replace(buffer);
553 self.i2c_accelerometer.disable();
554 self.state.set(State::Idle);
555 }
556 State::ReadMagnetometerXYZ => {
557 let mut x: usize = 0;
558 let mut y: usize = 0;
559 let mut z: usize = 0;
560 let values = if status == Ok(()) {
561 self.nine_dof_client.map(|client| {
562 let range = self.mag_range.get() as usize;
564 x = (((buffer[1] as i16 | ((buffer[0] as i16) << 8)) as i32) * 100
565 / RANGE_FACTOR_X_Y[range] as i32) as usize;
566 z = (((buffer[3] as i16 | ((buffer[2] as i16) << 8)) as i32) * 100
567 / RANGE_FACTOR_X_Y[range] as i32) as usize;
568 y = (((buffer[5] as i16 | ((buffer[4] as i16) << 8)) as i32) * 100
569 / RANGE_FACTOR_Z[range] as i32) as usize;
570 client.callback(x, y, z);
571 });
572
573 x = ((buffer[1] as u16 | ((buffer[0] as u16) << 8)) as i16) as usize;
574 z = ((buffer[3] as u16 | ((buffer[2] as u16) << 8)) as i16) as usize;
575 y = ((buffer[5] as u16 | ((buffer[4] as u16) << 8)) as i16) as usize;
576 true
577 } else {
578 self.nine_dof_client.map(|client| {
579 client.callback(0, 0, 0);
580 });
581 false
582 };
583 self.owning_process.map(|pid| {
584 let _res = self.apps.enter(pid, |_app, upcalls| {
585 if values {
586 let _ = upcalls.schedule_upcall(0, (x, y, z));
587 } else {
588 let _ = upcalls.schedule_upcall(0, (0, 0, 0));
589 }
590 });
591 });
592 self.buffer.replace(buffer);
593 self.i2c_magnetometer.disable();
594 self.state.set(State::Idle);
595 }
596 _ => {
597 self.i2c_magnetometer.disable();
598 self.i2c_accelerometer.disable();
599 self.buffer.replace(buffer);
600 }
601 }
602 }
603}
604
605impl<I: i2c::I2CDevice> SyscallDriver for Lsm303agrI2C<'_, I> {
606 fn command(
607 &self,
608 command_num: usize,
609 data1: usize,
610 data2: usize,
611 process_id: ProcessId,
612 ) -> CommandReturn {
613 if command_num == 0 {
614 return CommandReturn::success();
617 }
618
619 let match_or_empty_or_nonexistant = self.owning_process.map_or(true, |current_process| {
620 self.apps
621 .enter(current_process, |_, _| current_process == process_id)
622 .unwrap_or(true)
623 });
624 if match_or_empty_or_nonexistant {
625 self.owning_process.set(process_id);
626 } else {
627 return CommandReturn::failure(ErrorCode::RESERVE);
628 }
629
630 match command_num {
631 1 => {
633 if self.state.get() == State::Idle {
634 match self.is_present() {
635 Ok(()) => CommandReturn::success(),
636 Err(error) => CommandReturn::failure(error),
637 }
638 } else {
639 CommandReturn::failure(ErrorCode::BUSY)
640 }
641 }
642 2 => {
644 if self.state.get() == State::Idle {
645 if let Some(data_rate) = Lsm303AccelDataRate::from_usize(data1) {
646 match self.set_power_mode(data_rate, data2 != 0) {
647 Ok(()) => CommandReturn::success(),
648 Err(error) => CommandReturn::failure(error),
649 }
650 } else {
651 CommandReturn::failure(ErrorCode::INVAL)
652 }
653 } else {
654 CommandReturn::failure(ErrorCode::BUSY)
655 }
656 }
657 3 => {
659 if self.state.get() == State::Idle {
660 if let Some(scale) = Lsm303Scale::from_usize(data1) {
661 match self.set_scale_and_resolution(scale, data2 != 0) {
662 Ok(()) => CommandReturn::success(),
663 Err(error) => CommandReturn::failure(error),
664 }
665 } else {
666 CommandReturn::failure(ErrorCode::INVAL)
667 }
668 } else {
669 CommandReturn::failure(ErrorCode::BUSY)
670 }
671 }
672 4 => {
674 if self.state.get() == State::Idle {
675 if let Some(data_rate) = Lsm303MagnetoDataRate::from_usize(data1) {
676 match self.set_magneto_data_rate(data_rate) {
677 Ok(()) => CommandReturn::success(),
678 Err(error) => CommandReturn::failure(error),
679 }
680 } else {
681 CommandReturn::failure(ErrorCode::INVAL)
682 }
683 } else {
684 CommandReturn::failure(ErrorCode::BUSY)
685 }
686 }
687 5 => {
689 if self.state.get() == State::Idle {
690 if let Some(range) = Lsm303Range::from_usize(data1) {
691 match self.set_range(range) {
692 Ok(()) => CommandReturn::success(),
693 Err(error) => CommandReturn::failure(error),
694 }
695 } else {
696 CommandReturn::failure(ErrorCode::INVAL)
697 }
698 } else {
699 CommandReturn::failure(ErrorCode::BUSY)
700 }
701 }
702 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
704 }
705 }
706
707 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
708 self.apps.enter(processid, |_, _| {})
709 }
710}
711
712impl<'a, I: i2c::I2CDevice> sensors::NineDof<'a> for Lsm303agrI2C<'a, I> {
713 fn set_client(&self, nine_dof_client: &'a dyn sensors::NineDofClient) {
714 self.nine_dof_client.replace(nine_dof_client);
715 }
716
717 fn read_accelerometer(&self) -> Result<(), ErrorCode> {
718 self.read_acceleration_xyz()
719 }
720
721 fn read_magnetometer(&self) -> Result<(), ErrorCode> {
722 self.read_magnetometer_xyz()
723 }
724}
725
726impl<'a, I: i2c::I2CDevice> sensors::TemperatureDriver<'a> for Lsm303agrI2C<'a, I> {
727 fn set_client(&self, temperature_client: &'a dyn sensors::TemperatureClient) {
728 self.temperature_client.replace(temperature_client);
729 }
730
731 fn read_temperature(&self) -> Result<(), ErrorCode> {
732 self.read_temperature()
733 }
734}