#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UartError {
InitFailed,
TxTimeout,
RxTimeout,
}
pub type Result<T> = core::result::Result<T, UartError>;
const UART0: usize = 0x1000_0000;
const RHR: usize = 0; const THR: usize = 0; const IER: usize = 1; const FCR: usize = 2; #[allow(dead_code)]
const ISR: usize = 2; const LCR: usize = 3; const LSR: usize = 5;
mod ier {
#[allow(dead_code)]
pub const RX_ENABLE: u8 = 1 << 0;
#[allow(dead_code)]
pub const TX_ENABLE: u8 = 1 << 1;
}
mod fcr {
pub const FIFO_ENABLE: u8 = 1 << 0;
pub const RX_FIFO_CLEAR: u8 = 1 << 1;
pub const TX_FIFO_CLEAR: u8 = 1 << 2;
pub const FIFO_CLEAR: u8 = RX_FIFO_CLEAR | TX_FIFO_CLEAR;
}
mod lcr {
pub const EIGHT_BITS: u8 = 3 << 0;
pub const BAUD_LATCH: u8 = 1 << 7;
}
mod lsr {
pub const RX_READY: u8 = 1 << 0;
pub const TX_IDLE: u8 = 1 << 5;
}
#[derive(Debug, Clone, Copy)]
pub struct Uart;
impl Uart {
#[inline]
pub const fn new() -> Self {
Self
}
pub fn init() -> Result<()> {
unsafe { write_reg(IER, 0) };
unsafe { write_reg(LCR, lcr::BAUD_LATCH) };
unsafe { write_reg(0, 0x03) };
unsafe { write_reg(1, 0x00) };
unsafe { write_reg(LCR, lcr::EIGHT_BITS) };
unsafe { write_reg(FCR, fcr::FIFO_ENABLE | fcr::FIFO_CLEAR) };
Ok(())
}
#[inline(never)]
pub fn put_char_sync(c: u8) -> Result<()> {
let mut timeout = 100_000;
while unsafe { read_reg(LSR) } & lsr::TX_IDLE == 0 {
timeout -= 1;
if timeout == 0 {
return Err(UartError::TxTimeout);
}
}
unsafe { write_reg(THR, c) };
Ok(())
}
#[inline]
pub fn put_char(c: u8) {
while unsafe { read_reg(LSR) } & lsr::TX_IDLE == 0 {}
unsafe { write_reg(THR, c) };
}
#[inline]
pub fn put_str(s: &str) {
for c in s.bytes() {
Self::put_char(c);
}
}
#[inline]
pub fn try_get_char() -> Option<u8> {
if unsafe { read_reg(LSR) } & lsr::RX_READY != 0 {
Some(unsafe { read_reg(RHR) })
} else {
None
}
}
}
#[inline]
unsafe fn read_reg(offset: usize) -> u8 {
let addr = UART0 + offset;
unsafe { (addr as *const u8).read_volatile() }
}
#[inline]
unsafe fn write_reg(offset: usize, value: u8) {
let addr = UART0 + offset;
unsafe { (addr as *mut u8).write_volatile(value) }
}