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: (),
+                },
+            })
+        };
+    }
+}