blob: ca217442d221dbc4d3d7b053ec9cd864c298693c [file] [log] [blame]
use core::cell::Cell;
use core::ptr;
use libtock::futures;
use libtock::syscalls;
use matcha_config::*;
//------------------------------------------------------------------------------
pub struct MailboxClient {}
impl MailboxClient {
pub fn init() {
let _ = syscalls::command(CAPSULE_MAILBOX, CMD_MAILBOX_INIT, 0, 0);
}
pub async fn wait_message_async(buffer: &mut [u8]) -> usize {
// To coordinate with async/await we need a "global-ish" flag that can
// have multiple mutable references. The Tock workaround is to put those
// kind of things in 'Cells'.
let message_size: Cell<usize> = Cell::new(0);
// The mailbox capsule will notify us using this callback,
unsafe extern "C" fn subscribe_callback(_ok: usize, _len: usize, _: usize, data: usize) {
// which just sets the message flag to true.
let message_size = &*(data as *const Cell<usize>);
message_size.set(_len)
}
// We give Tock a reference to our message and our callback+flag
unsafe {
syscalls::raw::allow(
CAPSULE_MAILBOX,
CMD_MAILBOX_RECV,
buffer.as_ptr() as *mut u8,
buffer.len(),
);
syscalls::raw::subscribe(
CAPSULE_MAILBOX,
CMD_MAILBOX_RECV,
subscribe_callback as *const _,
&message_size as *const _ as usize,
);
}
// and asynchronously wait until the callback sets the flag.
futures::wait_until(|| (message_size.get() > 0)).await;
// Then we clear Tock's references to our message and callback.
unsafe {
syscalls::raw::subscribe(CAPSULE_MAILBOX, 0, ptr::null(), 0);
syscalls::raw::allow(CAPSULE_MAILBOX, 0, ptr::null_mut(), 0);
}
return message_size.get();
}
pub fn send_message_sync(size: usize, buffer: &[u8]) {
unsafe {
syscalls::raw::allow(
CAPSULE_MAILBOX,
CMD_MAILBOX_SEND,
buffer.as_ptr() as *mut u8,
buffer.len(),
);
let _ = syscalls::command(CAPSULE_MAILBOX, CMD_MAILBOX_SEND, size, 0);
syscalls::raw::allow(CAPSULE_MAILBOX, CMD_MAILBOX_SEND, ptr::null_mut(), 0);
}
}
}