diff --git a/.gitmodules b/.gitmodules
index e02c0e3e66e00a447c512b1a4273dfec1946feb8..4cf50dcd88df024b2601d2b66d196b6b1ff3fd1a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
-[submodule "c"]
-	path = c
+[submodule "card10-sys/firmware"]
+	path = card10-sys/firmware
 	url = https://git.card10.badge.events.ccc.de/card10/firmware.git
diff --git a/Cargo.lock b/Cargo.lock
index 4c5dbc7e1c401dde15195de86bb2ee6cb21d616c..362737c0c4718f6c3ca110cae94ca0c2e1c87392 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -80,6 +80,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 [[package]]
 name = "card10-l0dable"
 version = "0.1.1"
+dependencies = [
+ "card10-sys 0.1.0",
+]
+
+[[package]]
+name = "card10-sys"
+version = "0.1.0"
 dependencies = [
  "bindgen 0.51.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index abacb54b54a7d6d93d904c616cf49ed7906ca5ba..121d83969b85dfca59a9a1a8bc616467b144fcff 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,9 +1,11 @@
 [workspace]
 members = [
-  "l0dable",
+  "card10-sys",
+  "card10-l0dable",
   "example",
   "rkanoid",
 ]
+
 default-members = [
   "example",
   "rkanoid",
diff --git a/README.md b/README.md
index 9ef549383fa6545a12e99f3aa9f8a5f3bce1704d..ede1b4beff502748b01c8507228f5461051d50ff 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ https://firmware.card10.badge.events.ccc.de/how-to-build.html this
 should work as following:
 
 ```shell
-cd c/
+cd card10-sys/firmware
 ./bootstrap -Djailbreak_card10=true
 ninja -C build/
 ```
@@ -61,10 +61,63 @@ And then copy `build/pycardium/pycardium_epicardium.bin` as
 
 ## Build and run Rust loadables
 
+### Setup
+
+If you want to come up with your own rust based loadable crate a few
+preparations are required:
+
+  - Setup the new crate repository.
+ 
+  - Add `card10-l0dable = "^0.1"` as a dependency to your new crate.
+ 
+  - Change the configuration of the default cargo release profile inside your
+    `Cargo.toml` file:
+ 
+    ```
+    [profile.release]
+    opt-level = "s"
+    panic = "abort"
+    ```
+
+  - Create (or update) the `thumbv7em-none-eabi` target configuration at
+    `$PROJECT/.cargo/config` with the following rustflags:
+ 
+    ```
+    [target.thumbv7em-none-eabi]
+    rustflags = [
+      "-C", "linker=arm-none-eabi-gcc",
+      "-C", "link-args=-Tl0dable.ld -n -pie -fPIC",
+      "-C", "relocation-model=pic",
+    ]
+
+    [build]
+    target = "thumbv7em-none-eabi"
+    ```
+
+  - Ensure that your crate is marked as a `non_std` project and make
+    `card10-l0dable` aware of your custom main function. This should require
+    the following update to your `main.rs` file.
+
+    ```main.rs
+    #![no_std]
+    #![no_main]
+
+    use card10_l0dable::main;
+
+    main!(main);
+    fn main() {}
+    ```
+
+### Compilation
+
+To compile the project use the nightly toolchain and define the proper target.
+
 ```shell
 cargo +nightly build --release --target thumbv7em-none-eabi
 ```
 
+### Transfer to card10
+
 Then copy the resulting executable from the target directory 
 `target/thumbv7em-none-eabi/release/example` into the
 `apps` directory of your badge.
@@ -74,25 +127,25 @@ extension (e.g `example` must be renamed as `example.elf`).
 
 ## Crates
 
-| Crate    | Description                                               |
-| ----     | ---                                                       |
-| l0dable  | Helper crate for building l0dables                        |
-| example  | l0dable example                                           |
-| rkanoid  | Arkanoid clone                                            |
+| Crate           | Description                                               |
+| ----            | ---                                                       |
+| card10-l0dable  | Helper crate for building l0dables                        |
+| example         | l0dable example                                           |
+| rkanoid         | Arkanoid clone                                            |
 
 
 ## Misc
 
 ### How to update the firmware bindings
 
-1) Update the `c/` submodule to the latest firmware state.
+1) Update the `card10-sys/firmware` submodule to the latest firmware state.
 
 2) Rebuild the firmware as described above.
 
 3) Run the following script from the project root directory
 
    ```shell
-   python c/epicardium/api/genapi.py -H c/epicardium/epicardium.h -c l0dable/src/client.c -s l0dable/src/server.c
+   python card10-sys/firmware/epicardium/api/genapi.py -H card10-sys/firmware/epicardium/epicardium.h -c card10-sys/vendor/client.c -s card10-sys/vendor/server.c
    ```
 
 4) Rebuild your app :)
diff --git a/l0dable/Cargo.toml b/card10-l0dable/Cargo.toml
similarity index 65%
rename from l0dable/Cargo.toml
rename to card10-l0dable/Cargo.toml
index a23070dd8cb6fd28e007d21140e533e367ed41ed..96880ced0aa0403563f51380d63f891871e40e49 100644
--- a/l0dable/Cargo.toml
+++ b/card10-l0dable/Cargo.toml
@@ -14,20 +14,8 @@ keywords = [
     "l0dable",
 ]
 categories = ["no-std"]
-description = """
-make l0dables for the Card10 (CCCamp 2019) badge
-"""
-include = [
-    "**/*.rs",
-    "Cargo.toml",
-    "l0dable.ld",
-    "../c/",
-]
+description = "make l0dables for the Card10 (CCCamp 2019) badge"
 
 [dependencies]
-r0 = "0.2"
-panic-abort = "0.3"
+card10-sys = { path = "../card10-sys", version = "^0.1" }
 
-[build-dependencies]
-cc = "1.0"
-bindgen = "0.51"
diff --git a/l0dable/LICENSE-APACHE b/card10-l0dable/LICENSE-APACHE
similarity index 100%
rename from l0dable/LICENSE-APACHE
rename to card10-l0dable/LICENSE-APACHE
diff --git a/l0dable/LICENSE-MIT b/card10-l0dable/LICENSE-MIT
similarity index 100%
rename from l0dable/LICENSE-MIT
rename to card10-l0dable/LICENSE-MIT
diff --git a/l0dable/src/bhi160.rs b/card10-l0dable/src/bhi160.rs
similarity index 99%
rename from l0dable/src/bhi160.rs
rename to card10-l0dable/src/bhi160.rs
index 9569a4b1338a399a4a1320d5cdca94dfada8a647..1e68872e26517baadc095da4d307d1e008569b12 100644
--- a/l0dable/src/bhi160.rs
+++ b/card10-l0dable/src/bhi160.rs
@@ -4,7 +4,7 @@ use core::{
     mem::MaybeUninit,
 };
 
-use crate::{bindings::*, errno};
+use card10_sys::*;
 
 pub trait SensorType {
     /// sensor_type in C, sensor_id in Python
diff --git a/l0dable/src/bme680.rs b/card10-l0dable/src/bme680.rs
similarity index 87%
rename from l0dable/src/bme680.rs
rename to card10-l0dable/src/bme680.rs
index d2e3af27d6e4a32b07df92280c06d6ac259bee4f..719361a07a2306673187fb9b14d6b330da557cd8 100644
--- a/l0dable/src/bme680.rs
+++ b/card10-l0dable/src/bme680.rs
@@ -1,5 +1,5 @@
+use card10_sys::*;
 use core::mem::uninitialized;
-use super::bindings::*;
 
 pub struct BME680;
 pub type SensorData = bme680_sensor_data;
@@ -24,6 +24,8 @@ impl BME680 {
 
 impl Drop for BME680 {
     fn drop(&mut self) {
-        unsafe { epic_bme680_deinit(); }
+        unsafe {
+            epic_bme680_deinit();
+        }
     }
 }
diff --git a/l0dable/src/buttons.rs b/card10-l0dable/src/buttons.rs
similarity index 72%
rename from l0dable/src/buttons.rs
rename to card10-l0dable/src/buttons.rs
index 5bb633fef592b4209f44b5c814cd151038d5d3f5..dc033618c1ec0c727655572ca0811ee83a9fff83 100644
--- a/l0dable/src/buttons.rs
+++ b/card10-l0dable/src/buttons.rs
@@ -1,4 +1,4 @@
-use super::bindings::*;
+use card10_sys::*;
 
 pub struct Buttons {
     state: u32,
@@ -6,12 +6,11 @@ pub struct Buttons {
 
 impl Buttons {
     pub fn read() -> Self {
-        let mask =
-            epic_button_BUTTON_LEFT_BOTTOM |
-            epic_button_BUTTON_RIGHT_BOTTOM |
-            epic_button_BUTTON_LEFT_TOP |
-            epic_button_BUTTON_RIGHT_TOP |
-            epic_button_BUTTON_RESET;
+        let mask = epic_button_BUTTON_LEFT_BOTTOM
+            | epic_button_BUTTON_RIGHT_BOTTOM
+            | epic_button_BUTTON_LEFT_TOP
+            | epic_button_BUTTON_RIGHT_TOP
+            | epic_button_BUTTON_RESET;
         let state = unsafe { epic_buttons_read(mask as u8) }.into();
         Buttons { state }
     }
diff --git a/l0dable/src/display.rs b/card10-l0dable/src/display.rs
similarity index 72%
rename from l0dable/src/display.rs
rename to card10-l0dable/src/display.rs
index 84994cbc1bd5a9709ce3b68c6630c32b79bf4d61..c6ebb5e17934384f2076c5f99fb201b2f284de3a 100644
--- a/l0dable/src/display.rs
+++ b/card10-l0dable/src/display.rs
@@ -1,5 +1,5 @@
-use super::bindings::*;
 use super::framebuffer::FrameBuffer;
+use card10_sys::*;
 
 #[derive(Debug, Clone, Copy)]
 #[repr(C)]
@@ -32,9 +32,7 @@ impl Color {
 
     pub fn rgb8(r8: u8, g8: u8, b8: u8) -> Self {
         let c =
-            ((u16::from(r8) & 0xF8) << 8) |
-            ((u16::from(g8) & 0xFA) << 3) |
-            (u16::from(b8) & 0xF8);
+            ((u16::from(r8) & 0xF8) << 8) | ((u16::from(g8) & 0xFA) << 3) | (u16::from(b8) & 0xF8);
         Color(c)
     }
 
@@ -84,16 +82,22 @@ impl Display {
     pub const FONT_H: u16 = 20;
 
     pub fn open() -> Self {
-        unsafe { epic_disp_open(); }
+        unsafe {
+            epic_disp_open();
+        }
         Display
     }
 
     pub fn update(&self) {
-        unsafe { epic_disp_update(); }
+        unsafe {
+            epic_disp_update();
+        }
     }
 
     pub fn clear(&self, color: Color) {
-        unsafe { epic_disp_clear(color.0); }
+        unsafe {
+            epic_disp_clear(color.0);
+        }
     }
 
     /// s must be 0-terminated
@@ -109,19 +113,45 @@ impl Display {
         }
     }
 
-    pub fn line(&self, x1: u16, y1: u16, x2: u16, y2: u16, color: Color, linestyle: LineStyle, pixelsize: u16) {
+    pub fn line(
+        &self,
+        x1: u16,
+        y1: u16,
+        x2: u16,
+        y2: u16,
+        color: Color,
+        linestyle: LineStyle,
+        pixelsize: u16,
+    ) {
         unsafe {
             epic_disp_line(x1, y1, x2, y2, color.0, linestyle as u32, pixelsize);
         }
     }
 
-    pub fn rect(&self, x1: u16, y1: u16, x2: u16, y2: u16, color: Color, fillstyle: FillStyle, pixelsize: u16) {
+    pub fn rect(
+        &self,
+        x1: u16,
+        y1: u16,
+        x2: u16,
+        y2: u16,
+        color: Color,
+        fillstyle: FillStyle,
+        pixelsize: u16,
+    ) {
         unsafe {
             epic_disp_rect(x1, y1, x2, y2, color.0, fillstyle as u32, pixelsize);
         }
     }
 
-    pub fn circ(&self, x: u16, y: u16, rad: u16, color: Color, fillstyle: FillStyle, pixelsize: u16) {
+    pub fn circ(
+        &self,
+        x: u16,
+        y: u16,
+        rad: u16,
+        color: Color,
+        fillstyle: FillStyle,
+        pixelsize: u16,
+    ) {
         unsafe {
             epic_disp_circ(x, y, rad, color.0, fillstyle as u32, pixelsize);
         }
@@ -134,6 +164,8 @@ impl Display {
 
 impl Drop for Display {
     fn drop(&mut self) {
-        unsafe { epic_disp_close(); }
+        unsafe {
+            epic_disp_close();
+        }
     }
 }
diff --git a/l0dable/src/fmt_buffer.rs b/card10-l0dable/src/fmt_buffer.rs
similarity index 100%
rename from l0dable/src/fmt_buffer.rs
rename to card10-l0dable/src/fmt_buffer.rs
diff --git a/l0dable/src/framebuffer/font.rs b/card10-l0dable/src/framebuffer/font.rs
similarity index 100%
rename from l0dable/src/framebuffer/font.rs
rename to card10-l0dable/src/framebuffer/font.rs
diff --git a/l0dable/src/framebuffer/mod.rs b/card10-l0dable/src/framebuffer/mod.rs
similarity index 77%
rename from l0dable/src/framebuffer/mod.rs
rename to card10-l0dable/src/framebuffer/mod.rs
index 2794369303cb113abfbf582439776f112c712eec..7d1d07d93800a3dd1d30eac1368e79235281162a 100644
--- a/l0dable/src/framebuffer/mod.rs
+++ b/card10-l0dable/src/framebuffer/mod.rs
@@ -1,7 +1,7 @@
+use crate::Display;
+use card10_sys::*;
 use core::mem::{transmute, uninitialized};
 use core::ops::{Index, IndexMut};
-use crate::bindings::*;
-use crate::Display;
 
 mod font;
 pub use font::*;
@@ -13,14 +13,11 @@ pub struct FrameBuffer<'d> {
     buffer: disp_framebuffer,
 }
 
-
 impl<'d> FrameBuffer<'d> {
     pub fn uninitialized(display: &'d Display) -> Self {
         FrameBuffer {
             _display: display,
-            buffer: unsafe {
-                uninitialized()
-            },
+            buffer: unsafe { uninitialized() },
         }
     }
 
@@ -33,18 +30,26 @@ impl<'d> FrameBuffer<'d> {
     pub fn clear(&mut self, color: RawColor) {
         for y in 0..Display::H {
             for x in 0..Display::W {
-                let bytes: &mut RawColor = unsafe {
-                    transmute(&mut self.buffer.fb[y as usize][x as usize])
-                };
+                let bytes: &mut RawColor =
+                    unsafe { transmute(&mut self.buffer.fb[y as usize][x as usize]) };
                 *bytes = color;
             }
         }
     }
 
-    pub fn text<'a, 'f>(&'a mut self, x: isize, y: isize, font: &'f Font, color: RawColor) -> TextRenderer<'a, 'd, 'f> {
+    pub fn text<'a, 'f>(
+        &'a mut self,
+        x: isize,
+        y: isize,
+        font: &'f Font,
+        color: RawColor,
+    ) -> TextRenderer<'a, 'd, 'f> {
         TextRenderer {
             framebuffer: self,
-            x, y, font, color,
+            x,
+            y,
+            font,
+            color,
         }
     }
 }
@@ -54,9 +59,7 @@ impl<'d> Index<(u16, u16)> for FrameBuffer<'d> {
     fn index(&self, (x, y): (u16, u16)) -> &Self::Output {
         let x = usize::from(Display::W - 1 - x);
         let y = usize::from(Display::H - 1 - y);
-        unsafe {
-            transmute(&self.buffer.fb[y][x])
-        }
+        unsafe { transmute(&self.buffer.fb[y][x]) }
     }
 }
 
@@ -64,9 +67,7 @@ impl<'d> IndexMut<(u16, u16)> for FrameBuffer<'d> {
     fn index_mut(&mut self, (x, y): (u16, u16)) -> &mut Self::Output {
         let x = usize::from(Display::W - 1 - x);
         let y = usize::from(Display::H - 1 - y);
-        unsafe {
-            transmute(&mut self.buffer.fb[y][x])
-        }
+        unsafe { transmute(&mut self.buffer.fb[y][x]) }
     }
 }
 
diff --git a/l0dable/src/framebuffer/text.rs b/card10-l0dable/src/framebuffer/text.rs
similarity index 100%
rename from l0dable/src/framebuffer/text.rs
rename to card10-l0dable/src/framebuffer/text.rs
diff --git a/l0dable/src/fs.rs b/card10-l0dable/src/fs.rs
similarity index 76%
rename from l0dable/src/fs.rs
rename to card10-l0dable/src/fs.rs
index d5f89f29af5d934f0b581588865a584a4b6c1925..4148023db079a1f54e9d17314c1fcf34c9189077 100644
--- a/l0dable/src/fs.rs
+++ b/card10-l0dable/src/fs.rs
@@ -1,6 +1,7 @@
-use core::str::from_utf8_unchecked;
 use core::mem::uninitialized;
-use super::bindings::*;
+use core::str::from_utf8_unchecked;
+
+use card10_sys::*;
 
 type Result<T> = core::result::Result<T, Error>;
 
@@ -28,9 +29,7 @@ impl From<i32> for Error {
 
 pub fn read_dir(path: &str) -> Result<ReadDir> {
     let pathbuf = crate::str_to_cstr(path);
-    Error::check(|| unsafe {
-        epic_file_opendir(pathbuf.as_ptr())
-    }).map(|fd| ReadDir { fd })
+    Error::check(|| unsafe { epic_file_opendir(pathbuf.as_ptr()) }).map(|fd| ReadDir { fd })
 }
 
 pub struct ReadDir {
@@ -68,7 +67,7 @@ pub struct epic_stat {
     /// not u32 as generated by bindgen
     pub type_: epic_stat_type,
     pub size: u32,
-    pub name: [super::ctypes::c_char; 256usize],
+    pub name: [ctypes::c_char; 256usize],
     pub _reserved: [u8; 12usize],
 }
 
@@ -97,20 +96,15 @@ impl DirStat {
     }
 
     pub fn name(&self) -> &str {
-        let len = self.entry.name.iter().position(|b| *b == 0)
-            .unwrap_or(0);
-        unsafe {
-            from_utf8_unchecked(&self.entry.name[0..len])
-        }
+        let len = self.entry.name.iter().position(|b| *b == 0).unwrap_or(0);
+        unsafe { from_utf8_unchecked(&self.entry.name[0..len]) }
     }
 }
 
 pub fn rename(from: &str, to: &str) -> Result<()> {
     let frombuf = crate::str_to_cstr(from);
     let tobuf = crate::str_to_cstr(to);
-    Error::check(|| unsafe {
-        epic_file_rename(frombuf.as_ptr(), tobuf.as_ptr())
-    }).map(|_| ())
+    Error::check(|| unsafe { epic_file_rename(frombuf.as_ptr(), tobuf.as_ptr()) }).map(|_| ())
 }
 
 pub struct File {
@@ -121,21 +115,22 @@ impl File {
     pub fn open(path: &str) -> Result<File> {
         let pathbuf = crate::str_to_cstr(path);
         let modebuf = b"r\0";
-        Error::check(|| unsafe {
-            epic_file_open(pathbuf.as_ptr(), modebuf.as_ptr())
-        }).map(|fd| File { fd })
+        Error::check(|| unsafe { epic_file_open(pathbuf.as_ptr(), modebuf.as_ptr()) })
+            .map(|fd| File { fd })
     }
 
     pub fn read<'a>(&mut self, buf: &'a mut [u8]) -> Result<&'a [u8]> {
-        let bytes = Error::check(|| unsafe {
-            epic_file_read(self.fd, buf.as_ptr() as *mut _, buf.len())
-        })? as usize;
+        let bytes =
+            Error::check(|| unsafe { epic_file_read(self.fd, buf.as_ptr() as *mut _, buf.len()) })?
+                as usize;
         Ok(&buf[0..bytes])
     }
 }
 
 impl Drop for File {
     fn drop(&mut self) {
-        unsafe { epic_file_close(self.fd); }
+        unsafe {
+            epic_file_close(self.fd);
+        }
     }
 }
diff --git a/card10-l0dable/src/lib.rs b/card10-l0dable/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..bf0bf40148f54a7db98b9395d38fd313b3dbba79
--- /dev/null
+++ b/card10-l0dable/src/lib.rs
@@ -0,0 +1,41 @@
+#![no_std]
+
+mod os;
+pub use os::*;
+mod display;
+pub use display::{Color, Display, FillStyle, LineStyle};
+mod buttons;
+pub mod framebuffer;
+pub use buttons::Buttons;
+pub mod uart;
+pub const UART: uart::Uart = uart::Uart;
+mod light_sensor;
+pub use light_sensor::LightSensor;
+mod rtc;
+pub mod trng;
+pub mod vibra;
+pub use rtc::{MilliSeconds, Seconds, Time};
+mod fmt_buffer;
+pub use fmt_buffer::{str_to_cstr, FmtBuffer};
+mod bme680;
+pub use bme680::BME680;
+mod bhi160;
+pub use bhi160::{
+    Accelerometer, Error as BHI160Error, Gyroscope, Orientation, Sensor as BHI160,
+    SensorData as BHI160Data,
+};
+pub mod fs;
+
+/// Type check the user-supplied entry function.
+#[macro_export]
+macro_rules! main {
+    ($path:path) => {
+        #[export_name = "main"]
+        pub unsafe fn __main() {
+            // type check the given path
+            let f: fn() = $path;
+
+            f()
+        }
+    };
+}
diff --git a/l0dable/src/light_sensor.rs b/card10-l0dable/src/light_sensor.rs
similarity index 87%
rename from l0dable/src/light_sensor.rs
rename to card10-l0dable/src/light_sensor.rs
index a6aa16745530505202b70ad07b757ef4ac0cad86..f68e0351f12e38cbbf3133fb592f549d0cffb1ee 100644
--- a/l0dable/src/light_sensor.rs
+++ b/card10-l0dable/src/light_sensor.rs
@@ -1,4 +1,4 @@
-use super::bindings::*;
+use card10_sys::*;
 
 pub struct LightSensor {
     // Prevent creation of this struct by all but this module.
@@ -25,6 +25,8 @@ impl LightSensor {
 
 impl Drop for LightSensor {
     fn drop(&mut self) {
-        unsafe { epic_light_sensor_stop(); }
+        unsafe {
+            epic_light_sensor_stop();
+        }
     }
 }
diff --git a/l0dable/src/os.rs b/card10-l0dable/src/os.rs
similarity index 93%
rename from l0dable/src/os.rs
rename to card10-l0dable/src/os.rs
index af7a2283924cf08464b0981f711d35b62753683c..e209671614d31cae2d746c3f1e733470d1f57693 100644
--- a/l0dable/src/os.rs
+++ b/card10-l0dable/src/os.rs
@@ -1,4 +1,4 @@
-use super::bindings::*;
+use card10_sys::*;
 
 pub fn exec(path: &str) -> ! {
     let mut pathbuf = super::str_to_cstr(path);
diff --git a/l0dable/src/rtc.rs b/card10-l0dable/src/rtc.rs
similarity index 97%
rename from l0dable/src/rtc.rs
rename to card10-l0dable/src/rtc.rs
index d7741f4006607c7aba72080a942f6afe196ea9c3..cdf25a58c8bfc9369e2d483fc84c51a9ac2053bf 100644
--- a/l0dable/src/rtc.rs
+++ b/card10-l0dable/src/rtc.rs
@@ -1,5 +1,5 @@
+use card10_sys::*;
 use core::ops::Sub;
-use super::bindings::*;
 
 pub trait Time {
     fn time() -> Self;
diff --git a/l0dable/src/trng.rs b/card10-l0dable/src/trng.rs
similarity index 81%
rename from l0dable/src/trng.rs
rename to card10-l0dable/src/trng.rs
index b4635fa72b3386139a87f035e25f8d67e0d61b26..7bceca95a893ee76481ca1f791309619f423bef9 100644
--- a/l0dable/src/trng.rs
+++ b/card10-l0dable/src/trng.rs
@@ -1,4 +1,4 @@
-use super::bindings::*;
+use card10_sys::*;
 
 pub fn read(dest: &mut [u8]) -> bool {
     unsafe { epic_trng_read(dest.as_mut_ptr(), dest.len()) != 0 }
diff --git a/l0dable/src/uart.rs b/card10-l0dable/src/uart.rs
similarity index 96%
rename from l0dable/src/uart.rs
rename to card10-l0dable/src/uart.rs
index b164a6c7cfaf65020a41b01b9b6f1339235480f5..7dd860e9614086f5ced9c1d16e09104c03306637 100644
--- a/l0dable/src/uart.rs
+++ b/card10-l0dable/src/uart.rs
@@ -1,6 +1,7 @@
-use super::bindings::*;
 use core::fmt::Write;
 
+use card10_sys::*;
+
 pub struct Uart;
 
 impl Write for Uart {
diff --git a/card10-l0dable/src/vibra.rs b/card10-l0dable/src/vibra.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d2e4d53cd2c4af864dff5334d31bb292b670d814
--- /dev/null
+++ b/card10-l0dable/src/vibra.rs
@@ -0,0 +1,13 @@
+use card10_sys::*;
+
+pub fn set(status: bool) {
+    unsafe {
+        epic_vibra_set(status.into());
+    }
+}
+
+pub fn vibrate(millis: i32) {
+    unsafe {
+        epic_vibra_vibrate(millis);
+    }
+}
diff --git a/card10-sys/Cargo.toml b/card10-sys/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..6e924853c8331980a43ca0edfd24d7d5d8579b47
--- /dev/null
+++ b/card10-sys/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+
+name = "card10-sys"
+version = "0.1.0"
+authors = ["Astro <astro@spaceboyz.net>", "Kloenk <me@kloenk.de>"]
+license = "MIT/Apache-2.0"
+edition = "2018"
+
+description = "Rust bindings for card10"
+repository = "https://git.card10.badge.events.ccc.de/astro/rust-card10"
+homepage = "https://git.card10.badge.events.ccc.de/astro/rust-card10"
+
+categories = ["external-ffi-bindings", "no-std"]
+keywords = [
+    "CCC",
+    "CCCamp2019",
+    "CCCamp19",
+    "card10",
+    "l0dable",
+]
+
+[dependencies]
+panic-abort = "^0.3"
+r0 = "^0.2"
+
+[build-dependencies]
+bindgen = "^0.51"
+cc = "^1.0"
diff --git a/card10-sys/build.rs b/card10-sys/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5ef27cb815a752c73f2b1a2263508b8206cee546
--- /dev/null
+++ b/card10-sys/build.rs
@@ -0,0 +1,63 @@
+use std::{env, error::Error, fs, path::PathBuf};
+
+fn main() -> Result<(), Box<dyn Error>> {
+    let out = env::var_os("OUT_DIR")
+        .map(|path| PathBuf::from(path))
+        .ok_or("OUT_DIR definition missing")?;
+
+    println!("cargo:rerun-if-changed=build.rs");
+    println!("cargo:rerun-if-changed=vendor/l0dable.ld");
+    println!("cargo:rerun-if-changed=vendor/client.c");
+    println!("cargo:rerun-if-changed=vendor/wrapper.h");
+    println!("cargo:rustc-link-search={}", out.display());
+
+    // Linker script
+    fs::copy("vendor/crt.s", out.join("crt.s"))?;
+    fs::copy("vendor/l0dable.ld", out.join("l0dable.ld"))?;
+
+    // Link against C code
+    cc::Build::new()
+        .target("thumbv7em-none-eabi")
+        .compiler("arm-none-eabi-gcc")
+        .opt_level_str("s")
+        .debug(true)
+        .define("TARGET", "MAX32665")
+        .define("TARGET_UC", "MAX32665")
+        .define("TARGET_LC", "max32665")
+        .define("TARGET_REV", "0x4131")
+        .define("BOARD", "card10")
+        .flag("-fPIE")
+        .flag("-pie")
+        .include("firmware/epicardium")
+        .include("firmware/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Include")
+        .include("firmware/lib/sdk/Libraries/CMSIS/Include")
+        .include("firmware/lib/sdk/Libraries/MAX32665PeriphDriver/Include")
+        .file("firmware/lib/sdk/Libraries/MAX32665PeriphDriver/Source/sema.c")
+        .file("firmware/lib/sdk/Libraries/MAX32665PeriphDriver/Source/mxc_assert.c")
+        .file("firmware/l0dables/lib/hardware.c")
+        .file("firmware/epicardium/api/caller.c")
+        .file("firmware/lib/gfx/Fonts/font12.c")
+        .file("firmware/lib/gfx/Fonts/font16.c")
+        .file("firmware/lib/gfx/Fonts/font20.c")
+        .file("firmware/lib/gfx/Fonts/font24.c")
+        .file("firmware/lib/gfx/Fonts/font8.c")
+        .file("vendor/client.c")
+        .compile("card10");
+
+    // Generate bindings to C code
+    let bindings = bindgen::Builder::default()
+        .use_core()
+        .clang_arg("-Isrc")
+        .clang_arg("-Ifirmware/epicardium")
+        .clang_arg("-Ifirmware/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Include")
+        .clang_arg("-Ifirmware/lib/sdk/Libraries/CMSIS/Include")
+        .clang_arg("-Ifirmware/lib/sdk/Libraries/MAX32665PeriphDriver/Include")
+        .header("vendor/wrapper.h")
+        .ctypes_prefix("ctypes")
+        .generate()
+        .map_err(|_| "Couldn't generate bindings")?;
+
+    bindings.write_to_file(out.join("bindings.rs"))?;
+
+    Ok(())
+}
diff --git a/c b/card10-sys/firmware
similarity index 100%
rename from c
rename to card10-sys/firmware
diff --git a/l0dable/src/lib.rs b/card10-sys/src/lib.rs
similarity index 72%
rename from l0dable/src/lib.rs
rename to card10-sys/src/lib.rs
index b84440864108d6a9ee1da19f37fa3181a5f326e9..16c72f12ca2f1d8f2662b41f0e3992431f00276c 100644
--- a/l0dable/src/lib.rs
+++ b/card10-sys/src/lib.rs
@@ -1,23 +1,13 @@
 #![no_std]
 #![feature(global_asm)]
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+#![allow(non_snake_case)]
 
 use panic_abort as _;
 
-global_asm!(include_str!("crt.s"));
-
-/// Type check the user-supplied entry function.
-#[macro_export]
-macro_rules! main {
-    ($path:path) => {
-        #[export_name = "main"]
-        pub unsafe fn __main() {
-            // type check the given path
-            let f: fn() = $path;
-
-            f()
-        }
-    };
-}
+global_asm!(include_str!(concat!(env!("OUT_DIR"), "/crt.s")));
+include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
 
 #[link_section = ".text.boot"]
 #[no_mangle]
@@ -38,12 +28,12 @@ pub unsafe extern "C" fn Reset_Handler() -> ! {
     }
 
     main();
-    exit(0);
+
+    epic_exit(0);
+    unreachable!()
 }
 
 pub mod ctypes {
-    #![allow(non_camel_case_types)]
-
     pub type c_short = i16;
     pub type c_ushort = u16;
     pub type c_int = i32;
@@ -59,7 +49,6 @@ pub mod ctypes {
 }
 
 pub mod errno {
-    #![allow(non_snake_case)]
     use crate::ctypes::c_int;
 
     pub const EPERM: c_int = 1; // Operation not permitted
@@ -101,37 +90,3 @@ pub mod errno {
     pub const ETIMEDOUT: c_int = 110; //Connection timed out
     pub const EINPROGRESS: c_int = 115; //Operation now in progress
 }
-
-pub mod bindings {
-    #![allow(non_upper_case_globals)]
-    #![allow(non_camel_case_types)]
-    #![allow(non_snake_case)]
-
-    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
-}
-
-mod os;
-pub use os::*;
-mod display;
-pub use display::{Display, Color, LineStyle, FillStyle};
-pub mod framebuffer;
-mod buttons;
-pub use buttons::Buttons;
-pub mod uart;
-pub const UART: uart::Uart = uart::Uart;
-mod light_sensor;
-pub use light_sensor::LightSensor;
-pub mod vibra;
-pub mod trng;
-mod rtc;
-pub use rtc::{Seconds, MilliSeconds, Time};
-mod fmt_buffer;
-pub use fmt_buffer::{FmtBuffer, str_to_cstr};
-mod bme680;
-pub use bme680::BME680;
-mod bhi160;
-pub use bhi160::{
-    Accelerometer, Error as BHI160Error, Gyroscope, Orientation, Sensor as BHI160,
-    SensorData as BHI160Data,
-};
-pub mod fs;
diff --git a/l0dable/src/client.c b/card10-sys/vendor/client.c
similarity index 100%
rename from l0dable/src/client.c
rename to card10-sys/vendor/client.c
diff --git a/l0dable/src/crt.s b/card10-sys/vendor/crt.s
similarity index 100%
rename from l0dable/src/crt.s
rename to card10-sys/vendor/crt.s
diff --git a/l0dable/l0dable.ld b/card10-sys/vendor/l0dable.ld
similarity index 100%
rename from l0dable/l0dable.ld
rename to card10-sys/vendor/l0dable.ld
diff --git a/card10-sys/vendor/server.c b/card10-sys/vendor/server.c
new file mode 100644
index 0000000000000000000000000000000000000000..a44db3c80d522ee9e07f4efb3dbb9de430376d30
--- /dev/null
+++ b/card10-sys/vendor/server.c
@@ -0,0 +1,467 @@
+#include "modules/log.h"
+#include "epicardium.h"
+
+void __api_dispatch_call(uint32_t id, void*epc__apistub_buffer)
+{
+        switch (id) {
+        case API_INTERRUPT_ENABLE:
+                *((int*)epc__apistub_buffer) = epic_interrupt_enable(
+                        *(api_int_id_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_INTERRUPT_DISABLE:
+                *((int*)epc__apistub_buffer) = epic_interrupt_disable(
+                        *(api_int_id_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_SYSTEM_EXIT:
+                __epic_exit(
+                        *(int*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_SYSTEM_EXEC:
+                *((int*)epc__apistub_buffer) = __epic_exec(
+                        *(char **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_SYSTEM_RESET:
+                epic_system_reset(
+                );
+                break;
+        case API_BATTERY_VOLTAGE:
+                *((int*)epc__apistub_buffer) = epic_read_battery_voltage(
+                        *(float **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_BATTERY_CURRENT:
+                *((int*)epc__apistub_buffer) = epic_read_battery_current(
+                        *(float **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_CHARGEIN_VOLTAGE:
+                *((int*)epc__apistub_buffer) = epic_read_chargein_voltage(
+                        *(float **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_CHARGEIN_CURRENT:
+                *((int*)epc__apistub_buffer) = epic_read_chargein_current(
+                        *(float **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_SYSTEM_VOLTAGE:
+                *((int*)epc__apistub_buffer) = epic_read_system_voltage(
+                        *(float **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_THERMISTOR_VOLTAGE:
+                *((int*)epc__apistub_buffer) = epic_read_thermistor_voltage(
+                        *(float **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_UART_WRITE_STR:
+                epic_uart_write_str(
+                        *(const char **)(epc__apistub_buffer + 0),
+                        *(intptr_t*)(epc__apistub_buffer + sizeof(const char *))
+                );
+                break;
+        case API_UART_READ_CHAR:
+                *((int*)epc__apistub_buffer) = epic_uart_read_char(
+                );
+                break;
+        case API_UART_READ_STR:
+                *((int*)epc__apistub_buffer) = epic_uart_read_str(
+                        *(char **)(epc__apistub_buffer + 0),
+                        *(size_t*)(epc__apistub_buffer + sizeof(char *))
+                );
+                break;
+        case API_BUTTONS_READ:
+                *((uint8_t*)epc__apistub_buffer) = epic_buttons_read(
+                        *(uint8_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_GPIO_SET_PIN_MODE:
+                *((int*)epc__apistub_buffer) = epic_gpio_set_pin_mode(
+                        *(uint8_t*)(epc__apistub_buffer + 0),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(uint8_t))
+                );
+                break;
+        case API_GPIO_GET_PIN_MODE:
+                *((int*)epc__apistub_buffer) = epic_gpio_get_pin_mode(
+                        *(uint8_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_GPIO_WRITE_PIN:
+                *((int*)epc__apistub_buffer) = epic_gpio_write_pin(
+                        *(uint8_t*)(epc__apistub_buffer + 0),
+                        *(_Bool*)(epc__apistub_buffer + sizeof(uint8_t))
+                );
+                break;
+        case API_GPIO_READ_PIN:
+                *((int*)epc__apistub_buffer) = epic_gpio_read_pin(
+                        *(uint8_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_LEDS_SET:
+                epic_leds_set(
+                        *(int*)(epc__apistub_buffer + 0),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(int)),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(int) + sizeof(uint8_t)),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(int) + sizeof(uint8_t) + sizeof(uint8_t))
+                );
+                break;
+        case API_LEDS_SET_HSV:
+                epic_leds_set_hsv(
+                        *(int*)(epc__apistub_buffer + 0),
+                        *(float*)(epc__apistub_buffer + sizeof(int)),
+                        *(float*)(epc__apistub_buffer + sizeof(int) + sizeof(float)),
+                        *(float*)(epc__apistub_buffer + sizeof(int) + sizeof(float) + sizeof(float))
+                );
+                break;
+        case API_LEDS_SET_ALL:
+                epic_leds_set_all(
+                        *(uint8_t **)(epc__apistub_buffer + 0),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(uint8_t *))
+                );
+                break;
+        case API_LEDS_SET_ALL_HSV:
+                epic_leds_set_all_hsv(
+                        *(float **)(epc__apistub_buffer + 0),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(float *))
+                );
+                break;
+        case API_LEDS_PREP:
+                epic_leds_prep(
+                        *(int*)(epc__apistub_buffer + 0),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(int)),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(int) + sizeof(uint8_t)),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(int) + sizeof(uint8_t) + sizeof(uint8_t))
+                );
+                break;
+        case API_LEDS_PREP_HSV:
+                epic_leds_prep_hsv(
+                        *(int*)(epc__apistub_buffer + 0),
+                        *(float*)(epc__apistub_buffer + sizeof(int)),
+                        *(float*)(epc__apistub_buffer + sizeof(int) + sizeof(float)),
+                        *(float*)(epc__apistub_buffer + sizeof(int) + sizeof(float) + sizeof(float))
+                );
+                break;
+        case API_LEDS_DIM_BOTTOM:
+                epic_leds_dim_bottom(
+                        *(uint8_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_LEDS_DIM_TOP:
+                epic_leds_dim_top(
+                        *(uint8_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_LEDS_SET_POWERSAVE:
+                epic_leds_set_powersave(
+                        *(_Bool*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_LEDS_UPDATE:
+                epic_leds_update(
+                );
+                break;
+        case API_LEDS_SET_ROCKET:
+                epic_leds_set_rocket(
+                        *(int*)(epc__apistub_buffer + 0),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(int))
+                );
+                break;
+        case API_LEDS_SET_FLASHLIGHT:
+                epic_set_flashlight(
+                        *(_Bool*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_LEDS_SET_GAMMA_TABLE:
+                epic_leds_set_gamma_table(
+                        *(uint8_t*)(epc__apistub_buffer + 0),
+                        *(uint8_t **)(epc__apistub_buffer + sizeof(uint8_t))
+                );
+                break;
+        case API_LEDS_CLEAR_ALL:
+                epic_leds_clear_all(
+                        *(uint8_t*)(epc__apistub_buffer + 0),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(uint8_t)),
+                        *(uint8_t*)(epc__apistub_buffer + sizeof(uint8_t) + sizeof(uint8_t))
+                );
+                break;
+        case API_BME680_INIT:
+                *((int*)epc__apistub_buffer) = epic_bme680_init(
+                );
+                break;
+        case API_BME680_DEINIT:
+                *((int*)epc__apistub_buffer) = epic_bme680_deinit(
+                );
+                break;
+        case API_BME680_GET_DATA:
+                *((int*)epc__apistub_buffer) = epic_bme680_read_sensors(
+                        *(struct bme680_sensor_data **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_PERSONAL_STATE_SET:
+                *((int*)epc__apistub_buffer) = epic_personal_state_set(
+                        *(uint8_t*)(epc__apistub_buffer + 0),
+                        *(_Bool*)(epc__apistub_buffer + sizeof(uint8_t))
+                );
+                break;
+        case API_PERSONAL_STATE_GET:
+                *((int*)epc__apistub_buffer) = epic_personal_state_get(
+                );
+                break;
+        case API_PERSONAL_STATE_IS_PERSISTENT:
+                *((int*)epc__apistub_buffer) = epic_personal_state_is_persistent(
+                );
+                break;
+        case API_STREAM_READ:
+                *((int*)epc__apistub_buffer) = epic_stream_read(
+                        *(int*)(epc__apistub_buffer + 0),
+                        *(void **)(epc__apistub_buffer + sizeof(int)),
+                        *(size_t*)(epc__apistub_buffer + sizeof(int) + sizeof(void *))
+                );
+                break;
+        case API_BHI160_ENABLE:
+                *((int*)epc__apistub_buffer) = epic_bhi160_enable_sensor(
+                        *(enum bhi160_sensor_type*)(epc__apistub_buffer + 0),
+                        *(struct bhi160_sensor_config **)(epc__apistub_buffer + sizeof(enum bhi160_sensor_type))
+                );
+                break;
+        case API_BHI160_DISABLE:
+                *((int*)epc__apistub_buffer) = epic_bhi160_disable_sensor(
+                        *(enum bhi160_sensor_type*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_BHI160_DISABLE_ALL:
+                epic_bhi160_disable_all_sensors(
+                );
+                break;
+        case API_VIBRA_SET:
+                epic_vibra_set(
+                        *(int*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_VIBRA_VIBRATE:
+                epic_vibra_vibrate(
+                        *(int*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_DISP_OPEN:
+                *((int*)epc__apistub_buffer) = epic_disp_open(
+                );
+                break;
+        case API_DISP_CLOSE:
+                *((int*)epc__apistub_buffer) = epic_disp_close(
+                );
+                break;
+        case API_DISP_UPDATE:
+                *((int*)epc__apistub_buffer) = epic_disp_update(
+                );
+                break;
+        case API_DISP_PRINT:
+                *((int*)epc__apistub_buffer) = epic_disp_print(
+                        *(uint16_t*)(epc__apistub_buffer + 0),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t)),
+                        *(const char **)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(const char *)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(const char *) + sizeof(uint16_t))
+                );
+                break;
+        case API_DISP_CLEAR:
+                *((int*)epc__apistub_buffer) = epic_disp_clear(
+                        *(uint16_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_DISP_PIXEL:
+                *((int*)epc__apistub_buffer) = epic_disp_pixel(
+                        *(uint16_t*)(epc__apistub_buffer + 0),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t))
+                );
+                break;
+        case API_DISP_LINE:
+                *((int*)epc__apistub_buffer) = epic_disp_line(
+                        *(uint16_t*)(epc__apistub_buffer + 0),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(enum disp_linestyle*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(enum disp_linestyle))
+                );
+                break;
+        case API_DISP_RECT:
+                *((int*)epc__apistub_buffer) = epic_disp_rect(
+                        *(uint16_t*)(epc__apistub_buffer + 0),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(enum disp_fillstyle*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(enum disp_fillstyle))
+                );
+                break;
+        case API_DISP_CIRC:
+                *((int*)epc__apistub_buffer) = epic_disp_circ(
+                        *(uint16_t*)(epc__apistub_buffer + 0),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(enum disp_fillstyle*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t)),
+                        *(uint16_t*)(epc__apistub_buffer + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(enum disp_fillstyle))
+                );
+                break;
+        case API_DISP_FRAMEBUFFER:
+                *((int*)epc__apistub_buffer) = epic_disp_framebuffer(
+                        *(union disp_framebuffer **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_DISP_BACKLIGHT:
+                *((int*)epc__apistub_buffer) = epic_disp_backlight(
+                        *(uint16_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_LIGHT_SENSOR_RUN:
+                *((int*)epc__apistub_buffer) = epic_light_sensor_run(
+                );
+                break;
+        case API_LIGHT_SENSOR_GET:
+                *((int*)epc__apistub_buffer) = epic_light_sensor_get(
+                        *(uint16_t**)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_LIGHT_SENSOR_STOP:
+                *((int*)epc__apistub_buffer) = epic_light_sensor_stop(
+                );
+                break;
+        case API_LIGHT_SENSOR_READ:
+                *((uint16_t*)epc__apistub_buffer) = epic_light_sensor_read(
+                );
+                break;
+        case API_FILE_OPEN:
+                *((int*)epc__apistub_buffer) = epic_file_open(
+                        *(const char**)(epc__apistub_buffer + 0),
+                        *(const char**)(epc__apistub_buffer + sizeof(const char*))
+                );
+                break;
+        case API_FILE_CLOSE:
+                *((int*)epc__apistub_buffer) = epic_file_close(
+                        *(int*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_FILE_READ:
+                *((int*)epc__apistub_buffer) = epic_file_read(
+                        *(int*)(epc__apistub_buffer + 0),
+                        *(void**)(epc__apistub_buffer + sizeof(int)),
+                        *(size_t*)(epc__apistub_buffer + sizeof(int) + sizeof(void*))
+                );
+                break;
+        case API_FILE_WRITE:
+                *((int*)epc__apistub_buffer) = epic_file_write(
+                        *(int*)(epc__apistub_buffer + 0),
+                        *(const void**)(epc__apistub_buffer + sizeof(int)),
+                        *(size_t*)(epc__apistub_buffer + sizeof(int) + sizeof(const void*))
+                );
+                break;
+        case API_FILE_FLUSH:
+                *((int*)epc__apistub_buffer) = epic_file_flush(
+                        *(int*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_FILE_SEEK:
+                *((int*)epc__apistub_buffer) = epic_file_seek(
+                        *(int*)(epc__apistub_buffer + 0),
+                        *(long*)(epc__apistub_buffer + sizeof(int)),
+                        *(int*)(epc__apistub_buffer + sizeof(int) + sizeof(long))
+                );
+                break;
+        case API_FILE_TELL:
+                *((int*)epc__apistub_buffer) = epic_file_tell(
+                        *(int*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_FILE_STAT:
+                *((int*)epc__apistub_buffer) = epic_file_stat(
+                        *(const char**)(epc__apistub_buffer + 0),
+                        *(struct epic_stat**)(epc__apistub_buffer + sizeof(const char*))
+                );
+                break;
+        case API_FILE_OPENDIR:
+                *((int*)epc__apistub_buffer) = epic_file_opendir(
+                        *(const char**)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_FILE_READDIR:
+                *((int*)epc__apistub_buffer) = epic_file_readdir(
+                        *(int*)(epc__apistub_buffer + 0),
+                        *(struct epic_stat**)(epc__apistub_buffer + sizeof(int))
+                );
+                break;
+        case API_FILE_UNLINK:
+                *((int*)epc__apistub_buffer) = epic_file_unlink(
+                        *(const char**)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_FILE_RENAME:
+                *((int*)epc__apistub_buffer) = epic_file_rename(
+                        *(const char **)(epc__apistub_buffer + 0),
+                        *(const char**)(epc__apistub_buffer + sizeof(const char *))
+                );
+                break;
+        case API_FILE_MKDIR:
+                *((int*)epc__apistub_buffer) = epic_file_mkdir(
+                        *(const char **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_RTC_GET_SECONDS:
+                *((uint32_t*)epc__apistub_buffer) = epic_rtc_get_seconds(
+                );
+                break;
+        case API_RTC_GET_MILLISECONDS:
+                *((uint64_t*)epc__apistub_buffer) = epic_rtc_get_milliseconds(
+                );
+                break;
+        case API_RTC_SET_MILLISECONDS:
+                epic_rtc_set_milliseconds(
+                        *(uint64_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_RTC_SCHEDULE_ALARM:
+                *((int*)epc__apistub_buffer) = epic_rtc_schedule_alarm(
+                        *(uint32_t*)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_TRNG_READ:
+                *((int*)epc__apistub_buffer) = epic_trng_read(
+                        *(uint8_t **)(epc__apistub_buffer + 0),
+                        *(size_t*)(epc__apistub_buffer + sizeof(uint8_t *))
+                );
+                break;
+        case API_MAX30001_ENABLE:
+                *((int*)epc__apistub_buffer) = epic_max30001_enable_sensor(
+                        *(struct max30001_sensor_config **)(epc__apistub_buffer + 0)
+                );
+                break;
+        case API_MAX30001_DISABLE:
+                *((int*)epc__apistub_buffer) = epic_max30001_disable_sensor(
+                );
+                break;
+        case API_USB_SHUTDOWN:
+                *((int*)epc__apistub_buffer) = epic_usb_shutdown(
+                );
+                break;
+        case API_USB_STORAGE:
+                *((int*)epc__apistub_buffer) = epic_usb_storage(
+                );
+                break;
+        case API_USB_CDCACM:
+                *((int*)epc__apistub_buffer) = epic_usb_cdcacm(
+                );
+                break;
+        default:
+                /* TODO: Better error handling */
+                LOG_ERR("api-dispatcher", "API function 0x%lx is unknown!!", id);
+                break;
+        }
+}
diff --git a/l0dable/src/bindings.h b/card10-sys/vendor/wrapper.h
similarity index 100%
rename from l0dable/src/bindings.h
rename to card10-sys/vendor/wrapper.h
diff --git a/default.nix b/default.nix
index 2d1d411920397e48412ec72a237c614afe6bcabf..0b7b5b7e4b775cf0700ee5637ec06a3289f3d5bf 100644
--- a/default.nix
+++ b/default.nix
@@ -11,7 +11,7 @@ let
   };
   epic-stubs = stdenv.mkDerivation {
     name = "epic-stubs";
-    src = ./c;
+    src = ./card10-sys/firmware;
     buildInputs = [ gcc python3 ];
     buildPhase = ''
       ${python3}/bin/python epicardium/api/genapi.py -H epicardium/epicardium.h -c client.c -s server.c
@@ -28,7 +28,7 @@ let
     cargoSha256 = "10nims5j9r0d7pcfbbj8ycqxhcx7n07958jvkib29b0sf9c6qh3z";
     buildInputs = [ pkgsCross.arm-embedded.stdenv.cc ];
     prePatch = ''
-      cp ${epic-stubs}/client.c l0dable/src/
+      cp ${epic-stubs}/client.c card10-sys/vendor/
     '';
     NIX_DEBUG=1;
     LIBCLANG_PATH="${llvmPackages.libclang}/lib";
diff --git a/example/Cargo.toml b/example/Cargo.toml
index b4143a9324e2f9ae3556faf45e659848a67496d2..8d7ab8a4cef7377ecf8ab90b959d4bb105c55c7e 100644
--- a/example/Cargo.toml
+++ b/example/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.0.0"
 authors = ["Astro <astro@spaceboyz.net>"]
 
 [dependencies]
-card10-l0dable = { path = "../l0dable" }
+card10-l0dable = { path = "../card10-l0dable" }
 
 [build-dependencies]
 cc = "1.0"
diff --git a/l0dable/build.rs b/l0dable/build.rs
deleted file mode 100644
index ca52d6b9d9c9529fe25985e22ddaba2d9eb7b435..0000000000000000000000000000000000000000
--- a/l0dable/build.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-use std::env;
-use std::fs::File;
-use std::io::Write;
-use std::path::PathBuf;
-
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-
-    // Linker script
-    let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
-    File::create(out.join("l0dable.ld"))
-        .unwrap()
-        .write_all(include_bytes!("l0dable.ld"))
-        .unwrap();
-    println!("cargo:rustc-link-search={}", out.display());
-    println!("cargo:rerun-if-changed=l0dable.ld");
-
-    // Link against C code
-    cc::Build::new()
-        .target("thumbv7em-none-eabi")
-        .compiler("arm-none-eabi-gcc")
-        .define("TARGET", "MAX32665")
-        .define("TARGET_UC", "MAX32665")
-        .define("TARGET_LC", "max32665")
-        .define("TARGET_REV", "0x4131")
-        .define("BOARD", "card10")
-        .opt_level_str("s")
-        .debug(true)
-        .flag("-fPIE").flag("-pie")
-        .include("../c/epicardium")
-        .include("../c/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Include")
-        .include("../c/lib/sdk/Libraries/CMSIS/Include")
-        .include("../c/lib/sdk/Libraries/MAX32665PeriphDriver/Include")
-        .file("../c/lib/sdk/Libraries/MAX32665PeriphDriver/Source/sema.c")
-        .file("../c/lib/sdk/Libraries/MAX32665PeriphDriver/Source/mxc_assert.c")
-        .file("../c/l0dables/lib/hardware.c")
-        .file("../c/epicardium/api/caller.c")
-        .file("src/client.c")
-        .file("../c/lib/gfx/Fonts/font12.c")
-        .file("../c/lib/gfx/Fonts/font16.c")
-        .file("../c/lib/gfx/Fonts/font20.c")
-        .file("../c/lib/gfx/Fonts/font24.c")
-        .file("../c/lib/gfx/Fonts/font8.c")
-        .compile("card10");
-    println!("cargo:rerun-if-changed=src/client.c");
-
-    // Generate bindings to C code
-    let bindings = bindgen::Builder::default()
-        .clang_args(&[
-            "-Isrc",
-            "-I../c/epicardium",
-            "-I../c/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Include",
-            "-I../c/lib/sdk/Libraries/CMSIS/Include",
-            "-I../c/lib/sdk/Libraries/MAX32665PeriphDriver/Include",
-        ])
-        .header("src/bindings.h")
-        .use_core()
-        .ctypes_prefix("super::ctypes")
-        .generate()
-        .expect("Unable to generate bindings");
-    println!("cargo:rerun-if-changed=src/bindings.h");
-
-    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
-    bindings
-        .write_to_file(out_path.join("bindings.rs"))
-        .expect("Couldn't write bindings!");
-}
diff --git a/l0dable/src/errno.h b/l0dable/src/errno.h
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/l0dable/src/vibra.rs b/l0dable/src/vibra.rs
deleted file mode 100644
index 963634cb36b3bb01286836fd20ff25f070818c67..0000000000000000000000000000000000000000
--- a/l0dable/src/vibra.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use super::bindings::*;
-
-pub fn set(status: bool) {
-    unsafe { epic_vibra_set(status.into()); }
-}
-
-pub fn vibrate(millis: i32) {
-    unsafe { epic_vibra_vibrate(millis); }
-}
diff --git a/release.nix b/release.nix
index 4b3c76a45169ae9f860c23e6fb66c62b0f469b07..2b5567af1f7ae3c762c897d298ff609095352312 100644
--- a/release.nix
+++ b/release.nix
@@ -8,7 +8,7 @@ let
     src = ./.;
     phases = [ "unpackPhase" "patchPhase" "installPhase" ];
     nativeBuildInputs = [ git ];
-    prePatch = "cd c";
+    prePatch = "cd card10-sys/firmware";
     postPatch = ''
       VERSION="$(git describe --always)"
       GITHASH="$(git rev-parse HEAD)"
diff --git a/rkanoid/Cargo.toml b/rkanoid/Cargo.toml
index a7467193c332339c4316344e062414a6417aa0a1..e85651882303b63514cf1ef20ede50bcdc4f9d36 100644
--- a/rkanoid/Cargo.toml
+++ b/rkanoid/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.0.0"
 authors = ["Astro <astro@spaceboyz.net>"]
 
 [dependencies]
-card10-l0dable = { path = "../l0dable" }
+card10-l0dable = { path = "../card10-l0dable" }
 
 [build-dependencies]
 cc = "1.0"