use core::ptr::NonNull;
use tock_registers::{
interfaces::{Readable, Writeable},
register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
register_structs! {
Pl011UartRegs {
(0x00 => dr: ReadWrite<u32>),
(0x04 => _reserved0),
(0x18 => fr: ReadOnly<u32>),
(0x1c => _reserved1),
(0x30 => cr: ReadWrite<u32>),
(0x34 => ifls: ReadWrite<u32>),
(0x38 => imsc: ReadWrite<u32>),
(0x3c => ris: ReadOnly<u32>),
(0x40 => mis: ReadOnly<u32>),
(0x44 => icr: WriteOnly<u32>),
(0x48 => @END),
}
}
pub struct Pl011Uart {
base: NonNull<Pl011UartRegs>,
}
unsafe impl Send for Pl011Uart {}
unsafe impl Sync for Pl011Uart {}
impl Pl011Uart {
pub const fn new(base: *mut u8) -> Self {
Self {
base: NonNull::new(base).unwrap().cast(),
}
}
const fn regs(&self) -> &Pl011UartRegs {
unsafe { self.base.as_ref() }
}
pub fn init(&mut self) {
self.regs().icr.set(0x7ff);
self.regs().ifls.set(0);
self.regs().imsc.set(1 << 4);
self.regs().cr.set((1 << 0) | (1 << 8) | (1 << 9)); }
pub fn putchar(&mut self, c: u8) {
while self.regs().fr.get() & (1 << 5) != 0 {}
self.regs().dr.set(c as u32);
}
pub fn getchar(&mut self) -> Option<u8> {
if self.regs().fr.get() & (1 << 4) == 0 {
Some(self.regs().dr.get() as u8)
} else {
None
}
}
pub fn is_receive_interrupt(&self) -> bool {
let pending = self.regs().mis.get();
pending & (1 << 4) != 0
}
pub fn ack_interrupts(&mut self) {
self.regs().icr.set(0x7ff);
}
}