| use crate::callback::Identity0Consumer; |
| use crate::executor; |
| use crate::futures; |
| use crate::result::TockResult; |
| use crate::syscalls; |
| use core::cell::Cell; |
| use core::fmt; |
| use core::mem; |
| |
| const DRIVER_NUMBER: usize = 1; |
| |
| mod command_nr { |
| pub const WRITE: usize = 1; |
| } |
| |
| mod subscribe_nr { |
| pub const SET_ALARM: usize = 1; |
| } |
| |
| mod allow_nr { |
| pub const SHARE_BUFFER: usize = 1; |
| } |
| |
| #[non_exhaustive] |
| pub struct ConsoleDriver; |
| |
| impl ConsoleDriver { |
| pub fn create_console(self) -> Console { |
| Console { |
| allow_buffer: [0; 64], |
| } |
| } |
| } |
| |
| pub struct Console { |
| allow_buffer: [u8; 64], |
| } |
| |
| impl Console { |
| pub fn write<S: AsRef<[u8]>>(&mut self, text: S) -> TockResult<()> { |
| let mut not_written_yet = text.as_ref(); |
| while !not_written_yet.is_empty() { |
| let num_bytes_to_print = self.allow_buffer.len().min(not_written_yet.len()); |
| self.allow_buffer[..num_bytes_to_print] |
| .copy_from_slice(¬_written_yet[..num_bytes_to_print]); |
| self.flush(num_bytes_to_print)?; |
| not_written_yet = ¬_written_yet[num_bytes_to_print..]; |
| } |
| Ok(()) |
| } |
| |
| fn flush(&mut self, num_bytes_to_print: usize) -> TockResult<()> { |
| let shared_memory = syscalls::allow( |
| DRIVER_NUMBER, |
| allow_nr::SHARE_BUFFER, |
| &mut self.allow_buffer[..num_bytes_to_print], |
| )?; |
| |
| let is_written = Cell::new(false); |
| let mut is_written_alarm = || is_written.set(true); |
| let subscription = syscalls::subscribe::<Identity0Consumer, _>( |
| DRIVER_NUMBER, |
| subscribe_nr::SET_ALARM, |
| &mut is_written_alarm, |
| )?; |
| |
| syscalls::command(DRIVER_NUMBER, command_nr::WRITE, num_bytes_to_print, 0)?; |
| |
| unsafe { executor::block_on(futures::wait_until(|| is_written.get())) }; |
| |
| mem::drop(subscription); |
| mem::drop(shared_memory); |
| |
| Ok(()) |
| } |
| } |
| |
| impl fmt::Write for Console { |
| fn write_str(&mut self, string: &str) -> Result<(), fmt::Error> { |
| self.write(string).map_err(|_| fmt::Error) |
| } |
| } |