blob: 862366594c3422f71bd370adf49f214e3d8438ae [file] [log] [blame]
#![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() };
}
}