Merge pull request #238 from alistair23/alistair/opentitan

boards/layout_opentitan.ld: Update memory addresses
diff --git a/examples/ctap.rs b/examples/ctap.rs
new file mode 100644
index 0000000..42917d1
--- /dev/null
+++ b/examples/ctap.rs
@@ -0,0 +1,46 @@
+#![no_std]
+/// This is a very basic CTAP example
+/// This example only calls the CTAP driver calls, it does not implement CTAP
+use core::fmt::Write;
+use libtock::ctap::{CtapRecvBuffer, CtapSendBuffer};
+use libtock::result::TockResult;
+use libtock::syscalls;
+
+#[libtock::main]
+async fn main() -> TockResult<()> {
+    let mut drivers = libtock::retrieve_drivers()?;
+    let mut console = drivers.console.create_console();
+    writeln!(console, "Starting CTAP example")?;
+    let ctap_driver = drivers.ctap.init_driver()?;
+
+    writeln!(console, "Creating recv buffer")?;
+    let mut recv_buffer = CtapRecvBuffer::default();
+    let recv_buffer = ctap_driver.init_recv_buffer(&mut recv_buffer)?;
+    writeln!(console, "  done")?;
+
+    writeln!(console, "Creating send buffer")?;
+    let mut send_buffer = CtapSendBuffer::default();
+    let _send_buffer = ctap_driver.init_send_buffer(&mut send_buffer)?;
+    writeln!(console, "  done")?;
+
+    let mut temp_buffer = [0; libtock::ctap::RECV_BUFFER_SIZE];
+
+    writeln!(console, "Setting callback and running")?;
+    let mut callback = |_, _| {
+        writeln!(console, "CTAP Complete, printing data").unwrap();
+        recv_buffer.read_bytes(&mut temp_buffer[..]);
+
+        for buf in temp_buffer.iter().take(libtock::ctap::RECV_BUFFER_SIZE) {
+            write!(console, "{:x}", *buf).unwrap();
+        }
+
+        let _ret = ctap_driver.allow_receive();
+    };
+
+    let _subscription = ctap_driver.subscribe(&mut callback)?;
+    ctap_driver.allow_receive()?;
+
+    loop {
+        unsafe { syscalls::raw::yieldk() };
+    }
+}
diff --git a/src/ctap.rs b/src/ctap.rs
new file mode 100644
index 0000000..ac09120
--- /dev/null
+++ b/src/ctap.rs
@@ -0,0 +1,110 @@
+use crate::callback::CallbackSubscription;
+use crate::callback::Consumer;
+use crate::result::TockResult;
+use crate::syscalls;
+use core::marker::PhantomData;
+use libtock_core::shared_memory::SharedMemory;
+
+const DRIVER_NUMBER: usize = 0x40004;
+
+pub const RECV_BUFFER_SIZE: usize = 64;
+pub const SEND_BUFFER_SIZE: usize = 64;
+
+mod command_nr {
+    pub const SEND_DATA: usize = 0;
+    pub const ALLOW_RECEIVE: usize = 1;
+}
+
+mod subscribe_nr {
+    pub const SUBSCRIBE_CALLBACK: usize = 0;
+}
+
+mod allow_nr {
+    pub const RECV: usize = 0;
+    pub const SEND: usize = 1;
+}
+
+#[non_exhaustive]
+pub struct CtapDriverFactory;
+
+impl CtapDriverFactory {
+    pub fn init_driver(&mut self) -> TockResult<CtapDriver> {
+        let ctap = CtapDriver {
+            lifetime: PhantomData,
+        };
+        Ok(ctap)
+    }
+}
+
+struct CtapEventConsumer;
+
+impl<CB: FnMut(usize, usize)> Consumer<CB> for CtapEventConsumer {
+    fn consume(callback: &mut CB, sent: usize, _: usize, _: usize) {
+        callback(sent, 0);
+    }
+}
+
+pub struct CtapRecvBuffer {
+    buffer: [u8; RECV_BUFFER_SIZE],
+}
+
+impl Default for CtapRecvBuffer {
+    fn default() -> Self {
+        CtapRecvBuffer {
+            buffer: [0; RECV_BUFFER_SIZE],
+        }
+    }
+}
+
+pub struct CtapSendBuffer {
+    pub buffer: [u8; SEND_BUFFER_SIZE],
+}
+
+impl CtapSendBuffer {
+    pub fn new(buf: [u8; SEND_BUFFER_SIZE]) -> Self {
+        CtapSendBuffer { buffer: buf }
+    }
+}
+
+impl Default for CtapSendBuffer {
+    fn default() -> Self {
+        CtapSendBuffer {
+            buffer: [0; SEND_BUFFER_SIZE],
+        }
+    }
+}
+
+pub struct CtapDriver<'a> {
+    lifetime: PhantomData<&'a ()>,
+}
+
+impl<'a> CtapDriver<'a> {
+    pub fn init_recv_buffer(&self, buffer: &'a mut CtapRecvBuffer) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::RECV, &mut buffer.buffer).map_err(Into::into)
+    }
+
+    pub fn init_send_buffer(&self, buffer: &'a mut CtapSendBuffer) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::SEND, &mut buffer.buffer).map_err(Into::into)
+    }
+
+    pub fn subscribe<CB: FnMut(usize, usize)>(
+        &self,
+        callback: &'a mut CB,
+    ) -> TockResult<CallbackSubscription> {
+        syscalls::subscribe::<CtapEventConsumer, _>(
+            DRIVER_NUMBER,
+            subscribe_nr::SUBSCRIBE_CALLBACK,
+            callback,
+        )
+        .map_err(Into::into)
+    }
+    pub fn send_data(&self) -> TockResult<()> {
+        syscalls::command(DRIVER_NUMBER, command_nr::SEND_DATA, 0, 0)?;
+        Ok(())
+    }
+
+    pub fn allow_receive(&self) -> TockResult<()> {
+        syscalls::command(DRIVER_NUMBER, command_nr::ALLOW_RECEIVE, 0, 0)?;
+        Ok(())
+    }
+}
diff --git a/src/drivers.rs b/src/drivers.rs
index bd7f45b..9b74a28 100644
--- a/src/drivers.rs
+++ b/src/drivers.rs
@@ -1,6 +1,7 @@
 use crate::adc::AdcDriverFactory;
 use crate::buttons::ButtonsDriverFactory;
 use crate::console::ConsoleDriver;
+use crate::ctap::CtapDriverFactory;
 use crate::gpio::GpioDriverFactory;
 use crate::hmac::HmacDriverFactory;
 use crate::leds::LedsDriverFactory;
@@ -21,6 +22,7 @@
 #[non_exhaustive]
 pub struct Drivers {
     pub console: ConsoleDriver,
+    pub ctap: CtapDriverFactory,
     pub leds: LedsDriverFactory,
     pub timer: DriverContext,
     pub gpio: GpioDriverFactory,
@@ -68,6 +70,7 @@
     ble_scanning: BleScanningDriverFactory,
     buttons: ButtonsDriverFactory,
     console: ConsoleDriver,
+    ctap: CtapDriverFactory,
     leds: LedsDriverFactory,
     timer: DriverContext {
         active_timer: Cell::new(None),
diff --git a/src/lib.rs b/src/lib.rs
index eb13b94..96d2720 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,6 +5,7 @@
 pub mod ble_parser;
 pub mod buttons;
 pub mod console;
+pub mod ctap;
 pub mod debug;
 pub mod drivers;
 pub mod electronics;