From ca47faf168c2ae1332ed614b216c37348ae5c418 Mon Sep 17 00:00:00 2001 From: Histausse Date: Tue, 15 Nov 2022 23:37:52 +0100 Subject: [PATCH] Define console trait Write and implement POC for the QEMU uart --- src/bsp/qemu/console.rs | 69 +++++++++++++++++++++++++++-------------- src/bsp/rpi3/uart.rs | 10 +++++- src/main.rs | 28 ++++++++++++++--- src/traits/console.rs | 22 ++++++++++++- 4 files changed, 99 insertions(+), 30 deletions(-) diff --git a/src/bsp/qemu/console.rs b/src/bsp/qemu/console.rs index e51a30f..f85b106 100644 --- a/src/bsp/qemu/console.rs +++ b/src/bsp/qemu/console.rs @@ -2,26 +2,26 @@ use core::fmt; -use crate::traits::console::{Console, Write}; - +use crate::traits::console::{Console, Read, Write}; use crate::traits::synchronization::{DummyMutex, Mutex}; -/// The address for the magic qemu output -const QEMU_MAGIC_OUTPUT_ADDR: *mut u8 = 0x3F20_1000 as *mut u8; +/// The address for the magic qemu uart +const QEMU_MAGIC_UART_ADDR: *mut u8 = 0x3F20_1000 as *mut u8; +const QEMU_MAGIC_UART_ADDR_FR: *mut u8 = 0x3F20_1018 as *mut u8; -/// The unique qemu output allowing access to the qemu output. -static QEMU_OUTPUT: QemuOutput = QemuOutput::new(); +/// The unique QemuUart allowing access to the qemu uart. +static QEMU_UART: QemuUart = QemuUart::new(); -/// A structure allowing access to the qemu magic output. -struct QemuOutput { - inner: DummyMutex, +/// A structure allowing access to the qemu magic uart. +struct QemuUart { + inner: DummyMutex, } -/// Inner Qemu output. -struct QemuOutputInner; +/// Inner Qemu Uart. +struct QemuUartInner; -impl QemuOutputInner { - /// Constructor for [`QemuOutputInner`]. +impl QemuUartInner { + /// Constructor for [`QemuUartInner`]. const fn new() -> Self { Self {} } @@ -29,26 +29,39 @@ impl QemuOutputInner { /// Write a character to the output. fn write_char(&mut self, c: char) { unsafe { - core::ptr::write_volatile(QEMU_MAGIC_OUTPUT_ADDR, c as u8); + core::ptr::write_volatile(QEMU_MAGIC_UART_ADDR, c as u8); + } + } + + /// Read a character from the uart. + fn read_char(&mut self) -> char { + loop { + let fr = unsafe { core::ptr::read_volatile(QEMU_MAGIC_UART_ADDR_FR) }; + if fr & 0b1_0000 == 0 { + break; + } + } + unsafe { + core::ptr::read_volatile(QEMU_MAGIC_UART_ADDR) as u8 as char } } } -impl QemuOutput { - /// Constructor for [`QemuOutput`]. +impl QemuUart { + /// Constructor for [`QemuUart`]. pub const fn new() -> Self { Self { - inner: DummyMutex::new(QemuOutputInner::new()), + inner: DummyMutex::new(QemuUartInner::new()), } } } -/// Allow to use QemuOutputInner for print! and formating macros. +/// Allow to use QemuUartInner for print! and formating macros. /// `write_str` needs `&mut self` (mutable ref), so we can implement -/// it only on the inner type, the `QemuOutput` need to be manipulable +/// it only on the inner type, the `QemuUart` need to be manipulable /// using unmutable references (`&self`), so we will use a custom /// interface for it. -impl fmt::Write for QemuOutputInner { +impl fmt::Write for QemuUartInner { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.chars() { // \n -> \r\n @@ -61,7 +74,7 @@ impl fmt::Write for QemuOutputInner { } } -impl Write for QemuOutput { +impl Write for QemuUart { fn write_char(&self, c: char) { self.inner.lock(|q_out| q_out.write_char(c)) } @@ -76,10 +89,18 @@ impl Write for QemuOutput { } } -impl Console for QemuOutput {} +impl Read for QemuUart { + fn read_char(&self) -> char { + self.inner.lock(|q_in| q_in.read_char()) + } + + fn flush_input(&self) {} +} + +impl Console for QemuUart {} // TODO: move? -/// Return a reference to the Qemu Output. +/// Return a reference to the Qemu Uart. pub fn console() -> &'static dyn Console { - &QEMU_OUTPUT + &QEMU_UART } diff --git a/src/bsp/rpi3/uart.rs b/src/bsp/rpi3/uart.rs index caf892b..7c80b52 100644 --- a/src/bsp/rpi3/uart.rs +++ b/src/bsp/rpi3/uart.rs @@ -3,7 +3,7 @@ use core::arch::asm; use core::fmt; -use crate::traits::console::{Write, Console}; +use crate::traits::console::{Console, Read, Write}; use crate::traits::synchronization::{DummyMutex, Mutex}; use super::memory_map::uart as mm; @@ -120,6 +120,14 @@ impl Write for Uart<'_> { } } +impl Read for Uart<'_> { + fn read_char(&self) -> char { + todo!() + } + + fn flush_input(&self) {} +} + impl<'a> Uart<'a> { // TODO: not sure this should be public? public in bsp only? diff --git a/src/main.rs b/src/main.rs index c42e220..2322a23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,9 +27,9 @@ use core::arch::global_asm; use core::arch::asm; // TODO: handle this with features -//use crate::bsp::qemu::console::console; -#[cfg(not(test))] -use crate::bsp::rpi3::uart::console; +use crate::bsp::qemu::console::console; +//#[cfg(not(test))] +//use crate::bsp::rpi3::uart::console; #[cfg(not(test))] use crate::bsp::rpi3::gpio; @@ -66,9 +66,29 @@ pub unsafe fn _start_rust() -> ! { match gpio::set_pin_output_state(20, gpio::PinOutputState::Low) { _ => (), } - bsp::rpi3::uart::init(); + //bsp::rpi3::uart::init(); println!("Hello there"); + let mut buffer = ['X'; 200]; + let mut i = 0; + let mut c = console().read_char(); + console().write_char(c); + while c != '\r' && i < 199 { + buffer[i] = c; + c = console().read_char(); + console().write_char(c); + i += 1; + } + buffer[i] = c; + i += 1; + let mut j = 0; + print!("Received: "); + while j < i { + print!("{}", buffer[j]); + j += 1; + } + println!(""); + match gpio::set_pin_fonction(21, gpio::PinFunction::Output) { Ok(()) => println!("Successfully set pin to output"), Err(err) => println!("Failled to set pin: {err}"), diff --git a/src/traits/console.rs b/src/traits/console.rs index 7d90ad6..9fe4660 100644 --- a/src/traits/console.rs +++ b/src/traits/console.rs @@ -3,7 +3,7 @@ use core::fmt; /// Trait allowing a structure to be used as a console. -pub trait Console: Write {} +pub trait Console: Write + Read {} /// Trait allowing to write to an object. pub trait Write { @@ -17,6 +17,17 @@ pub trait Write { fn flush(&self); } +/// Trait allowing to read from an object. +pub trait Read { + // TODO: return an option? + /// Read a single character. + fn read_char(&self) -> char; + + /// Clear the input buffer if any. + fn flush_input(&self); +} + + /// A Dummy Console. /// /// The DummyConsole implement the [`Console`] trait, and do nothing. @@ -32,4 +43,13 @@ impl Write for DummyConsole { fn flush(&self) {} } +impl Read for DummyConsole { + fn read_char(&self) -> char { + ' ' + } + + fn flush_input(&self) {} +} + + impl Console for DummyConsole {}