blob: c505cf94981f59c50f2158470f907433b7d4f29f [file] [log] [blame]
Woytene22bc2b2020-01-17 14:12:47 +01001use crate::result::OutOfRangeError;
Woyten70c09f92019-12-01 15:17:32 +01002use crate::result::TockResult;
3use crate::syscalls::command;
4use core::marker::PhantomData;
5
6const DRIVER_NUMBER: usize = 0x00002;
7
8mod command_nr {
9 pub const COUNT: usize = 0;
10 pub const ON: usize = 1;
11 pub const OFF: usize = 2;
12 pub const TOGGLE: usize = 3;
13}
14
15#[non_exhaustive]
16pub struct LedsDriverFactory;
17
18impl LedsDriverFactory {
19 pub fn init_driver(&mut self) -> TockResult<LedsDriver> {
20 let driver = LedsDriver {
21 num_leds: command(DRIVER_NUMBER, command_nr::COUNT, 0, 0)?,
22 lifetime: PhantomData,
23 };
24 Ok(driver)
25 }
26}
27
28pub struct LedsDriver<'a> {
29 num_leds: usize,
30 lifetime: PhantomData<&'a ()>,
31}
32
33impl<'a> LedsDriver<'a> {
34 pub fn num_leds(&self) -> usize {
35 self.num_leds
36 }
37
38 pub fn leds(&self) -> Leds {
39 Leds {
40 num_leds: self.num_leds,
41 curr_led: 0,
42 lifetime: PhantomData,
43 }
44 }
45
Woytene22bc2b2020-01-17 14:12:47 +010046 /// Returns the led at 0-based index `led_num`
47 pub fn get(&self, led_num: usize) -> Result<Led, OutOfRangeError> {
Woyten70c09f92019-12-01 15:17:32 +010048 if led_num < self.num_leds {
Woytene22bc2b2020-01-17 14:12:47 +010049 Ok(Led {
Woyten70c09f92019-12-01 15:17:32 +010050 led_num,
51 lifetime: PhantomData,
52 })
53 } else {
Woytene22bc2b2020-01-17 14:12:47 +010054 Err(OutOfRangeError)
Woyten70c09f92019-12-01 15:17:32 +010055 }
56 }
57}
58
59pub struct Leds<'a> {
60 num_leds: usize,
61 curr_led: usize,
62 lifetime: PhantomData<&'a ()>,
63}
64
65impl<'a> Iterator for Leds<'a> {
66 type Item = Led<'a>;
67
68 fn next(&mut self) -> Option<Self::Item> {
69 if self.curr_led < self.num_leds {
70 let item = Led {
71 led_num: self.curr_led,
72 lifetime: PhantomData,
73 };
74 self.curr_led += 1;
75 Some(item)
76 } else {
77 None
78 }
79 }
80}
81
82pub struct Led<'a> {
83 led_num: usize,
84 lifetime: PhantomData<&'a ()>,
85}
86
87impl<'a> Led<'a> {
88 pub fn led_num(&self) -> usize {
89 self.led_num
90 }
91
92 pub fn set(&self, state: impl Into<LedState>) -> TockResult<()> {
93 match state.into() {
94 LedState::On => self.on(),
95 LedState::Off => self.off(),
96 }
97 }
98
99 pub fn on(&self) -> TockResult<()> {
100 command(DRIVER_NUMBER, command_nr::ON, self.led_num, 0)?;
101 Ok(())
102 }
103
104 pub fn off(&self) -> TockResult<()> {
105 command(DRIVER_NUMBER, command_nr::OFF, self.led_num, 0)?;
106 Ok(())
107 }
108
109 pub fn toggle(&self) -> TockResult<()> {
110 command(DRIVER_NUMBER, command_nr::TOGGLE, self.led_num, 0)?;
111 Ok(())
112 }
113}
114
115#[derive(Copy, Clone, Debug, Eq, PartialEq)]
116pub enum LedState {
117 On,
118 Off,
119}
120
121impl From<bool> for LedState {
122 fn from(from_value: bool) -> Self {
123 if from_value {
124 LedState::On
125 } else {
126 LedState::Off
127 }
128 }
129}
torfmaster672b5432020-01-24 17:10:12 +0100130
131#[cfg(test)]
132mod test {
133 use super::command_nr;
134 use super::DRIVER_NUMBER;
135 use crate::result::TockResult;
136 use crate::syscalls;
137 use crate::syscalls::raw::Event;
138
139 #[test]
140 pub fn single_led_can_be_enabled() {
141 let events = syscalls::raw::run_recording_events::<TockResult<()>, _>(|next_return| {
142 let mut drivers = unsafe { crate::drivers::retrieve_drivers_unsafe() };
143
144 next_return.set(1);
145
146 let leds_driver = drivers.leds.init_driver()?;
147 next_return.set(0);
148
149 let led = leds_driver.get(0)?;
150 led.on()?;
151 Ok(())
152 });
153 assert_eq!(
154 events,
155 vec![
156 Event::Command(DRIVER_NUMBER, command_nr::COUNT, 0, 0),
157 Event::Command(DRIVER_NUMBER, command_nr::ON, 0, 0),
158 ]
159 );
160 }
161}