blob: c505cf94981f59c50f2158470f907433b7d4f29f [file] [log] [blame]
use crate::result::OutOfRangeError;
use crate::result::TockResult;
use crate::syscalls::command;
use core::marker::PhantomData;
const DRIVER_NUMBER: usize = 0x00002;
mod command_nr {
pub const COUNT: usize = 0;
pub const ON: usize = 1;
pub const OFF: usize = 2;
pub const TOGGLE: usize = 3;
}
#[non_exhaustive]
pub struct LedsDriverFactory;
impl LedsDriverFactory {
pub fn init_driver(&mut self) -> TockResult<LedsDriver> {
let driver = LedsDriver {
num_leds: command(DRIVER_NUMBER, command_nr::COUNT, 0, 0)?,
lifetime: PhantomData,
};
Ok(driver)
}
}
pub struct LedsDriver<'a> {
num_leds: usize,
lifetime: PhantomData<&'a ()>,
}
impl<'a> LedsDriver<'a> {
pub fn num_leds(&self) -> usize {
self.num_leds
}
pub fn leds(&self) -> Leds {
Leds {
num_leds: self.num_leds,
curr_led: 0,
lifetime: PhantomData,
}
}
/// Returns the led at 0-based index `led_num`
pub fn get(&self, led_num: usize) -> Result<Led, OutOfRangeError> {
if led_num < self.num_leds {
Ok(Led {
led_num,
lifetime: PhantomData,
})
} else {
Err(OutOfRangeError)
}
}
}
pub struct Leds<'a> {
num_leds: usize,
curr_led: usize,
lifetime: PhantomData<&'a ()>,
}
impl<'a> Iterator for Leds<'a> {
type Item = Led<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.curr_led < self.num_leds {
let item = Led {
led_num: self.curr_led,
lifetime: PhantomData,
};
self.curr_led += 1;
Some(item)
} else {
None
}
}
}
pub struct Led<'a> {
led_num: usize,
lifetime: PhantomData<&'a ()>,
}
impl<'a> Led<'a> {
pub fn led_num(&self) -> usize {
self.led_num
}
pub fn set(&self, state: impl Into<LedState>) -> TockResult<()> {
match state.into() {
LedState::On => self.on(),
LedState::Off => self.off(),
}
}
pub fn on(&self) -> TockResult<()> {
command(DRIVER_NUMBER, command_nr::ON, self.led_num, 0)?;
Ok(())
}
pub fn off(&self) -> TockResult<()> {
command(DRIVER_NUMBER, command_nr::OFF, self.led_num, 0)?;
Ok(())
}
pub fn toggle(&self) -> TockResult<()> {
command(DRIVER_NUMBER, command_nr::TOGGLE, self.led_num, 0)?;
Ok(())
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum LedState {
On,
Off,
}
impl From<bool> for LedState {
fn from(from_value: bool) -> Self {
if from_value {
LedState::On
} else {
LedState::Off
}
}
}
#[cfg(test)]
mod test {
use super::command_nr;
use super::DRIVER_NUMBER;
use crate::result::TockResult;
use crate::syscalls;
use crate::syscalls::raw::Event;
#[test]
pub fn single_led_can_be_enabled() {
let events = syscalls::raw::run_recording_events::<TockResult<()>, _>(|next_return| {
let mut drivers = unsafe { crate::drivers::retrieve_drivers_unsafe() };
next_return.set(1);
let leds_driver = drivers.leds.init_driver()?;
next_return.set(0);
let led = leds_driver.get(0)?;
led.on()?;
Ok(())
});
assert_eq!(
events,
vec![
Event::Command(DRIVER_NUMBER, command_nr::COUNT, 0, 0),
Event::Command(DRIVER_NUMBER, command_nr::ON, 0, 0),
]
);
}
}