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;