Merge #255 #257 #258

255: libmctp: Initial support of MCTP support r=jrvanwhy a=alistair23

MCTP (Management Component Transport Protocol) is a transport layer that is commonly used for server management. It supports multiple underlying protocols, but in this case we are focued on SMBus.

This adds initial support for a MCTP example in libtock-rs.

257: Add ninedof example r=jrvanwhy a=l162

For unit testing.

258: stm32f3discovery support r=jrvanwhy a=l162

Adds support for stm32f3discovery.

Co-authored-by: Alistair Francis <alistair.francis@wdc.com>
Co-authored-by: l162 <l162@hey.com>
diff --git a/Cargo.toml b/Cargo.toml
index caeae02..99543d9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,7 @@
 p256 = { version = "0.5.0" , default-features = false, features = ["arithmetic", "ecdsa", "ecdsa-core"] }
 subtle = { version = "2.3.0", default-features = false, features = ["i128"] }
 generic-array = { version = "0.14.3" }
+libmctp = { version = "0.1.0" }
 
 # We need to override this to allow builds for targets that don't support atomics.
 # Once a version newer then 0.4.11 is released we can update to use that.
diff --git a/examples/libmctp.rs b/examples/libmctp.rs
new file mode 100644
index 0000000..8623665
--- /dev/null
+++ b/examples/libmctp.rs
@@ -0,0 +1,105 @@
+#![no_std]
+/// This is a example of a MCTP master device
+use libmctp::smbus::{MCTPSMBusContext, VendorIDFormat};
+use libtock::i2c_master::I2cBuffer;
+use libtock::println;
+use libtock::result::TockResult;
+use libtock::syscalls;
+
+libtock_core::stack_size! {0x800}
+
+// The address of this device
+const MY_ID: u8 = 0x23;
+const DEST_ID: u8 = 0x10;
+// Support vendor defined protocol 0x7E
+const MSG_TYPES: [u8; 1] = [0x7E];
+// Specify a PCI vendor ID that we support
+const VENDOR_IDS: [libmctp::smbus::VendorIDFormat; 1] = [VendorIDFormat {
+    // PCI Vendor ID
+    format: 0x00,
+    // PCI VID
+    data: 0x1414,
+    // Extra data
+    numeric_value: 4,
+}];
+
+#[libtock::main]
+async fn main() -> TockResult<()> {
+    let mut drivers = libtock::retrieve_drivers()?;
+    drivers.console.create_console();
+    println!("Starting libmctp example");
+    let i2c_driver = drivers.i2c.init_driver()?;
+
+    // Check that I2C exists
+    if i2c_driver.check_present().is_err() {
+        println!("No I2C device, yielding");
+        loop {
+            unsafe { syscalls::raw::yieldk() };
+        }
+    }
+    println!("Found the I2C device");
+
+    println!("Setting callback");
+    let mut callback = |_, _| {
+        println!("I2C Callback");
+    };
+
+    let _subscription = i2c_driver.subscribe(&mut callback)?;
+    println!("Creating MCTP SMBus Context");
+    let ctx = MCTPSMBusContext::new(MY_ID, &MSG_TYPES, &VENDOR_IDS);
+
+    let mut buf: [u8; 32] = [0; 32];
+
+    println!("Creating the request");
+    let len = ctx
+        .get_request()
+        .get_vendor_defined_message_support(0xB, 0, &mut buf);
+
+    println!("Creating master write buffer");
+    let mut master_write_buffer = I2cBuffer::default();
+    // Skip the first byte, as that is the destination address
+    for (i, d) in buf[1..].iter().enumerate() {
+        master_write_buffer[i] = *d;
+    }
+    let dest_buffer = i2c_driver.init_buffer(&mut master_write_buffer)?;
+    println!("  done");
+
+    let _ = i2c_driver.write(DEST_ID as usize, len.unwrap());
+
+    unsafe { syscalls::raw::yieldk() };
+
+    // Read 4 bytes for the SMBus header
+    let _ = i2c_driver.read(DEST_ID as usize, 4);
+
+    unsafe { syscalls::raw::yieldk() };
+
+    // Copy into a temp buffer
+    let mut temp_buffer = [0; libtock::hmac::DEST_BUFFER_SIZE];
+    dest_buffer.read_bytes(&mut temp_buffer[1..4]);
+
+    // Determine the full length
+    let bytes = ctx.get_length(&temp_buffer).unwrap();
+
+    // Read the full packet. The slave will re-send the data, so do
+    // a full read
+    let _ = i2c_driver.read(DEST_ID as usize, bytes - 1);
+
+    unsafe { syscalls::raw::yieldk() };
+
+    // Copy in the full packet, with space for the destination address
+    dest_buffer.read_bytes(&mut temp_buffer[1..bytes - 1]);
+
+    // Set the destination address as this isn't filled in the buffer from
+    // the kernel
+    temp_buffer[0] = DEST_ID << 1;
+
+    // Decode the response
+    let ret = ctx.decode_packet(&temp_buffer[0..bytes]);
+
+    // Print the outcome of the decode
+    println!("ret: {:?}", ret);
+
+    loop {
+        unsafe { syscalls::raw::yieldk() };
+    }
+}
diff --git a/examples/ninedof.rs b/examples/ninedof.rs
new file mode 100644
index 0000000..ec0724c
--- /dev/null
+++ b/examples/ninedof.rs
@@ -0,0 +1,23 @@
+#![no_std]
+
+use libtock::println;
+use libtock::result::TockResult;
+use libtock::timer::Duration;
+
+libtock_core::stack_size! {0x800}
+
+#[libtock::main]
+async fn main() -> TockResult<()> {
+    let mut drivers = libtock::retrieve_drivers()?;
+
+    let mut timer_driver = drivers.timer.create_timer_driver();
+    let timer_driver = timer_driver.activate()?;
+    drivers.console.create_console();
+
+    loop {
+        println!("Mag:   {}\n", drivers.ninedof.read_magnetometer()?);
+        println!("Accel: {}\n", drivers.ninedof.read_acceleration()?);
+        println!("Gyro:  {}\n", drivers.ninedof.read_gyroscope()?);
+        timer_driver.sleep(Duration::from_ms(500)).await?;
+    }
+}
diff --git a/src/drivers.rs b/src/drivers.rs
index 7df124b..8604691 100644
--- a/src/drivers.rs
+++ b/src/drivers.rs
@@ -4,7 +4,8 @@
 use crate::ctap::CtapDriverFactory;
 use crate::gpio::GpioDriverFactory;
 use crate::hmac::HmacDriverFactory;
-use crate::i2c::I2cDriverFactory;
+use crate::i2c_master::I2cDriverFactory;
+use crate::i2c_master_slave::I2cMSDriverFactory;
 use crate::leds::LedsDriverFactory;
 use crate::result::OtherError;
 use crate::result::TockError;
@@ -31,6 +32,7 @@
     pub temperature: TemperatureDriverFactory,
     pub buttons: ButtonsDriverFactory,
     pub adc: AdcDriverFactory,
+    pub i2c_ms: I2cMSDriverFactory,
     pub i2c: I2cDriverFactory,
     pub rng: RngDriver,
     pub ble_advertising: BleAdvertisingDriverFactory,
@@ -79,6 +81,7 @@
     },
     gpio: GpioDriverFactory,
     hmac: HmacDriverFactory,
+    i2c_ms: I2cMSDriverFactory,
     i2c: I2cDriverFactory,
     temperature: TemperatureDriverFactory,
     rng: RngDriver,
diff --git a/src/i2c_master.rs b/src/i2c_master.rs
new file mode 100644
index 0000000..55f2ee1
--- /dev/null
+++ b/src/i2c_master.rs
@@ -0,0 +1,112 @@
+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 = 0x20003;
+
+pub const BUFFER_SIZE: usize = 64;
+
+mod command_nr {
+    pub const CHECK_PRESENT: usize = 0;
+    pub const WRITE: usize = 1;
+    pub const READ: usize = 2;
+    pub const WRITE_READ: usize = 3;
+}
+
+mod subscribe_nr {
+    pub const SUBSCRIBE_CALLBACK: usize = 1;
+}
+
+mod allow_nr {
+    pub const BUFFER: usize = 1;
+}
+
+#[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 I2cBuffer {
+    buffer: [u8; BUFFER_SIZE],
+}
+
+impl Default for I2cBuffer {
+    fn default() -> Self {
+        I2cBuffer {
+            buffer: [0; BUFFER_SIZE],
+        }
+    }
+}
+
+impl Deref for I2cBuffer {
+    type Target = [u8; BUFFER_SIZE];
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl DerefMut for I2cBuffer {
+    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_buffer(&self, buffer: &'a mut I2cBuffer) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::BUFFER, &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 write(&self, address: usize, length: usize) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::WRITE, address, length).map_err(Into::into)
+    }
+
+    pub fn read(&self, address: usize, length: usize) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::READ, address, length).map_err(Into::into)
+    }
+
+    pub fn write_read(&self, address: usize, length: usize) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::WRITE_READ, address, length)
+            .map_err(Into::into)
+    }
+}
diff --git a/src/i2c.rs b/src/i2c_master_slave.rs
similarity index 80%
rename from src/i2c.rs
rename to src/i2c_master_slave.rs
index 8256af8..0e3cce6 100644
--- a/src/i2c.rs
+++ b/src/i2c_master_slave.rs
@@ -35,38 +35,38 @@
 }
 
 #[non_exhaustive]
-pub struct I2cDriverFactory;
+pub struct I2cMSDriverFactory;
 
-impl I2cDriverFactory {
-    pub fn init_driver(&mut self) -> TockResult<I2cDriver> {
-        let i2c = I2cDriver {
+impl I2cMSDriverFactory {
+    pub fn init_driver(&mut self) -> TockResult<I2cMSDriver> {
+        let i2c_ms = I2cMSDriver {
             lifetime: PhantomData,
         };
-        Ok(i2c)
+        Ok(i2c_ms)
     }
 }
 
-struct I2cEventConsumer;
+struct I2cMSEventConsumer;
 
-impl<CB: FnMut(usize, usize)> Consumer<CB> for I2cEventConsumer {
+impl<CB: FnMut(usize, usize)> Consumer<CB> for I2cMSEventConsumer {
     fn consume(callback: &mut CB, _: usize, _: usize, _: usize) {
         callback(0, 0);
     }
 }
 
-pub struct I2cMasterWriteBuffer {
+pub struct I2cMSMasterWriteBuffer {
     buffer: [u8; MASTER_BUFFER_SIZE],
 }
 
-impl Default for I2cMasterWriteBuffer {
+impl Default for I2cMSMasterWriteBuffer {
     fn default() -> Self {
-        I2cMasterWriteBuffer {
+        I2cMSMasterWriteBuffer {
             buffer: [0; MASTER_BUFFER_SIZE],
         }
     }
 }
 
-impl Deref for I2cMasterWriteBuffer {
+impl Deref for I2cMSMasterWriteBuffer {
     type Target = [u8; MASTER_BUFFER_SIZE];
 
     fn deref(&self) -> &Self::Target {
@@ -74,25 +74,25 @@
     }
 }
 
-impl DerefMut for I2cMasterWriteBuffer {
+impl DerefMut for I2cMSMasterWriteBuffer {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.buffer
     }
 }
 
-pub struct I2cMasterReadBuffer {
+pub struct I2cMSMasterReadBuffer {
     buffer: [u8; MASTER_BUFFER_SIZE],
 }
 
-impl Default for I2cMasterReadBuffer {
+impl Default for I2cMSMasterReadBuffer {
     fn default() -> Self {
-        I2cMasterReadBuffer {
+        I2cMSMasterReadBuffer {
             buffer: [0; MASTER_BUFFER_SIZE],
         }
     }
 }
 
-impl Deref for I2cMasterReadBuffer {
+impl Deref for I2cMSMasterReadBuffer {
     type Target = [u8; MASTER_BUFFER_SIZE];
 
     fn deref(&self) -> &Self::Target {
@@ -100,25 +100,25 @@
     }
 }
 
-impl DerefMut for I2cMasterReadBuffer {
+impl DerefMut for I2cMSMasterReadBuffer {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.buffer
     }
 }
 
-pub struct I2cSlaveReadBuffer {
+pub struct I2cMSSlaveReadBuffer {
     buffer: [u8; SLAVE_BUFFER_SIZE],
 }
 
-impl Default for I2cSlaveReadBuffer {
+impl Default for I2cMSSlaveReadBuffer {
     fn default() -> Self {
-        I2cSlaveReadBuffer {
+        I2cMSSlaveReadBuffer {
             buffer: [0; SLAVE_BUFFER_SIZE],
         }
     }
 }
 
-impl Deref for I2cSlaveReadBuffer {
+impl Deref for I2cMSSlaveReadBuffer {
     type Target = [u8; SLAVE_BUFFER_SIZE];
 
     fn deref(&self) -> &Self::Target {
@@ -126,25 +126,25 @@
     }
 }
 
-impl DerefMut for I2cSlaveReadBuffer {
+impl DerefMut for I2cMSSlaveReadBuffer {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.buffer
     }
 }
 
-pub struct I2cSlaveWriteBuffer {
+pub struct I2cMSSlaveWriteBuffer {
     buffer: [u8; SLAVE_BUFFER_SIZE],
 }
 
-impl Default for I2cSlaveWriteBuffer {
+impl Default for I2cMSSlaveWriteBuffer {
     fn default() -> Self {
-        I2cSlaveWriteBuffer {
+        I2cMSSlaveWriteBuffer {
             buffer: [0; SLAVE_BUFFER_SIZE],
         }
     }
 }
 
-impl Deref for I2cSlaveWriteBuffer {
+impl Deref for I2cMSSlaveWriteBuffer {
     type Target = [u8; SLAVE_BUFFER_SIZE];
 
     fn deref(&self) -> &Self::Target {
@@ -152,20 +152,20 @@
     }
 }
 
-impl DerefMut for I2cSlaveWriteBuffer {
+impl DerefMut for I2cMSSlaveWriteBuffer {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.buffer
     }
 }
 
-pub struct I2cDriver<'a> {
+pub struct I2cMSDriver<'a> {
     lifetime: PhantomData<&'a ()>,
 }
 
-impl<'a> I2cDriver<'a> {
+impl<'a> I2cMSDriver<'a> {
     pub fn init_master_write_buffer(
         &self,
-        buffer: &'a mut I2cMasterWriteBuffer,
+        buffer: &'a mut I2cMSMasterWriteBuffer,
     ) -> TockResult<SharedMemory> {
         syscalls::allow(DRIVER_NUMBER, allow_nr::MASTER_WRIE, &mut buffer.buffer)
             .map_err(Into::into)
@@ -173,7 +173,7 @@
 
     pub fn init_master_read_buffer(
         &self,
-        buffer: &'a mut I2cMasterReadBuffer,
+        buffer: &'a mut I2cMSMasterReadBuffer,
     ) -> TockResult<SharedMemory> {
         syscalls::allow(DRIVER_NUMBER, allow_nr::MASTER_READ, &mut buffer.buffer)
             .map_err(Into::into)
@@ -181,14 +181,14 @@
 
     pub fn init_slave_read_buffer(
         &self,
-        buffer: &'a mut I2cSlaveReadBuffer,
+        buffer: &'a mut I2cMSSlaveReadBuffer,
     ) -> 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,
+        buffer: &'a mut I2cMSSlaveWriteBuffer,
     ) -> TockResult<SharedMemory> {
         syscalls::allow(DRIVER_NUMBER, allow_nr::SLAVE_WRITE, &mut buffer.buffer)
             .map_err(Into::into)
@@ -198,7 +198,7 @@
         &self,
         callback: &'a mut CB,
     ) -> TockResult<CallbackSubscription> {
-        syscalls::subscribe::<I2cEventConsumer, _>(
+        syscalls::subscribe::<I2cMSEventConsumer, _>(
             DRIVER_NUMBER,
             subscribe_nr::SUBSCRIBE_CALLBACK,
             callback,
diff --git a/src/lib.rs b/src/lib.rs
index 619c379..6f5be5a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,7 +13,8 @@
 pub mod futures;
 pub mod gpio;
 pub mod hmac;
-pub mod i2c;
+pub mod i2c_master;
+pub mod i2c_master_slave;
 pub mod leds;
 pub mod result;
 pub mod rng;