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 core::fmt;
|
||||||
|
|
||||||
use crate::traits::console::{Console, Write};
|
use crate::traits::console::{Console, Read, Write};
|
||||||
|
|
||||||
use crate::traits::synchronization::{DummyMutex, Mutex};
|
use crate::traits::synchronization::{DummyMutex, Mutex};
|
||||||
|
|
||||||
/// The address for the magic qemu output
|
/// The address for the magic qemu uart
|
||||||
const QEMU_MAGIC_OUTPUT_ADDR: *mut u8 = 0x3F20_1000 as *mut u8;
|
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.
|
/// The unique QemuUart allowing access to the qemu uart.
|
||||||
static QEMU_OUTPUT: QemuOutput = QemuOutput::new();
|
static QEMU_UART: QemuUart = QemuUart::new();
|
||||||
|
|
||||||
/// A structure allowing access to the qemu magic output.
|
/// A structure allowing access to the qemu magic uart.
|
||||||
struct QemuOutput {
|
struct QemuUart {
|
||||||
inner: DummyMutex<QemuOutputInner>,
|
inner: DummyMutex<QemuUartInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inner Qemu output.
|
/// Inner Qemu Uart.
|
||||||
struct QemuOutputInner;
|
struct QemuUartInner;
|
||||||
|
|
||||||
impl QemuOutputInner {
|
impl QemuUartInner {
|
||||||
/// Constructor for [`QemuOutputInner`].
|
/// Constructor for [`QemuUartInner`].
|
||||||
const fn new() -> Self {
|
const fn new() -> Self {
|
||||||
Self {}
|
Self {}
|
||||||
}
|
}
|
||||||
|
@ -29,26 +29,39 @@ impl QemuOutputInner {
|
||||||
/// Write a character to the output.
|
/// Write a character to the output.
|
||||||
fn write_char(&mut self, c: char) {
|
fn write_char(&mut self, c: char) {
|
||||||
unsafe {
|
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 {
|
impl QemuUart {
|
||||||
/// Constructor for [`QemuOutput`].
|
/// Constructor for [`QemuUart`].
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
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
|
/// `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
|
/// using unmutable references (`&self`), so we will use a custom
|
||||||
/// interface for it.
|
/// interface for it.
|
||||||
impl fmt::Write for QemuOutputInner {
|
impl fmt::Write for QemuUartInner {
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
for c in s.chars() {
|
for c in s.chars() {
|
||||||
// \n -> \r\n
|
// \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) {
|
fn write_char(&self, c: char) {
|
||||||
self.inner.lock(|q_out| q_out.write_char(c))
|
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?
|
// TODO: move?
|
||||||
/// Return a reference to the Qemu Output.
|
/// Return a reference to the Qemu Uart.
|
||||||
pub fn console() -> &'static dyn Console {
|
pub fn console() -> &'static dyn Console {
|
||||||
&QEMU_OUTPUT
|
&QEMU_UART
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use crate::traits::console::{Write, Console};
|
use crate::traits::console::{Console, Read, Write};
|
||||||
use crate::traits::synchronization::{DummyMutex, Mutex};
|
use crate::traits::synchronization::{DummyMutex, Mutex};
|
||||||
|
|
||||||
use super::memory_map::uart as mm;
|
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> {
|
impl<'a> Uart<'a> {
|
||||||
|
|
||||||
// TODO: not sure this should be public? public in bsp only?
|
// 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;
|
use core::arch::asm;
|
||||||
|
|
||||||
// TODO: handle this with features
|
// TODO: handle this with features
|
||||||
//use crate::bsp::qemu::console::console;
|
use crate::bsp::qemu::console::console;
|
||||||
#[cfg(not(test))]
|
//#[cfg(not(test))]
|
||||||
use crate::bsp::rpi3::uart::console;
|
//use crate::bsp::rpi3::uart::console;
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
use crate::bsp::rpi3::gpio;
|
use crate::bsp::rpi3::gpio;
|
||||||
|
|
||||||
|
@ -66,9 +66,29 @@ pub unsafe fn _start_rust() -> ! {
|
||||||
match gpio::set_pin_output_state(20, gpio::PinOutputState::Low) {
|
match gpio::set_pin_output_state(20, gpio::PinOutputState::Low) {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
bsp::rpi3::uart::init();
|
//bsp::rpi3::uart::init();
|
||||||
println!("Hello there");
|
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) {
|
match gpio::set_pin_fonction(21, gpio::PinFunction::Output) {
|
||||||
Ok(()) => println!("Successfully set pin to output"),
|
Ok(()) => println!("Successfully set pin to output"),
|
||||||
Err(err) => println!("Failled to set pin: {err}"),
|
Err(err) => println!("Failled to set pin: {err}"),
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
/// Trait allowing a structure to be used as a console.
|
/// 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.
|
/// Trait allowing to write to an object.
|
||||||
pub trait Write {
|
pub trait Write {
|
||||||
|
@ -17,6 +17,17 @@ pub trait Write {
|
||||||
fn flush(&self);
|
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.
|
/// A Dummy Console.
|
||||||
///
|
///
|
||||||
/// The DummyConsole implement the [`Console`] trait, and do nothing.
|
/// The DummyConsole implement the [`Console`] trait, and do nothing.
|
||||||
|
@ -32,4 +43,13 @@ impl Write for DummyConsole {
|
||||||
fn flush(&self) {}
|
fn flush(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Read for DummyConsole {
|
||||||
|
fn read_char(&self) -> char {
|
||||||
|
' '
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_input(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Console for DummyConsole {}
|
impl Console for DummyConsole {}
|
||||||
|
|
Loading…
Reference in a new issue