blob: 83e603e5baf497c1349ddb6402e8793f542561a4 [file] [edit]
//! Shared userland driver for light sensors.
//!
//! You need a device that provides the `hil::sensors::AmbientLight` trait.
//!
//! ```rust
//! # use kernel::{hil, static_init};
//!
//! let light = static_init!(
//! capsules::ambient_light::AmbientLight<'static>,
//! capsules::ambient_light::AmbientLight::new(isl29035,
//! board_kernel.create_grant(&grant_cap)));
//! hil::sensors::AmbientLight::set_client(isl29035, ambient_light);
//! ```
use core::cell::Cell;
use kernel::hil;
use kernel::{AppId, Callback, Driver, Grant, ReturnCode};
/// Syscall driver number.
use crate::driver;
pub const DRIVER_NUM: usize = driver::NUM::AmbientLight as usize;
/// Per-process metadata
#[derive(Default)]
pub struct App {
callback: Option<Callback>,
pending: bool,
}
pub struct AmbientLight<'a> {
sensor: &'a dyn hil::sensors::AmbientLight<'a>,
command_pending: Cell<bool>,
apps: Grant<App>,
}
impl<'a> AmbientLight<'a> {
pub fn new(sensor: &'a dyn hil::sensors::AmbientLight<'a>, grant: Grant<App>) -> AmbientLight {
AmbientLight {
sensor: sensor,
command_pending: Cell::new(false),
apps: grant,
}
}
fn enqueue_sensor_reading(&self, appid: AppId) -> ReturnCode {
self.apps
.enter(appid, |app, _| {
if app.pending {
ReturnCode::ENOMEM
} else {
app.pending = true;
if !self.command_pending.get() {
self.command_pending.set(true);
self.sensor.read_light_intensity();
}
ReturnCode::SUCCESS
}
})
.unwrap_or_else(|err| err.into())
}
}
impl Driver for AmbientLight<'_> {
/// Subscribe to light intensity readings
///
/// ### `subscribe`
///
/// - `0`: Subscribe to light intensity readings. The callback signature is
/// `fn(lux: usize)`, where `lux` is the light intensity in lux (lx).
fn subscribe(
&self,
subscribe_num: usize,
callback: Option<Callback>,
app_id: AppId,
) -> ReturnCode {
match subscribe_num {
0 => self
.apps
.enter(app_id, |app, _| {
app.callback = callback;
ReturnCode::SUCCESS
})
.unwrap_or_else(|err| err.into()),
_ => ReturnCode::ENOSUPPORT,
}
}
/// Initiate light intensity readings
///
/// Sensor readings are coalesced if processes request them concurrently. If
/// multiple processes request have outstanding requests for a sensor
/// reading, only one command will be issued and the result is returned to
/// all subscribed processes.
///
/// ### `command_num`
///
/// - `0`: Check driver presence
/// - `1`: Start a light sensor reading
fn command(&self, command_num: usize, _: usize, _: usize, appid: AppId) -> ReturnCode {
match command_num {
0 /* check if present */ => ReturnCode::SUCCESS,
1 => {
self.enqueue_sensor_reading(appid);
ReturnCode::SUCCESS
}
_ => ReturnCode::ENOSUPPORT,
}
}
}
impl hil::sensors::AmbientLightClient for AmbientLight<'_> {
fn callback(&self, lux: usize) {
self.command_pending.set(false);
self.apps.each(|app| {
if app.pending {
app.pending = false;
if let Some(mut callback) = app.callback {
callback.schedule(lux, 0, 0);
}
}
});
}
}