use std::collections::VecDeque; use std::io; use std::os::fd::AsFd; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; use nix::fcntl::fcntl; use nix::fcntl::{FcntlArg, OFlag}; use trve::consts::{Byte, DWord, HWord, Word}; use trve::mem::{MemAccessFault, MemDeviceInterface, PageNum}; /// byte 0: rx/tx /// byte 1: status (------rt, r=rxready, t=txready)/none pub struct BasicUart { rx_buf: Mutex>, } impl BasicUart { pub fn new() -> Self { // Make sure stdin is nonblocking let stdin = io::stdin(); let fd = stdin.as_fd(); let flags = fcntl(fd, FcntlArg::F_GETFL).unwrap(); fcntl( fd, FcntlArg::F_SETFL(OFlag::from_bits_truncate(flags) | OFlag::O_NONBLOCK), ) .unwrap(); BasicUart { rx_buf: Mutex::new(VecDeque::new()), } } pub fn spawn_poller(self, poll_interval: Duration) -> Arc { let shared = Arc::new(self); let uart_clone = shared.clone(); thread::spawn(move || { loop { uart_clone.poll(); thread::sleep(poll_interval); } }); shared } fn write(&self, byte: u8) { print!("{}", byte as char); } fn read(&self) -> u8 { self.rx_buf.lock().unwrap().pop_front().unwrap_or(0) } fn can_read(&self) -> bool { !self.rx_buf.lock().unwrap().is_empty() } pub fn poll(&self) { let mut rx_buf = self.rx_buf.lock().unwrap(); let mut buffer = [0u8; 1]; while let Ok(1) = nix::unistd::read(io::stdin().as_fd(), &mut buffer) { rx_buf.push_back(buffer[0]); } } } impl MemDeviceInterface for BasicUart { fn write_dword( &self, _page: PageNum, _offset: u16, _value: DWord, ) -> Result<(), MemAccessFault> { Err(MemAccessFault) } fn write_word(&self, _page: PageNum, _offset: u16, _value: Word) -> Result<(), MemAccessFault> { Err(MemAccessFault) } fn write_hword( &self, _page: PageNum, _offset: u16, _value: HWord, ) -> Result<(), MemAccessFault> { Err(MemAccessFault) } fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), MemAccessFault> { if page > 0 { return Err(MemAccessFault); } match offset { 0 => { self.write(value); Ok(()) } _ => Err(MemAccessFault), } } fn read_dword(&self, _page: PageNum, _offset: u16) -> Result { Err(MemAccessFault) } fn read_word(&self, _page: PageNum, _offset: u16) -> Result { Err(MemAccessFault) } fn read_hword(&self, _page: PageNum, _offset: u16) -> Result { Err(MemAccessFault) } fn read_byte(&self, page: PageNum, offset: u16) -> Result { if page > 0 { return Err(MemAccessFault); } match offset { 0 => Ok(self.read()), 1 => Ok(1 | (self.can_read() as u8) << 1), _ => Err(MemAccessFault), } } fn get_atomic_word( &self, _page: PageNum, _offset: u16, ) -> Result<&std::sync::atomic::AtomicU32, MemAccessFault> { Err(MemAccessFault) } fn get_atomic_dword( &self, _page: PageNum, _offset: u16, ) -> Result<&std::sync::atomic::AtomicU64, MemAccessFault> { Err(MemAccessFault) } }