// src/uart.rs //! This module provides access to the UART console. use spin::Mutex; // Replaces spinning_top crate pub static CONSOLE: Mutex> = Mutex::new(None); /// Represents an initialised UART device. pub struct Device { base: usize, } impl Device { /// Create a new UART device. /// # Safety /// `base` must be the base address of a UART device. pub fn new(base: usize) -> Self { use core::ptr::write_volatile; let addr = base as *mut u8; // Set data size to 8 bits. unsafe { write_volatile(addr.offset(3), 0b11) }; // Enable FIFO. unsafe { write_volatile(addr.offset(2), 0b1) }; // Enable receiver buffer interrupts. unsafe { write_volatile(addr.offset(1), 0b1) }; // Return a new, initialised UART device. Device { base } } pub fn put(&mut self, character: u8) { let ptr = self.base as *mut u8; // UNSAFE: fine as long as self.base is valid unsafe { core::ptr::write_volatile(ptr, character); } } /// Gets a character from the UART input. pub fn get(&mut self) -> Option { const READY: u8 = 0b1; let ptr = self.base as *mut u8; // SAFETY: Fine as long as base is correct. let lsr = unsafe { ptr.offset(5) }; unsafe { if core::ptr::read_volatile(lsr) & READY == READY { Some(core::ptr::read_volatile(ptr)) } else { None } } } } impl core::fmt::Write for Device { fn write_str(&mut self, s: &str) -> core::fmt::Result { for c in s.bytes() { self.put(c); } Ok(()) // there are never errors writing to UART :) } } /// Initialise the UART debugging console. /// # Safety /// `base` must point to the base address of a UART device. pub fn init_console(base: usize) { let mut console = CONSOLE.lock(); *console = Some(Device::new(base)); } /// Prints a formatted string to the [CONSOLE]. #[macro_export] macro_rules! print { ($($arg:tt)*) => ({ use core::fmt::Write; $crate::uart::CONSOLE.lock().as_mut().map(|writer| { writer.write_fmt(format_args!($($arg)*)).unwrap() }); }); } /// println prints a formatted string to the [CONSOLE] with a trailing newline character. #[macro_export] macro_rules! println { ($fmt:expr) => ($crate::print!(concat!($fmt, "\n"))); ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*)); }