Make led driver a singleton
diff --git a/examples/adc.rs b/examples/adc.rs index 83b5919..afc110e 100644 --- a/examples/adc.rs +++ b/examples/adc.rs
@@ -13,7 +13,7 @@ let mut driver = context.create_timer_driver()?; let timer_driver = driver.activate()?; - let Hardware { console_driver } = libtock::retrieve_hardware()?; + let Hardware { console_driver, .. } = libtock::retrieve_hardware()?; let mut console = console_driver.create_console(); let mut with_callback = adc::with_callback(|channel: usize, value: usize| { writeln!(console, "channel: {}, value: {}", channel, value).unwrap();
diff --git a/examples/adc_buffer.rs b/examples/adc_buffer.rs index 067c67d..2559376 100644 --- a/examples/adc_buffer.rs +++ b/examples/adc_buffer.rs
@@ -10,7 +10,7 @@ #[libtock::main] /// Reads a 128 byte sample into a buffer and prints the first value to the console. async fn main() -> TockResult<()> { - let Hardware { console_driver } = libtock::retrieve_hardware()?; + let Hardware { console_driver, .. } = libtock::retrieve_hardware()?; let mut console = console_driver.create_console(); let mut adc_buffer = AdcBuffer::default(); let mut temp_buffer = [0; libtock::adc::BUFFER_SIZE];
diff --git a/examples/ble_scanning.rs b/examples/ble_scanning.rs index 78de325..8846ed7 100644 --- a/examples/ble_scanning.rs +++ b/examples/ble_scanning.rs
@@ -2,11 +2,11 @@ use futures::future; use libtock::ble_parser; -use libtock::led; use libtock::result::TockResult; use libtock::simple_ble; use libtock::simple_ble::BleCallback; use libtock::simple_ble::BleDriver; +use libtock::Hardware; use serde::Deserialize; #[derive(Deserialize)] @@ -20,13 +20,18 @@ let mut shared_buffer = BleDriver::create_scan_buffer(); let mut my_buffer = BleDriver::create_scan_buffer(); let shared_memory = BleDriver::share_memory(&mut shared_buffer)?; + let Hardware { mut led_driver, .. } = libtock::retrieve_hardware()?; let mut callback = BleCallback::new(|_: usize, _: usize| { shared_memory.read_bytes(&mut my_buffer[..]); ble_parser::find(&my_buffer, simple_ble::gap_data::SERVICE_DATA as u8) .and_then(|service_data| ble_parser::extract_for_service([91, 79], service_data)) .and_then(|payload| corepack::from_bytes::<LedCommand>(&payload).ok()) - .and_then(|msg| led::get(msg.nr as usize).map(|led| led.set_state(msg.st))); + .and_then(|msg| { + led_driver + .get(msg.nr as usize) + .map(|mut led| led.set_state(msg.st)) + }); }); let _subscription = BleDriver::start(&mut callback)?;
diff --git a/examples/blink.rs b/examples/blink.rs index f37fd12..88857c2 100644 --- a/examples/blink.rs +++ b/examples/blink.rs
@@ -1,13 +1,14 @@ #![no_std] -use libtock::led; use libtock::result::TockResult; use libtock::timer; use libtock::timer::Duration; +use libtock::Hardware; #[libtock::main] async fn main() -> TockResult<()> { - let num_leds = led::count()?; + let Hardware { mut led_driver, .. } = libtock::retrieve_hardware()?; + let context = timer::DriverContext::create()?; let mut driver = context.create_timer_driver()?; let timer_driver = driver.activate()?; @@ -16,11 +17,12 @@ // to the number of LEDs on the board. let mut count: usize = 0; loop { - for i in 0..num_leds { + for mut led in led_driver.all() { + let i = led.number(); if count & (1 << i) == (1 << i) { - led::get(i).unwrap().on()?; + led.on()?; } else { - led::get(i).unwrap().off()?; + led.off()?; } } count = count.wrapping_add(1);
diff --git a/examples/blink_random.rs b/examples/blink_random.rs index 6b964a2..a857181 100644 --- a/examples/blink_random.rs +++ b/examples/blink_random.rs
@@ -1,18 +1,20 @@ #![no_std] -use libtock::led; +use libtock::led::LedDriver; use libtock::result::TockResult; use libtock::rng; use libtock::timer; use libtock::timer::Duration; +use libtock::Hardware; #[libtock::main] async fn main() -> TockResult<()> { let context = timer::DriverContext::create()?; let mut driver = context.create_timer_driver()?; let timer_driver = driver.activate()?; + let Hardware { mut led_driver, .. } = libtock::retrieve_hardware()?; - let num_leds = led::count()?; + let num_leds = led_driver.count()?; // blink_nibble assumes 4 leds. assert_eq!(num_leds, 4); @@ -21,18 +23,18 @@ rng::fill_buffer(&mut buf).await?; for &x in buf.iter() { - blink_nibble(x)?; + blink_nibble(x, &mut led_driver)?; timer_driver.sleep(Duration::from_ms(100)).await?; - blink_nibble(x >> 4)?; + blink_nibble(x >> 4, &mut led_driver)?; timer_driver.sleep(Duration::from_ms(100)).await?; } } } // Takes the 4 least-significant bits of x, and turn the 4 leds on/off accordingly. -fn blink_nibble(x: u8) -> TockResult<()> { +fn blink_nibble(x: u8, led_driver: &mut LedDriver) -> TockResult<()> { for i in 0..4 { - let led = led::get(i).unwrap(); + let mut led = led_driver.get(i).unwrap(); if (x >> i) & 1 != 0 { led.on()?; } else {
diff --git a/examples/button_leds.rs b/examples/button_leds.rs index 294d45a..789cb9b 100644 --- a/examples/button_leds.rs +++ b/examples/button_leds.rs
@@ -3,14 +3,16 @@ use futures::future; use libtock::buttons; use libtock::buttons::ButtonState; -use libtock::led; use libtock::result::TockResult; +use libtock::Hardware; #[libtock::main] async fn main() -> TockResult<()> { + let Hardware { mut led_driver, .. } = libtock::retrieve_hardware()?; + let mut with_callback = buttons::with_callback(|button_num: usize, state| { match state { - ButtonState::Pressed => led::get(button_num).unwrap().toggle().ok().unwrap(), + ButtonState::Pressed => led_driver.get(button_num).unwrap().toggle().ok().unwrap(), ButtonState::Released => (), }; });
diff --git a/examples/button_read.rs b/examples/button_read.rs index 32714de..ddd98e8 100644 --- a/examples/button_read.rs +++ b/examples/button_read.rs
@@ -10,7 +10,7 @@ #[libtock::main] async fn main() -> TockResult<()> { - let Hardware { console_driver } = libtock::retrieve_hardware()?; + let Hardware { console_driver, .. } = libtock::retrieve_hardware()?; let mut console = console_driver.create_console(); let mut with_callback = buttons::with_callback(|_, _| {}); let mut buttons = with_callback.init()?;
diff --git a/examples/button_subscribe.rs b/examples/button_subscribe.rs index 05a0cfe..afc8079 100644 --- a/examples/button_subscribe.rs +++ b/examples/button_subscribe.rs
@@ -10,7 +10,7 @@ // FIXME: Hangs up when buttons are pressed rapidly. Yielding in callback leads to stack overflow. #[libtock::main] async fn main() -> TockResult<()> { - let Hardware { console_driver } = libtock::retrieve_hardware()?; + let Hardware { console_driver, .. } = libtock::retrieve_hardware()?; let mut console = console_driver.create_console(); let mut with_callback = buttons::with_callback(|button_num: usize, state| { writeln!(
diff --git a/examples/gpio_read.rs b/examples/gpio_read.rs index 7c7493d..9a69b8e 100644 --- a/examples/gpio_read.rs +++ b/examples/gpio_read.rs
@@ -11,7 +11,7 @@ // example works on p0.03 #[libtock::main] async fn main() -> TockResult<()> { - let Hardware { console_driver } = libtock::retrieve_hardware()?; + let Hardware { console_driver, .. } = libtock::retrieve_hardware()?; let mut console = console_driver.create_console(); let pin = GpioPinUnitialized::new(0); let pin = pin.open_for_read(None, InputMode::PullDown)?;
diff --git a/examples/hardware_test.rs b/examples/hardware_test.rs index a98f378..8dd6da6 100644 --- a/examples/hardware_test.rs +++ b/examples/hardware_test.rs
@@ -34,7 +34,7 @@ #[libtock::main] async fn main() -> TockResult<()> { - let Hardware { console_driver } = libtock::retrieve_hardware()?; + let Hardware { console_driver, .. } = libtock::retrieve_hardware()?; let mut console = console_driver.create_console(); writeln!(console, "[test-results]")?;
diff --git a/examples/hello.rs b/examples/hello.rs index 81a629b..9bc98a8 100644 --- a/examples/hello.rs +++ b/examples/hello.rs
@@ -8,7 +8,7 @@ #[libtock::main] async fn main() -> TockResult<()> { - let Hardware { console_driver } = libtock::retrieve_hardware()?; + let Hardware { console_driver, .. } = libtock::retrieve_hardware()?; let mut console = console_driver.create_console(); let context = timer::DriverContext::create()?; let mut driver = context.create_timer_driver()?;
diff --git a/examples/sensors.rs b/examples/sensors.rs index 20e1f29..e24c95b 100644 --- a/examples/sensors.rs +++ b/examples/sensors.rs
@@ -10,7 +10,7 @@ #[libtock::main] async fn main() -> TockResult<()> { - let Hardware { console_driver } = libtock::retrieve_hardware()?; + let Hardware { console_driver, .. } = libtock::retrieve_hardware()?; let mut console = console_driver.create_console(); let mut humidity = HumiditySensor; let mut temperature = TemperatureSensor;
diff --git a/examples/simple_ble.rs b/examples/simple_ble.rs index 97511a0..7988c9e 100644 --- a/examples/simple_ble.rs +++ b/examples/simple_ble.rs
@@ -2,11 +2,11 @@ use libtock::ble_composer; use libtock::ble_composer::BlePayload; -use libtock::led; use libtock::result::TockResult; use libtock::simple_ble::BleAdvertisingDriver; use libtock::timer; use libtock::timer::Duration; +use libtock::Hardware; use serde::Serialize; #[derive(Serialize)] @@ -17,7 +17,9 @@ #[libtock::main] async fn main() -> TockResult<()> { - let led = led::get(0).unwrap(); + let Hardware { mut led_driver, .. } = libtock::retrieve_hardware()?; + + let mut led = led_driver.get(0).unwrap(); let uuid: [u8; 2] = [0x00, 0x18];
diff --git a/examples/temperature.rs b/examples/temperature.rs index 8143944..81245eb 100644 --- a/examples/temperature.rs +++ b/examples/temperature.rs
@@ -7,7 +7,7 @@ #[libtock::main] async fn main() -> TockResult<()> { - let Hardware { console_driver } = libtock::retrieve_hardware()?; + let Hardware { console_driver, .. } = libtock::retrieve_hardware()?; let mut console = console_driver.create_console(); let temperature = temperature::measure_temperature().await?; writeln!(console, "Temperature: {}", temperature).map_err(Into::into)
diff --git a/examples/timer_parallel.rs b/examples/timer_parallel.rs index c19e583..d640ebd 100644 --- a/examples/timer_parallel.rs +++ b/examples/timer_parallel.rs
@@ -1,19 +1,20 @@ #![no_std] use futures::future; -use libtock::led; +use libtock::led::Led; use libtock::result::TockResult; use libtock::timer; use libtock::timer::Duration; use libtock::timer::ParallelSleepDriver; +use libtock::Hardware; async fn blink<'a>( timer_driver: &'a ParallelSleepDriver<'a>, duration: Duration<usize>, - led_number: usize, + led: &'a mut Led<'a>, ) -> TockResult<()> { loop { - led::get(led_number).unwrap().toggle()?; + led.toggle()?; timer_driver.sleep(duration).await?; } @@ -21,13 +22,19 @@ #[libtock::main] async fn main() -> TockResult<()> { + let Hardware { mut led_driver, .. } = libtock::retrieve_hardware()?; + let mut led_iter = led_driver.all(); + let mut led_1 = led_iter.next().unwrap(); + let mut led_2 = led_iter.next().unwrap(); + let mut led_3 = led_iter.next().unwrap(); + let context = timer::DriverContext::create()?; let mut driver = context.create_timer_driver()?; let timer_driver = driver.activate()?; - let fut_1 = blink(&timer_driver, Duration::from_ms(500), 0); - let fut_2 = blink(&timer_driver, Duration::from_ms(333), 1); - let fut_3 = blink(&timer_driver, Duration::from_ms(250), 2); + let fut_1 = blink(&timer_driver, Duration::from_ms(500), &mut led_1); + let fut_2 = blink(&timer_driver, Duration::from_ms(333), &mut led_2); + let fut_3 = blink(&timer_driver, Duration::from_ms(250), &mut led_3); future::try_join3(fut_1, fut_2, fut_3).await?; Ok(())
diff --git a/examples/timer_subscribe.rs b/examples/timer_subscribe.rs index 471e924..d1f0123 100644 --- a/examples/timer_subscribe.rs +++ b/examples/timer_subscribe.rs
@@ -9,7 +9,7 @@ #[libtock::main] async fn main() -> TockResult<()> { - let Hardware { console_driver } = libtock::retrieve_hardware()?; + let Hardware { console_driver, .. } = libtock::retrieve_hardware()?; let mut console = console_driver.create_console(); let mut with_callback = timer::with_callback(|_, _| { writeln!(
diff --git a/src/hardware.rs b/src/hardware.rs new file mode 100644 index 0000000..9cf8e98 --- /dev/null +++ b/src/hardware.rs
@@ -0,0 +1,58 @@ +use crate::console::ConsoleDriver; +use crate::led::LedDriver; +use crate::result::OtherError; +use crate::result::TockError; +use crate::result::TockResult; + +/// Struct containing all drivers constructible through retrieve_hardware() +pub struct Hardware { + pub console_driver: ConsoleDriver, + pub led_driver: LedDriver, +} + +/// Retrieve Hardware struct. Returns Hardware only once. +pub fn retrieve_hardware() -> TockResult<Hardware> { + match unsafe { HARDWARE_SINGLETON.take() } { + Some(hardware) => Ok(hardware), + None => Err(TockError::Other(OtherError::DriverAlreadyTaken)), + } +} + +/// Retrieve [Hardware] struct without check whether it has already been taken +/// at a different point. +/// # Safety +/// This shall only used in special situations where drivers cannot be passed as arguments +/// as in the panic handler. Otherwise global mutable state (as shared buffers) may be exposed +/// in an unsafe manner. +pub unsafe fn retrieve_hardware_unsafe() -> Hardware { + HARDWARE +} + +const HARDWARE: Hardware = Hardware { + console_driver: ConsoleDriver { + _unconstructible: (), + }, + led_driver: LedDriver { + _unconstructible: (), + }, +}; + +static mut HARDWARE_SINGLETON: Option<Hardware> = Some(HARDWARE); + +#[cfg(test)] +mod test { + use crate::retrieve_hardware; + #[test] + pub fn can_be_retrieved_once() { + reset_hardware_singleton(); + + assert!(retrieve_hardware().is_ok()); + assert!(retrieve_hardware().is_err()); + } + + fn reset_hardware_singleton() { + unsafe { + super::HARDWARE_SINGLETON = Some(super::HARDWARE); + }; + } +}
diff --git a/src/lang_items.rs b/src/lang_items.rs index 197de47..0b3186e 100644 --- a/src/lang_items.rs +++ b/src/lang_items.rs
@@ -18,9 +18,9 @@ //! `rustc_main`. That's covered by the `_start` function in the root of this //! crate. -use crate::led; use crate::timer; use crate::timer::Duration; +use crate::Hardware; use core::alloc::Layout; use core::executor; use core::panic::PanicInfo; @@ -50,14 +50,16 @@ let context = timer::DriverContext::create().ok(); let mut driver = context.as_ref().map(|c| c.create_timer_driver_unsafe()); let timer_driver = driver.as_mut().and_then(|d| d.activate().ok()); + let Hardware { mut led_driver, .. } = crate::retrieve_hardware_unsafe(); + loop { - for led in led::all() { + for mut led in led_driver.all() { let _ = led.on(); } if let Some(ref timer_driver) = timer_driver { let _ = timer_driver.sleep(Duration::from_ms(100)).await; } - for led in led::all() { + for mut led in led_driver.all() { let _ = led.off(); } if let Some(ref timer_driver) = timer_driver { @@ -75,14 +77,16 @@ let context = timer::DriverContext::create().ok(); let mut driver = context.as_ref().map(|c| c.create_timer_driver_unsafe()); let timer_driver = driver.as_mut().and_then(|d| d.activate().ok()); + let Hardware { mut led_driver, .. } = crate::retrieve_hardware_unsafe(); + loop { - for led in led::all() { + for mut led in led_driver.all() { let _ = led.on(); } if let Some(ref timer_driver) = timer_driver { let _ = timer_driver.sleep(Duration::from_ms(100)).await; } - for led in led::all() { + for mut led in led_driver.all() { let _ = led.off(); } if let Some(ref timer_driver) = timer_driver {
diff --git a/src/led.rs b/src/led.rs index d7aac8f..ded7d01 100644 --- a/src/led.rs +++ b/src/led.rs
@@ -1,5 +1,6 @@ use crate::result::TockResult; use crate::syscalls::command; +use core::marker::PhantomData; const DRIVER_NUMBER: usize = 0x00002; @@ -10,33 +11,45 @@ pub const TOGGLE: usize = 3; } -pub struct Led { +pub struct LedDriver { + pub(crate) _unconstructible: (), +} + +pub struct Led<'a> { led_num: usize, + phantom: PhantomData<&'a mut ()>, } -pub fn count() -> TockResult<usize> { - command(DRIVER_NUMBER, command_nr::COUNT, 0, 0).map_err(Into::into) -} +impl LedDriver { + pub fn get(&mut self, led_num: usize) -> Option<Led> { + if led_num < self.count().ok().unwrap() { + Some(Led { + led_num, + phantom: PhantomData, + }) + } else { + None + } + } -pub fn get(led_num: usize) -> Option<Led> { - if led_num < count().ok().unwrap() { - Some(Led { led_num }) - } else { - None + pub fn count(&self) -> TockResult<usize> { + command(DRIVER_NUMBER, command_nr::COUNT, 0, 0).map_err(Into::into) + } + + pub fn all(&mut self) -> LedIter { + LedIter { + curr_led: 0, + led_count: self.count().unwrap_or(0), + phantom: PhantomData, + } } } /// Returns an iterator over all available LEDs. If the LED driver is not /// present, the iterator will be empty. -pub fn all() -> LedIter { - LedIter { - curr_led: 0, - led_count: count().unwrap_or(0), - } -} -impl Led { - pub fn set_state(&self, state: bool) -> TockResult<()> { +impl<'a> Led<'a> { + pub fn set_state(&mut self, state: bool) -> TockResult<()> { if state { self.on() } else { @@ -44,35 +57,41 @@ } } - pub fn on(&self) -> TockResult<()> { + pub fn on(&mut self) -> TockResult<()> { command(DRIVER_NUMBER, command_nr::ON, self.led_num, 0)?; Ok(()) } - pub fn off(&self) -> TockResult<()> { + pub fn off(&mut self) -> TockResult<()> { command(DRIVER_NUMBER, command_nr::OFF, self.led_num, 0)?; Ok(()) } - pub fn toggle(&self) -> TockResult<()> { + pub fn toggle(&mut self) -> TockResult<()> { command(DRIVER_NUMBER, command_nr::TOGGLE, self.led_num, 0)?; Ok(()) } + + pub fn number(&self) -> usize { + self.led_num + } } #[derive(Copy, Clone)] -pub struct LedIter { +pub struct LedIter<'a> { curr_led: usize, led_count: usize, + phantom: PhantomData<&'a ()>, } -impl Iterator for LedIter { - type Item = Led; +impl<'a> Iterator for LedIter<'a> { + type Item = Led<'a>; fn next(&mut self) -> Option<Self::Item> { if self.curr_led < self.led_count { let item = Led { led_num: self.curr_led, + phantom: PhantomData, }; self.curr_led += 1; Some(item)
diff --git a/src/lib.rs b/src/lib.rs index 9d5ba70..2019925 100644 --- a/src/lib.rs +++ b/src/lib.rs
@@ -31,56 +31,11 @@ pub mod syscalls; -use crate::console::ConsoleDriver; pub use libtock_codegen::main; +mod hardware; +pub use hardware::*; + /// Dummy structure to force importing the panic_handler and other no_std elements when nothing else /// is imported. pub struct LibTock; - -/// Struct containing all drivers constructible through retrieve_hardware() -pub struct Hardware { - pub console_driver: ConsoleDriver, -} - -use result::OtherError; -use result::TockError; -use result::TockResult; - -/// Retrieve Hardware struct. Returns Hardware only once. -pub fn retrieve_hardware() -> TockResult<Hardware> { - match unsafe { HARDWARE.take() } { - Some(hardware) => Ok(hardware), - None => Err(TockError::Other(OtherError::DriverAlreadyTaken)), - } -} - -static mut HARDWARE: Option<Hardware> = Some(Hardware { - console_driver: ConsoleDriver { - _unconstructible: (), - }, -}); - -#[cfg(test)] -mod test { - use crate::console::ConsoleDriver; - use crate::retrieve_hardware; - use crate::Hardware; - #[test] - pub fn can_be_retrieved_once() { - reset_hardware_singleton(); - - assert!(retrieve_hardware().is_ok()); - assert!(retrieve_hardware().is_err()); - } - - fn reset_hardware_singleton() { - unsafe { - super::HARDWARE = Some(Hardware { - console_driver: ConsoleDriver { - _unconstructible: (), - }, - }) - }; - } -}