Skip to content

Commit

Permalink
Improve console (#74)
Browse files Browse the repository at this point in the history
* Move keyboard key decoding to keyboard interrupt handler

* Read keys from serial

* Disable cursor in shell for serial

* Trim cpu brand string

* Use array for writer position

* Add Serial struct

* Add console::clear_row()

* Update autocomplete commands

* Parse ANSI color code

* Add colors to banner

* Remove newline before diskless mode

* Use lighter colors in banner

* Fix ansi color code parsing

* Use ansi colors in logger

* Rewrite colors command

* Add color to halt command

* Rewrite help command

* Use yellow color for titles

* User kernel::console::color() in shell

* Update screenshot

* Fix execute state in vte parser

* Fix typo

* Add colors to serial logger

* Fix banner colors

* Add some randomnly darker colors to banner

* Autocomplete devices path

* Create /ini/version.txt during install
  • Loading branch information
vinc authored Jul 10, 2020
1 parent 5118a3d commit 5828c7f
Show file tree
Hide file tree
Showing 18 changed files with 427 additions and 191 deletions.
58 changes: 58 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ spin = "0.5.2"
uart_16550 = "0.2.7"
volatile = "0.2.6"
x86_64 = "0.11.1"
vte = "0.8.0"
16 changes: 8 additions & 8 deletions dsk/ini/banner.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
(o o)
+-------------------ooO--(_)--Ooo------------------+
| |
| .100 110. .1100. 111110. .1001. .01000. |
| 00'1001`11 .11 01. 00 `00 .10 00. 10' 11 |
| 01 00 10 10 00 001101' 01 00 `100. |
| 10 01 10 01 11 01`00 01 11 `100. |
| 00 01 01 `00 11' 10 `11. `00 11' 01 00 |
| 11 10 10 `1001' 00 01 `0110' `01101' |
| .100 110. .1100. 111110. .1001. .01000. |
| 00'1001`11 .11 01. 00 `00 .10 00. 10' 11 |
| 01 00 10 10 00 001101' 01 00 `100. |
| 10 01 10 01 11 01`00 01 11 `100. |
| 00 01 01 `00 11' 10 `11. `00 11' 01 00 |
| 11 10 10 `1001' 00 01 `0110' `01101' |
| |
| MOROS: Obscure Rust Operating System |
| MOROS: Obscure Rust Operating System |
| |
| (v0.3.1) |
| (v{x.x.x}) |
| |
+--------------------------------------------------+

1 change: 1 addition & 0 deletions dsk/ini/version.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MOROS v{x.x.x}
Binary file modified screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 53 additions & 18 deletions src/kernel/console.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,58 @@
use crate::{print, kernel};
use alloc::string::String;
use lazy_static::lazy_static;
use pc_keyboard::{KeyCode, DecodedKey};
use spin::Mutex;
use x86_64::instructions::interrupts;

pub fn color(name: &str) -> &str {
match name {
"Black" => "\x1b[30m",
"Red" => "\x1b[31m",
"Green" => "\x1b[32m",
"Brown" => "\x1b[33m",
"Blue" => "\x1b[34m",
"Magenta" => "\x1b[35m",
"Cyan" => "\x1b[36m",
"LightGray" => "\x1b[37m",
"DarkGray" => "\x1b[90m",
"LightRed" => "\x1b[91m",
"LightGreen" => "\x1b[92m",
"Yellow" => "\x1b[93m",
"LightBlue" => "\x1b[94m",
"Pink" => "\x1b[95m",
"LightCyan" => "\x1b[96m",
"White" => "\x1b[97m",
"Reset" => "\x1b[0m",
_ => "",
}
}

lazy_static! {
pub static ref STDIN: Mutex<String> = Mutex::new(String::new());
pub static ref ECHO: Mutex<bool> = Mutex::new(true);
pub static ref RAW: Mutex<bool> = Mutex::new(false);
}

#[cfg(feature="vga")]
pub fn has_cursor() -> bool {
true
}

#[cfg(feature="serial")]
pub fn has_cursor() -> bool {
false
}

#[cfg(feature="vga")]
pub fn clear_row() {
kernel::vga::clear_row();
}

#[cfg(feature="serial")]
pub fn clear_row() {
print!("\x1b[2K\r");
}

#[cfg(feature="vga")]
#[macro_export]
macro_rules! print {
Expand All @@ -32,10 +74,9 @@ macro_rules! print {
macro_rules! log {
($($arg:tt)*) => ({
let uptime = $crate::kernel::clock::uptime();
let (fg, bg) = $crate::kernel::vga::color();
$crate::kernel::vga::set_color($crate::kernel::vga::Color::Green, bg);
$crate::kernel::vga::print_fmt(format_args!("[{:.6}] ", uptime));
$crate::kernel::vga::set_color(fg, bg);
let csi_color = $crate::kernel::console::color("LightGreen");
let csi_reset = $crate::kernel::console::color("Reset");
$crate::kernel::vga::print_fmt(format_args!("{}[{:.6}]{} ", csi_color, uptime, csi_reset));
$crate::kernel::vga::print_fmt(format_args!($($arg)*));
});
}
Expand All @@ -45,7 +86,9 @@ macro_rules! log {
macro_rules! log {
($($arg:tt)*) => ({
let uptime = $crate::kernel::clock::uptime();
$crate::kernel::serial::print_fmt(format_args!("[{:.6}] ", uptime));
let csi_color = $crate::kernel::console::color("LightGreen");
let csi_reset = $crate::kernel::console::color("Reset");
$crate::kernel::serial::print_fmt(format_args!("{}[{:.6}]{} ", csi_color, uptime, csi_reset));
$crate::kernel::serial::print_fmt(format_args!($($arg)*));
});
}
Expand Down Expand Up @@ -78,18 +121,10 @@ pub fn is_raw_enabled() -> bool {
*RAW.lock()
}

pub fn key_handle(key: DecodedKey) {
let c = match key {
DecodedKey::Unicode(c) => c,
DecodedKey::RawKey(KeyCode::ArrowLeft) => '←', // U+2190
DecodedKey::RawKey(KeyCode::ArrowUp) => '↑', // U+2191
DecodedKey::RawKey(KeyCode::ArrowRight) => '→', // U+2192
DecodedKey::RawKey(KeyCode::ArrowDown) => '↓', // U+2193
DecodedKey::RawKey(_) => '\0'
};
pub fn key_handle(key: char) {
let mut stdin = STDIN.lock();

if c == '\x08' && !is_raw_enabled() {
if key == '\x08' && !is_raw_enabled() {
// Avoid printing more backspaces than chars inserted into STDIN.
// Also, the VGA driver support only ASCII so unicode chars will
// be displayed with one square for each codepoint.
Expand All @@ -104,9 +139,9 @@ pub fn key_handle(key: DecodedKey) {
} else {
// TODO: Replace non-ascii chars by ascii square symbol to keep length
// at 1 instead of being variable?
stdin.push(c);
stdin.push(key);
if is_echo_enabled() {
print!("{}", c);
print!("{}", key);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/kernel/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub fn init() {

if let Some(extended_function_info) = cpuid.get_extended_function_info() {
if let Some(processor_brand_string) = extended_function_info.processor_brand_string() {
log!("CPU {}\n", processor_brand_string);
log!("CPU {}\n", processor_brand_string.trim());
}
}

Expand Down
12 changes: 10 additions & 2 deletions src/kernel/keyboard.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::kernel;
use lazy_static::lazy_static;
use pc_keyboard::{Keyboard, ScancodeSet1, HandleControl, layouts};
use pc_keyboard::{Keyboard, ScancodeSet1, HandleControl, layouts, KeyCode, DecodedKey};
use spin::Mutex;
use x86_64::instructions::port::Port;

Expand Down Expand Up @@ -84,7 +84,15 @@ fn interrupt_handler() {
let scancode = read_scancode();
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
if let Some(key) = keyboard.process_keyevent(key_event) {
kernel::console::key_handle(key);
let c = match key {
DecodedKey::Unicode(c) => c,
DecodedKey::RawKey(KeyCode::ArrowLeft) => '←', // U+2190
DecodedKey::RawKey(KeyCode::ArrowUp) => '↑', // U+2191
DecodedKey::RawKey(KeyCode::ArrowRight) => '→', // U+2192
DecodedKey::RawKey(KeyCode::ArrowDown) => '↓', // U+2193
DecodedKey::RawKey(_) => '\0'
};
kernel::console::key_handle(c);
}
}
}
57 changes: 49 additions & 8 deletions src/kernel/serial.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,58 @@
use crate::kernel;
use lazy_static::lazy_static;
use spin::Mutex;
use uart_16550::SerialPort;
use core::fmt;
use core::fmt::Write;

lazy_static! {
pub static ref SERIAL1: Mutex<SerialPort> = {
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
serial_port.init();
Mutex::new(serial_port)
};
pub static ref SERIAL: Mutex<Serial> = Mutex::new(Serial::new(0x3F8));
}

pub struct Serial {
pub port: SerialPort
}

impl Serial {
fn new(addr: u16) -> Self {
let mut port = unsafe { SerialPort::new(addr) };
port.init();
Self { port }
}

fn write_string(&mut self, s: &str) {
for byte in s.bytes() {
self.write_byte(byte)
}
}

pub fn write_byte(&mut self, byte: u8) {
self.port.send(byte);
}
}

impl fmt::Write for Serial {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.write_string(s);
Ok(())
}
}

#[doc(hidden)]
pub fn print_fmt(args: ::core::fmt::Arguments) {
use core::fmt::Write;
SERIAL1.lock().write_fmt(args).expect("Could not print to serial");
pub fn print_fmt(args: fmt::Arguments) {
SERIAL.lock().write_fmt(args).expect("Could not print to serial");
}

pub fn init() {
kernel::idt::set_irq_handler(4, interrupt_handler);
}

fn interrupt_handler() {
let b = SERIAL.lock().port.receive();
let c = match b as char {
'\r' => '\n',
'\x7F' => '\x08', // Delete => Backspace
c => c,
};
kernel::console::key_handle(c);
}
Loading

0 comments on commit 5828c7f

Please sign in to comment.