capsules_extra/
ambient_light.rs1use core::cell::Cell;
20
21use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
22use kernel::hil;
23use kernel::syscall::{CommandReturn, SyscallDriver};
24use kernel::{ErrorCode, ProcessId};
25
26use capsules_core::driver;
28pub const DRIVER_NUM: usize = driver::NUM::AmbientLight as usize;
29
30mod upcall {
32 pub const LIGHT_INTENSITY: usize = 0;
37 pub const COUNT: u8 = 1;
39}
40
41#[derive(Default)]
43pub struct App {
44 pending: bool,
45}
46
47pub struct AmbientLight<'a> {
48 sensor: &'a dyn hil::sensors::AmbientLight<'a>,
49 command_pending: Cell<bool>,
50 apps: Grant<App, UpcallCount<{ upcall::COUNT }>, AllowRoCount<0>, AllowRwCount<0>>,
51}
52
53impl<'a> AmbientLight<'a> {
54 pub fn new(
55 sensor: &'a dyn hil::sensors::AmbientLight<'a>,
56 grant: Grant<App, UpcallCount<{ upcall::COUNT }>, AllowRoCount<0>, AllowRwCount<0>>,
57 ) -> Self {
58 Self {
59 sensor,
60 command_pending: Cell::new(false),
61 apps: grant,
62 }
63 }
64
65 fn enqueue_sensor_reading(&self, processid: ProcessId) -> Result<(), ErrorCode> {
66 self.apps
67 .enter(processid, |app, _| {
68 if app.pending {
69 Err(ErrorCode::NOMEM)
70 } else {
71 app.pending = true;
72 if !self.command_pending.get() {
73 self.command_pending.set(true);
74 let _ = self.sensor.read_light_intensity();
75 }
76 Ok(())
77 }
78 })
79 .unwrap_or_else(|err| err.into())
80 }
81}
82
83impl SyscallDriver for AmbientLight<'_> {
84 fn command(
96 &self,
97 command_num: usize,
98 _: usize,
99 _: usize,
100 processid: ProcessId,
101 ) -> CommandReturn {
102 match command_num {
103 0 => CommandReturn::success(),
104 1 => {
105 let _ = self.enqueue_sensor_reading(processid);
106 CommandReturn::success()
107 }
108 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
109 }
110 }
111
112 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
113 self.apps.enter(processid, |_, _| {})
114 }
115}
116
117impl hil::sensors::AmbientLightClient for AmbientLight<'_> {
118 fn callback(&self, lux: usize) {
119 self.command_pending.set(false);
120 self.apps.each(|_, app, upcalls| {
121 if app.pending {
122 app.pending = false;
123 upcalls
124 .schedule_upcall(upcall::LIGHT_INTENSITY, (lux, 0, 0))
125 .ok();
126 }
127 });
128 }
129}