vesper/src/devices/console.rs

163 lines
4.2 KiB
Rust

/*
* MIT License
*
* Copyright (c) 2019 Andre Richter <andre.o.richter@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::jlink_rtt::Output as JLinkOutput;
use crate::platform;
use core::fmt::{self, Write};
/// A trait that must be implemented by devices that are candidates for the
/// global console.
#[allow(unused_variables)]
pub trait ConsoleOps: Drop {
fn putc(&self, c: char) {}
fn puts(&self, string: &str) {}
fn getc(&self) -> char {
' '
}
fn flush(&self) {}
}
/// A dummy console that just ignores its inputs.
pub struct NullConsole;
impl Drop for NullConsole {
fn drop(&mut self) {}
}
impl ConsoleOps for NullConsole {}
/// Possible outputs which the console can store.
pub enum Output {
None(NullConsole),
MiniUart(platform::MiniUart),
PL011Uart(platform::PL011Uart),
RTT(JLinkOutput),
}
impl From<platform::MiniUart> for Output {
fn from(instance: platform::MiniUart) -> Self {
Output::MiniUart(instance)
}
}
impl From<platform::PL011Uart> for Output {
fn from(instance: platform::PL011Uart) -> Self {
Output::PL011Uart(instance)
}
}
impl From<JLinkOutput> for Output {
fn from(instance: JLinkOutput) -> Self {
Output::RTT(instance)
}
}
pub struct Console {
output: Output,
}
impl Console {
pub const fn new() -> Console {
Console {
output: Output::None(NullConsole {}),
}
}
#[inline(always)]
fn current_ptr(&self) -> &dyn ConsoleOps {
match &self.output {
Output::None(i) => i,
Output::MiniUart(i) => i,
Output::PL011Uart(i) => i,
Output::RTT(i) => i,
}
}
/// Overwrite the current output. The old output will go out of scope and
/// it's Drop function will be called.
pub fn replace_with(&mut self, x: Output) {
self.current_ptr().flush();
self.output = x;
}
/// A command prompt.
pub fn command_prompt<'a>(&self, buf: &'a mut [u8]) -> &'a [u8] {
self.puts("\n$> ");
let mut i = 0;
let mut input;
loop {
input = self.getc();
if input == '\n' {
self.putc('\n');
return &buf[..i];
} else {
if i < buf.len() {
buf[i] = input as u8;
i += 1;
} else {
return &buf[..i];
}
self.putc(input);
}
}
}
}
impl Drop for Console {
fn drop(&mut self) {}
}
/// Dispatch the respective function to the currently stored output device.
impl ConsoleOps for Console {
fn putc(&self, c: char) {
self.current_ptr().putc(c);
}
fn puts(&self, string: &str) {
self.current_ptr().puts(string);
}
fn getc(&self) -> char {
self.current_ptr().getc()
}
fn flush(&self) {
self.current_ptr().flush()
}
}
/// Implementing this trait enables usage of the format_args! macros, which in
/// turn are used to implement the kernel's print! and println! macros.
///
/// See src/macros.rs.
impl fmt::Write for Console {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.current_ptr().puts(s);
Ok(())
}
}