use core::fmt::Write; // todo: this should probably be in the dev module pub trait Serial { fn put(&self, c: u8); fn putstr(&self, s: &str); fn put_bytes(&self, s: &[u8]); fn get(&self) -> Option; } pub struct UART { offset: usize, } impl UART { pub fn init(&self) { let offset = self.offset as *mut u8; unsafe { // word length let lcr = (1 << 0) | (1 << 1); offset.add(3).write_volatile(lcr); // enable fifo offset.add(2).write_volatile(1 << 0); // receiver buffer interrupts offset.add(1).write_volatile(1 << 0); // divisor boilerplate code, maybe check this later if we want custom baud rate let divisor: u16 = 592; let dlo: u8 = (divisor & 0xff) as u8; let dhi: u8 = (divisor >> 8) as u8; offset.add(3).write_volatile(lcr | 1 << 7); offset.add(0).write_volatile(dlo); offset.add(1).write_volatile(dhi); offset.add(3).write_volatile(lcr); } } pub fn new_and_init(offset: usize) -> UART { let uart = UART { offset: offset }; uart.init(); uart } pub const fn new(offset: usize) -> UART { let uart = UART { offset: offset }; uart } pub fn get(&self) -> Option { unsafe { if (self.offset as *mut u8).add(5).read_volatile() & 1 == 0 { None } else { Some((self.offset as *mut u8).add(0).read_volatile()) } } } pub fn put(&self, c: u8) { unsafe { (self.offset as *mut u8).add(0).write_volatile(c); } } pub fn putstr(&self, s: &str) { for c in s.bytes() { self.put(c); } } pub fn put_bytes(&self, s: &[u8]) { for c in s { self.put(*c); } } } impl Write for UART { fn write_str(&mut self, s: &str) -> core::fmt::Result { for c in s.bytes() { self.put(c); } Ok(()) } } impl Serial for UART { fn put(&self, c: u8) { self.put(c); } fn putstr(&self, s: &str) { self.putstr(s); } fn put_bytes(&self, s: &[u8]) { self.put_bytes(s); } fn get(&self) -> Option { self.get() } }