89 lines
2.5 KiB
Rust
89 lines
2.5 KiB
Rust
// src/uart.rs
|
|
//! This module provides access to the UART console.
|
|
|
|
use spin::Mutex; // Replaces spinning_top crate
|
|
|
|
pub static CONSOLE: Mutex<Option<Device>> = 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<u8> {
|
|
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)*));
|
|
}
|