i2c: Add support for the I2C interface

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
diff --git a/src/drivers.rs b/src/drivers.rs
index 9b74a28..7df124b 100644
--- a/src/drivers.rs
+++ b/src/drivers.rs
@@ -4,6 +4,7 @@
 use crate::ctap::CtapDriverFactory;
 use crate::gpio::GpioDriverFactory;
 use crate::hmac::HmacDriverFactory;
+use crate::i2c::I2cDriverFactory;
 use crate::leds::LedsDriverFactory;
 use crate::result::OtherError;
 use crate::result::TockError;
@@ -30,6 +31,7 @@
     pub temperature: TemperatureDriverFactory,
     pub buttons: ButtonsDriverFactory,
     pub adc: AdcDriverFactory,
+    pub i2c: I2cDriverFactory,
     pub rng: RngDriver,
     pub ble_advertising: BleAdvertisingDriverFactory,
     pub ble_scanning: BleScanningDriverFactory,
@@ -77,6 +79,7 @@
     },
     gpio: GpioDriverFactory,
     hmac: HmacDriverFactory,
+    i2c: I2cDriverFactory,
     temperature: TemperatureDriverFactory,
     rng: RngDriver,
     ambient_light_sensor: AmbientLightSensor,
diff --git a/src/i2c.rs b/src/i2c.rs
new file mode 100644
index 0000000..8256af8
--- /dev/null
+++ b/src/i2c.rs
@@ -0,0 +1,264 @@
+use crate::callback::CallbackSubscription;
+use crate::callback::Consumer;
+use crate::result::TockResult;
+use crate::syscalls;
+use core::marker::PhantomData;
+use core::ops::Deref;
+use core::ops::DerefMut;
+use libtock_core::shared_memory::SharedMemory;
+
+const DRIVER_NUMBER: usize = 0x20006;
+
+pub const MASTER_BUFFER_SIZE: usize = 32;
+pub const SLAVE_BUFFER_SIZE: usize = 32;
+
+mod command_nr {
+    pub const CHECK_PRESENT: usize = 0;
+    pub const MASTER_WRITE: usize = 1;
+    pub const MASTER_READ: usize = 2;
+    pub const SLAVE_LISTEN: usize = 3;
+    pub const SLAVE_ENABLE_READ: usize = 4;
+    pub const SLAVE_STOP_LISTEN: usize = 5;
+    pub const SLAVE_SET_ADDRESS: usize = 6;
+    pub const MASTER_WRITE_READ: usize = 7;
+}
+
+mod subscribe_nr {
+    pub const SUBSCRIBE_CALLBACK: usize = 0;
+}
+
+mod allow_nr {
+    pub const MASTER_WRIE: usize = 0;
+    pub const MASTER_READ: usize = 1;
+    pub const SLAVE_READ: usize = 2;
+    pub const SLAVE_WRITE: usize = 2;
+}
+
+#[non_exhaustive]
+pub struct I2cDriverFactory;
+
+impl I2cDriverFactory {
+    pub fn init_driver(&mut self) -> TockResult<I2cDriver> {
+        let i2c = I2cDriver {
+            lifetime: PhantomData,
+        };
+        Ok(i2c)
+    }
+}
+
+struct I2cEventConsumer;
+
+impl<CB: FnMut(usize, usize)> Consumer<CB> for I2cEventConsumer {
+    fn consume(callback: &mut CB, _: usize, _: usize, _: usize) {
+        callback(0, 0);
+    }
+}
+
+pub struct I2cMasterWriteBuffer {
+    buffer: [u8; MASTER_BUFFER_SIZE],
+}
+
+impl Default for I2cMasterWriteBuffer {
+    fn default() -> Self {
+        I2cMasterWriteBuffer {
+            buffer: [0; MASTER_BUFFER_SIZE],
+        }
+    }
+}
+
+impl Deref for I2cMasterWriteBuffer {
+    type Target = [u8; MASTER_BUFFER_SIZE];
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl DerefMut for I2cMasterWriteBuffer {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.buffer
+    }
+}
+
+pub struct I2cMasterReadBuffer {
+    buffer: [u8; MASTER_BUFFER_SIZE],
+}
+
+impl Default for I2cMasterReadBuffer {
+    fn default() -> Self {
+        I2cMasterReadBuffer {
+            buffer: [0; MASTER_BUFFER_SIZE],
+        }
+    }
+}
+
+impl Deref for I2cMasterReadBuffer {
+    type Target = [u8; MASTER_BUFFER_SIZE];
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl DerefMut for I2cMasterReadBuffer {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.buffer
+    }
+}
+
+pub struct I2cSlaveReadBuffer {
+    buffer: [u8; SLAVE_BUFFER_SIZE],
+}
+
+impl Default for I2cSlaveReadBuffer {
+    fn default() -> Self {
+        I2cSlaveReadBuffer {
+            buffer: [0; SLAVE_BUFFER_SIZE],
+        }
+    }
+}
+
+impl Deref for I2cSlaveReadBuffer {
+    type Target = [u8; SLAVE_BUFFER_SIZE];
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl DerefMut for I2cSlaveReadBuffer {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.buffer
+    }
+}
+
+pub struct I2cSlaveWriteBuffer {
+    buffer: [u8; SLAVE_BUFFER_SIZE],
+}
+
+impl Default for I2cSlaveWriteBuffer {
+    fn default() -> Self {
+        I2cSlaveWriteBuffer {
+            buffer: [0; SLAVE_BUFFER_SIZE],
+        }
+    }
+}
+
+impl Deref for I2cSlaveWriteBuffer {
+    type Target = [u8; SLAVE_BUFFER_SIZE];
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl DerefMut for I2cSlaveWriteBuffer {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.buffer
+    }
+}
+
+pub struct I2cDriver<'a> {
+    lifetime: PhantomData<&'a ()>,
+}
+
+impl<'a> I2cDriver<'a> {
+    pub fn init_master_write_buffer(
+        &self,
+        buffer: &'a mut I2cMasterWriteBuffer,
+    ) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::MASTER_WRIE, &mut buffer.buffer)
+            .map_err(Into::into)
+    }
+
+    pub fn init_master_read_buffer(
+        &self,
+        buffer: &'a mut I2cMasterReadBuffer,
+    ) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::MASTER_READ, &mut buffer.buffer)
+            .map_err(Into::into)
+    }
+
+    pub fn init_slave_read_buffer(
+        &self,
+        buffer: &'a mut I2cSlaveReadBuffer,
+    ) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::SLAVE_READ, &mut buffer.buffer).map_err(Into::into)
+    }
+
+    pub fn init_slave_write_buffer(
+        &self,
+        buffer: &'a mut I2cSlaveWriteBuffer,
+    ) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::SLAVE_WRITE, &mut buffer.buffer)
+            .map_err(Into::into)
+    }
+
+    pub fn subscribe<CB: FnMut(usize, usize)>(
+        &self,
+        callback: &'a mut CB,
+    ) -> TockResult<CallbackSubscription> {
+        syscalls::subscribe::<I2cEventConsumer, _>(
+            DRIVER_NUMBER,
+            subscribe_nr::SUBSCRIBE_CALLBACK,
+            callback,
+        )
+        .map_err(Into::into)
+    }
+
+    pub fn check_present(&self) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::CHECK_PRESENT, 0, 0).map_err(Into::into)
+    }
+
+    pub fn master_write(&self, address: usize, length: usize) -> TockResult<usize> {
+        syscalls::command(
+            DRIVER_NUMBER,
+            command_nr::MASTER_WRITE,
+            address & 0xFFFF | length << 16,
+            0,
+        )
+        .map_err(Into::into)
+    }
+
+    pub fn master_read(&self, address: usize, length: usize) -> TockResult<usize> {
+        syscalls::command(
+            DRIVER_NUMBER,
+            command_nr::MASTER_READ,
+            address & 0xFFFF | length << 16,
+            0,
+        )
+        .map_err(Into::into)
+    }
+
+    pub fn slave_listen(&self) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::SLAVE_LISTEN, 0, 0).map_err(Into::into)
+    }
+
+    pub fn slave_enable_read(&self) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::SLAVE_ENABLE_READ, 0, 0).map_err(Into::into)
+    }
+
+    pub fn slave_stop_listen(&self) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::SLAVE_STOP_LISTEN, 0, 0).map_err(Into::into)
+    }
+
+    pub fn slave_set_address(&self, address: usize) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::SLAVE_SET_ADDRESS, address, 0)
+            .map_err(Into::into)
+    }
+
+    pub fn master_write_read(
+        &self,
+        address: usize,
+        read_length: usize,
+        write_length: usize,
+    ) -> TockResult<usize> {
+        syscalls::command(
+            DRIVER_NUMBER,
+            command_nr::MASTER_WRITE_READ,
+            address & 0xFF | read_length << 8 | write_length << 16,
+            0,
+        )
+        .map_err(Into::into)
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 96d2720..619c379 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,6 +13,7 @@
 pub mod futures;
 pub mod gpio;
 pub mod hmac;
+pub mod i2c;
 pub mod leds;
 pub mod result;
 pub mod rng;