Define console trait Write and implement POC for the QEMU uart
This commit is contained in:
parent
571a2c995e
commit
ca47faf168
4 changed files with 99 additions and 30 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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?
|
||||
|
|
28
src/main.rs
28
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}"),
|
||||
|
|
|
@ -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 {}
|
||||
|
|
Loading…
Reference in a new issue