| use core::cell::Cell; |
| use kernel::{AppId, AppSlice, Callback, Driver, Grant, ReturnCode, Shared}; |
| use matcha_hal::dprintf; |
| use matcha_hal::mailbox_hal::MailboxHAL; |
| |
| use matcha_config::*; |
| |
| //------------------------------------------------------------------------------ |
| |
| pub struct AppData { |
| pub send_callback: Option<Callback>, |
| pub recv_callback: Option<Callback>, |
| pub send_buffer: Option<AppSlice<Shared, u8>>, |
| pub recv_buffer: Option<AppSlice<Shared, u8>>, |
| } |
| |
| impl Default for AppData { |
| fn default() -> AppData { |
| AppData { |
| send_callback: None, |
| recv_callback: None, |
| send_buffer: None, |
| recv_buffer: None, |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| // MailboxCapsule is a global static singleton - its members have to be |
| // pseudo-const. |
| |
| pub struct MailboxCapsule { |
| pub app_data_grant: Grant<AppData>, |
| pub mailbox_hal: Cell<Option<&'static dyn MailboxHAL>>, |
| pub current_app: Cell<Option<AppId>>, |
| } |
| |
| //---------------------------------------- |
| |
| impl MailboxCapsule { |
| pub fn new(app_data_grant: Grant<AppData>) -> Self { |
| return MailboxCapsule { |
| app_data_grant: app_data_grant, |
| mailbox_hal: Cell::new(None), |
| current_app: Cell::new(None), |
| }; |
| } |
| |
| pub fn set_mailbox(&self, mailbox: &'static dyn MailboxHAL) { |
| self.mailbox_hal.set(Some(mailbox)); |
| } |
| |
| pub fn handle_command( |
| &self, |
| app_id: AppId, |
| app_data: &mut AppData, |
| cmd_num: usize, |
| arg2: usize, |
| _arg3: usize, |
| ) -> ReturnCode { |
| match cmd_num { |
| CMD_MAILBOX_INIT => { |
| self.current_app.set(Some(app_id)); |
| ReturnCode::SUCCESS |
| } |
| CMD_MAILBOX_SEND => { |
| let message_len = arg2; |
| match &app_data.send_buffer { |
| Some(buffer) => { |
| self.mailbox_hal.get().map(|mb| { |
| let _ = mb.send_message_slice_sync(message_len, buffer); |
| }); |
| ReturnCode::SUCCESS |
| } |
| None => ReturnCode::FAIL, |
| } |
| } |
| CMD_MAILBOX_RECV => { |
| // Nothing to do here yet? |
| ReturnCode::SUCCESS |
| } |
| _ => { |
| dprintf!("MailboxCapsule::handle_command({:?}, ????)\n", app_id); |
| ReturnCode::EINVAL |
| } |
| } |
| } |
| |
| pub fn handle_subscribe( |
| &self, |
| _app_id: AppId, |
| app_data: &mut AppData, |
| minor_num: usize, |
| callback: Option<Callback>, |
| ) -> ReturnCode { |
| match minor_num { |
| CMD_MAILBOX_SEND => { |
| app_data.send_callback = callback; |
| ReturnCode::SUCCESS |
| } |
| CMD_MAILBOX_RECV => { |
| app_data.recv_callback = callback; |
| ReturnCode::SUCCESS |
| } |
| _ => ReturnCode::EINVAL, |
| } |
| } |
| |
| pub fn handle_allow( |
| &self, |
| _app_id: AppId, |
| app_data: &mut AppData, |
| minor_num: usize, |
| slice: Option<AppSlice<Shared, u8>>, |
| ) -> ReturnCode { |
| match minor_num { |
| CMD_MAILBOX_SEND => { |
| app_data.send_buffer = slice; |
| ReturnCode::SUCCESS |
| } |
| CMD_MAILBOX_RECV => { |
| app_data.recv_buffer = slice; |
| ReturnCode::SUCCESS |
| } |
| _ => ReturnCode::EINVAL, |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Our "driver" trait impl just unwraps the app data grant and delegates to |
| // MailboxCapsule. |
| |
| impl Driver for MailboxCapsule { |
| fn subscribe(&self, minor_num: usize, callback: Option<Callback>, app_id: AppId) -> ReturnCode { |
| self.app_data_grant |
| .enter(app_id, |app_data, _| { |
| self.handle_subscribe(app_id, app_data, minor_num, callback) |
| }) |
| .unwrap_or_else(|err| err.into()) |
| } |
| |
| fn command(&self, cmd_num: usize, r2: usize, r3: usize, app_id: AppId) -> ReturnCode { |
| self.app_data_grant |
| .enter(app_id, |app_data, _| { |
| self.handle_command(app_id, app_data, cmd_num, r2, r3) |
| }) |
| .unwrap_or_else(|err| err.into()) |
| } |
| |
| fn allow( |
| &self, |
| app_id: AppId, |
| minor_num: usize, |
| slice: Option<AppSlice<Shared, u8>>, |
| ) -> ReturnCode { |
| self.app_data_grant |
| .enter(app_id, |app_data, _| { |
| self.handle_allow(app_id, app_data, minor_num, slice) |
| }) |
| .unwrap_or_else(|err| err.into()) |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| impl matcha_hal::mailbox_hal::MailboxISR for MailboxCapsule { |
| fn on_wtirq(&self) { |
| // Nothing to do here at the moment, sends are synchronous and the |
| // polarity of the ISR is backwards. |
| } |
| |
| // When a message arrives, we copy it to the waiting app's buffer (if there |
| // is one) and then fire the app's callback. Async waiting is handled in |
| // app/src/mailbox_client.rs |
| fn on_rtirq(&self) { |
| // Unwrap all our optionals. There's probably a better way to do this. |
| self.current_app.get().map(|app_id| { |
| self.app_data_grant.enter(app_id, |app_data, _| { |
| app_data.recv_buffer.as_ref().map(|buffer| { |
| self.mailbox_hal.get().map(|mailbox| { |
| // Copy the message to the app's buffer and then |
| // schedule the app callback. |
| match mailbox.get_message_slice_sync(&buffer) { |
| Ok(len) => { |
| let page = mailbox.get_message_page().unwrap_or(0); |
| app_data.recv_callback.map(|mut callback| { |
| callback.schedule(1, len, page as usize); |
| }); |
| } |
| Err(len) => { |
| app_data.recv_callback.map(|mut callback| { |
| callback.schedule(0, len, 0); |
| }); |
| } |
| } |
| }); |
| }); |
| }) |
| }); |
| } |
| |
| fn on_eirq(&self) { |
| // We should probably do something here eventually. |
| } |
| } |