mirror of
https://github.com/FeitianTech/OpenSK.git
synced 2026-08-28 10:41:01 -07:00
162 lines
3.6 KiB
Rust
162 lines
3.6 KiB
Rust
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),
|
|
]
|
|
);
|
|
}
|
|
}
|