| #![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() }; | |
| } | |
| } |