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                let _ = upcalls.schedule_upcall(upcall::LIGHT_INTENSITY, (lux, 0, 0));
124            }
125        });
126    }
127}