Define console trait Write and implement POC for the QEMU uart

This commit is contained in:
histausse 2022-11-15 23:37:52 +01:00
parent 571a2c995e
commit ca47faf168
Signed by: histausse
GPG key ID: 67486F107F62E9E9
4 changed files with 99 additions and 30 deletions

View file

@ -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<QemuOutputInner>,
/// A structure allowing access to the qemu magic uart.
struct QemuUart {
inner: DummyMutex<QemuUartInner>,
}
/// 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
}

View file

@ -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?

View file

@ -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}"),

View file

@ -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 {}