/src/console.rs
use core::cell::RefCell;
use core::fmt::Write;
use critical_section::Mutex;
use usb_device::UsbError;
use crate::{capabilities::CapType, peripherals::with_usb, task::with_task_manager};
static CONSOLE: Mutex<RefCell<Console>> = Mutex::new(RefCell::new(Console::new()));
#[derive(Debug)]
pub enum ConsoleError {
Read,
Write,
Blocked,
}
pub struct Console {
read_buffer: heapless::Deque<u8, 64>,
}
impl Console {
const fn new() -> Console {
Console {
read_buffer: heapless::Deque::new(),
}
}
pub fn fill_read_buffer(&mut self, data: &[u8]) {
for b in data {
match self.read_buffer.push_back(*b) {
Ok(()) => (),
Err(_) => break, // All remaining characters read will be dropped
}
with_task_manager(|t| t.unblock_task_with_capability(CapType::ConsoleRead));
}
}
pub fn write_ready(&mut self) {
with_task_manager(|tm| tm.unblock_task_with_capability(CapType::ConsoleWrite));
}
pub fn write(&mut self, bytes: impl AsRef<[u8]>) -> Result<usize, ConsoleError> {
with_usb(|u| match u.serial().write(bytes.as_ref()) {
Ok(n) => Ok(n),
Err(UsbError::WouldBlock) => Err(ConsoleError::Blocked),
Err(_) => Err(ConsoleError::Write),
})
}
pub fn read(&mut self, data: &mut [u8]) -> Result<usize, ConsoleError> {
if self.read_buffer.is_empty() {
return Err(ConsoleError::Blocked);
}
let mut l = 0;
for i in 0..data.len() {
data[i] = match self.read_buffer.pop_front() {
Some(b) => b,
None => break,
};
l += 1;
}
Ok(l)
}
}
pub fn init_console() {
// Does nothing since console can be statically initialized
}
pub fn with_console<F, R>(mut f: F) -> R
where
F: FnMut(&mut Console) -> R,
{
critical_section::with(|cs| {
let mut console = CONSOLE.borrow_ref_mut(cs);
f(&mut console)
})
}
pub fn write(bytes: &[u8]) -> Result<usize, ConsoleError> {
critical_section::with(|cs| {
let mut console = CONSOLE.borrow_ref_mut(cs);
console.write(bytes)
})
}
pub fn read(bytes: &mut [u8]) -> Result<usize, ConsoleError> {
critical_section::with(|cs| {
let mut console = CONSOLE.borrow_ref_mut(cs);
console.read(bytes)
})
}
pub fn flush() {
with_usb(
|u| {
while let Err(UsbError::WouldBlock) = u.serial().flush() {}
},
);
}
pub(crate) fn _printf(s: core::fmt::Arguments) {
let mut buf: heapless::Vec<u8, 256> = heapless::Vec::new();
write!(&mut buf, "{}", s).expect("write!");
let mut bytes_written = 0;
while bytes_written < buf.len() {
bytes_written += match write(&buf[bytes_written..]) {
Ok(n) => n,
Err(ConsoleError::Blocked) => 0,
Err(_) => panic!("printf"),
}
}
}
#[macro_export]
macro_rules! kprintf {
($($arg:tt)*) => {{
$crate::console::_printf(core::format_args!($($arg)*));
}}
}
#[macro_export]
macro_rules! kprint {
($($arg:tt)*) => {{
$($crate::console::write($arg.as_bytes());)*
}}
}