|
|
|
@ -4,24 +4,27 @@ use core::arch::asm;
|
|
|
|
|
use core::fmt;
|
|
|
|
|
|
|
|
|
|
use crate::traits::console::{Write, Console};
|
|
|
|
|
use crate::traits::synchronization::{DummyMutex, Mutex};
|
|
|
|
|
|
|
|
|
|
use super::memory_map::uart as mm;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub struct Uart<'a> {
|
|
|
|
|
inner: DummyMutex<UartInner<'a>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct UartInner<'a> {
|
|
|
|
|
initialized: bool,
|
|
|
|
|
memory_map: &'a mm::UartMemoryMap,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> Uart<'a> {
|
|
|
|
|
// TODO: not sure this should be public outside of bsp.
|
|
|
|
|
impl<'a> UartInner<'a> {
|
|
|
|
|
/// Constructor for [`Uart`].
|
|
|
|
|
pub const fn new(memory_map: &'a mm::UartMemoryMap) -> Self {
|
|
|
|
|
Uart { initialized: false, memory_map }
|
|
|
|
|
const fn new(memory_map: &'a mm::UartMemoryMap) -> Self {
|
|
|
|
|
Self { initialized: false, memory_map }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Initialise the UART.
|
|
|
|
|
pub fn init(&mut self) {
|
|
|
|
|
fn init(&mut self) {
|
|
|
|
|
// TODO: Recover from possible previous test.
|
|
|
|
|
|
|
|
|
|
self.flush();
|
|
|
|
@ -68,55 +71,80 @@ impl<'a> Uart<'a> {
|
|
|
|
|
fn is_tx_full(&self) -> bool {
|
|
|
|
|
self.memory_map.fr_txff.read() != 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Write a character to the Uart
|
|
|
|
|
fn write_char(&self, c: char) {
|
|
|
|
|
if !self.initialized {
|
|
|
|
|
panic!("Cannot write to a non initialized UART");
|
|
|
|
|
}
|
|
|
|
|
while self.is_tx_full() {
|
|
|
|
|
use super::gpio;
|
|
|
|
|
let _ = gpio::set_pin_output_state(20, gpio::PinOutputState::High);
|
|
|
|
|
unsafe { asm!("nop") };
|
|
|
|
|
}
|
|
|
|
|
self.memory_map.dr_data.write_without_read(c as u32);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Flush the uart
|
|
|
|
|
fn flush(&self) {
|
|
|
|
|
while self.is_busy() {
|
|
|
|
|
unsafe { asm!("nop") };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allow the use of uart for fmt::Write::write_fmt.
|
|
|
|
|
impl fmt::Write for Uart<'_> {
|
|
|
|
|
impl fmt::Write for UartInner<'_> {
|
|
|
|
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
|
|
|
for c in s.chars() {
|
|
|
|
|
if c == '\n' {
|
|
|
|
|
Write::write_char(self, '\r');
|
|
|
|
|
UartInner::write_char(self, '\r');
|
|
|
|
|
}
|
|
|
|
|
Write::write_char(self, c);
|
|
|
|
|
UartInner::write_char(self, c);
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: add sync
|
|
|
|
|
impl Write for Uart<'_> {
|
|
|
|
|
fn write_char(&self, c: char) {
|
|
|
|
|
if !self.initialized {
|
|
|
|
|
//panic!("Cannot write to a non initialized UART");
|
|
|
|
|
}
|
|
|
|
|
while self.is_tx_full() {
|
|
|
|
|
use super::gpio;
|
|
|
|
|
let _ = gpio::set_pin_output_state(20, gpio::PinOutputState::High);
|
|
|
|
|
unsafe { asm!("nop") };
|
|
|
|
|
}
|
|
|
|
|
self.memory_map.dr_data.write_without_read(c as u32);
|
|
|
|
|
self.inner.lock(|uart| uart.write_char(c))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result {
|
|
|
|
|
// TODO: use syncronisation here
|
|
|
|
|
let mut new_uart = Uart { initialized: self.initialized, memory_map: self.memory_map};
|
|
|
|
|
fmt::Write::write_fmt(&mut new_uart, args)
|
|
|
|
|
self.inner.lock(|uart| fmt::Write::write_fmt(uart, args))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn flush(&self) {
|
|
|
|
|
while self.is_busy() {
|
|
|
|
|
unsafe { asm!("nop") };
|
|
|
|
|
self.inner.lock(|uart| uart.flush())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> Uart<'a> {
|
|
|
|
|
|
|
|
|
|
// TODO: not sure this should be public? public in bsp only?
|
|
|
|
|
/// Create a new UART object
|
|
|
|
|
const fn new(memory_map: &'a mm::UartMemoryMap) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
inner: DummyMutex::new(
|
|
|
|
|
UartInner::new(memory_map)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Initialize the UART.
|
|
|
|
|
fn init(&self) {
|
|
|
|
|
self.inner.lock(|uart| uart.init())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Console for Uart<'_> {}
|
|
|
|
|
|
|
|
|
|
static UART: Uart = Uart { initialized: true, memory_map: &mm::UART }; // TODO: use sync
|
|
|
|
|
/// The UART object
|
|
|
|
|
static UART: Uart = Uart::new(&mm::UART);
|
|
|
|
|
|
|
|
|
|
pub fn init() {
|
|
|
|
|
let mut uart = Uart::new(&mm::UART);
|
|
|
|
|
uart.init();
|
|
|
|
|
UART.init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: move?
|
|
|
|
|