Make console only constructible from Hardware singleton
diff --git a/examples/adc.rs b/examples/adc.rs index 61894ad..83b5919 100644 --- a/examples/adc.rs +++ b/examples/adc.rs
@@ -2,10 +2,10 @@ use core::fmt::Write; use libtock::adc; -use libtock::console::Console; use libtock::result::TockResult; use libtock::timer; use libtock::timer::Duration; +use libtock::Hardware; #[libtock::main] async fn main() -> TockResult<()> { @@ -13,7 +13,8 @@ let mut driver = context.create_timer_driver()?; let timer_driver = driver.activate()?; - let mut console = Console::default(); + 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 406bf57..067c67d 100644 --- a/examples/adc_buffer.rs +++ b/examples/adc_buffer.rs
@@ -3,14 +3,15 @@ use core::fmt::Write; use libtock::adc; use libtock::adc::AdcBuffer; -use libtock::console::Console; use libtock::result::TockResult; use libtock::syscalls; +use libtock::Hardware; #[libtock::main] /// Reads a 128 byte sample into a buffer and prints the first value to the console. async fn main() -> TockResult<()> { - let mut console = Console::default(); + 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/button_read.rs b/examples/button_read.rs index d86e70d..32714de 100644 --- a/examples/button_read.rs +++ b/examples/button_read.rs
@@ -3,14 +3,15 @@ use core::fmt::Write; use libtock::buttons; use libtock::buttons::ButtonState; -use libtock::console::Console; use libtock::result::TockResult; use libtock::timer; use libtock::timer::Duration; +use libtock::Hardware; #[libtock::main] async fn main() -> TockResult<()> { - let mut console = Console::default(); + 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()?; let mut button = buttons.iter_mut().next().unwrap();
diff --git a/examples/button_subscribe.rs b/examples/button_subscribe.rs index 3453c9b..05a0cfe 100644 --- a/examples/button_subscribe.rs +++ b/examples/button_subscribe.rs
@@ -4,14 +4,14 @@ use futures::future; use libtock::buttons; use libtock::buttons::ButtonState; -use libtock::console::Console; use libtock::result::TockResult; +use libtock::Hardware; // FIXME: Hangs up when buttons are pressed rapidly. Yielding in callback leads to stack overflow. #[libtock::main] async fn main() -> TockResult<()> { - let mut console = Console::default(); - + 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!( console,
diff --git a/examples/gpio_read.rs b/examples/gpio_read.rs index ad871ac..7c7493d 100644 --- a/examples/gpio_read.rs +++ b/examples/gpio_read.rs
@@ -1,17 +1,18 @@ #![no_std] use core::fmt::Write; -use libtock::console::Console; use libtock::gpio::GpioPinUnitialized; use libtock::gpio::InputMode; use libtock::result::TockResult; use libtock::timer; use libtock::timer::Duration; +use libtock::Hardware; // example works on p0.03 #[libtock::main] async fn main() -> TockResult<()> { - let mut console = Console::default(); + 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)?; let context = timer::DriverContext::create()?;
diff --git a/examples/hardware_test.rs b/examples/hardware_test.rs index 4f8ad5f..a98f378 100644 --- a/examples/hardware_test.rs +++ b/examples/hardware_test.rs
@@ -12,6 +12,7 @@ use libtock::result::TockResult; use libtock::timer; use libtock::timer::Duration; +use libtock::Hardware; static mut STATIC: usize = 0; @@ -33,7 +34,8 @@ #[libtock::main] async fn main() -> TockResult<()> { - let mut console = Console::default(); + let Hardware { console_driver } = libtock::retrieve_hardware()?; + let mut console = console_driver.create_console(); writeln!(console, "[test-results]")?; test_heap(&mut console);
diff --git a/examples/hello.rs b/examples/hello.rs index 5e4f987..81a629b 100644 --- a/examples/hello.rs +++ b/examples/hello.rs
@@ -1,14 +1,15 @@ #![no_std] use core::fmt::Write; -use libtock::console::Console; use libtock::result::TockResult; use libtock::timer; use libtock::timer::Duration; +use libtock::Hardware; #[libtock::main] async fn main() -> TockResult<()> { - let mut console = Console::default(); + 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()?; let timer_driver = driver.activate()?;
diff --git a/examples/sensors.rs b/examples/sensors.rs index 9936d31..20e1f29 100644 --- a/examples/sensors.rs +++ b/examples/sensors.rs
@@ -1,16 +1,17 @@ #![no_std] use core::fmt::Write; -use libtock::console::Console; use libtock::result::TockResult; use libtock::sensors::Ninedof; use libtock::sensors::*; use libtock::timer; use libtock::timer::Duration; +use libtock::Hardware; #[libtock::main] async fn main() -> TockResult<()> { - let mut console = Console::default(); + let Hardware { console_driver } = libtock::retrieve_hardware()?; + let mut console = console_driver.create_console(); let mut humidity = HumiditySensor; let mut temperature = TemperatureSensor; let mut light = AmbientLightSensor;
diff --git a/examples/temperature.rs b/examples/temperature.rs index 8a3eef0..8143944 100644 --- a/examples/temperature.rs +++ b/examples/temperature.rs
@@ -1,13 +1,14 @@ #![no_std] use core::fmt::Write; -use libtock::console::Console; use libtock::result::TockResult; use libtock::temperature; +use libtock::Hardware; #[libtock::main] async fn main() -> TockResult<()> { - let mut console = Console::default(); + 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_subscribe.rs b/examples/timer_subscribe.rs index 11afdfd..471e924 100644 --- a/examples/timer_subscribe.rs +++ b/examples/timer_subscribe.rs
@@ -2,15 +2,15 @@ use core::fmt::Write; use futures::future; -use libtock::console::Console; use libtock::result::TockResult; use libtock::timer; use libtock::timer::Duration; +use libtock::Hardware; #[libtock::main] async fn main() -> TockResult<()> { - let mut console = Console::default(); - + let Hardware { console_driver } = libtock::retrieve_hardware()?; + let mut console = console_driver.create_console(); let mut with_callback = timer::with_callback(|_, _| { writeln!( console,
diff --git a/run_all_checks.sh b/run_all_checks.sh new file mode 100755 index 0000000..c989212 --- /dev/null +++ b/run_all_checks.sh
@@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -eux + +cargo fmt --all -- --check +cargo test --workspace +cargo clippy --workspace --all-targets +./build_examples.sh \ No newline at end of file
diff --git a/src/console.rs b/src/console.rs index bfcd6d7..fb65af7 100644 --- a/src/console.rs +++ b/src/console.rs
@@ -20,6 +20,18 @@ pub const SHARE_BUFFER: usize = 1; } +pub struct ConsoleDriver { + pub(crate) _unconstructible: (), +} + +impl ConsoleDriver { + pub fn create_console(self) -> Console { + Console { + allow_buffer: [0; 64], + } + } +} + pub struct Console { allow_buffer: [u8; 64], }
diff --git a/src/lib.rs b/src/lib.rs index 8873c33..9d5ba70 100644 --- a/src/lib.rs +++ b/src/lib.rs
@@ -31,8 +31,56 @@ pub mod syscalls; +use crate::console::ConsoleDriver; pub use libtock_codegen::main; -// Dummy structure to force importing the panic_handler and other no_std elements when nothing else -// is imported. +/// 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: (), + }, + }) + }; + } +}