VTerm| VTerm device
This commit is contained in:
parent
8e66a677fa
commit
b1eaea239e
|
@ -31,7 +31,7 @@ pub fn init() {
|
||||||
Capabilities::empty(),
|
Capabilities::empty(),
|
||||||
High,
|
High,
|
||||||
"".to_string(),
|
"".to_string(),
|
||||||
StdIO::new(crate::stdio::Device::VTerm),
|
StdIO::new("null".to_string()),
|
||||||
);
|
);
|
||||||
scheduler.add_process(process_0);
|
scheduler.add_process(process_0);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod dev_null;
|
pub mod dev_null;
|
||||||
pub mod dev_unicode;
|
pub mod dev_unicode;
|
||||||
|
|
||||||
pub mod dev_zero;
|
pub mod dev_zero;
|
||||||
|
|
||||||
pub use kernel::device_interface::character::CharacterDevice;
|
pub use kernel::device_interface::character::CharacterDevice;
|
||||||
|
|
245
ableos/src/devices/dev_vterm.rs
Normal file
245
ableos/src/devices/dev_vterm.rs
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
// ! A virtual terminal device.
|
||||||
|
|
||||||
|
use kernel::device_interface::character::CharacterDevice;
|
||||||
|
|
||||||
|
use core::ops::Not;
|
||||||
|
use shadeable::pixel_format::Rgba64;
|
||||||
|
pub const VTERM_HEIGHT: u32 = 40;
|
||||||
|
pub const VTERM_WIDTH: u32 = 100;
|
||||||
|
/// Fg and bg colors for vterm
|
||||||
|
pub type ColorCharacter = (Rgba64, Rgba64);
|
||||||
|
/// A vterm representation of a character
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct VtermCharacter {
|
||||||
|
pub character: char,
|
||||||
|
//
|
||||||
|
pub style: Style,
|
||||||
|
//
|
||||||
|
pub char_color: ColorCharacter,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Copy)]
|
||||||
|
|
||||||
|
pub struct Style(pub u8);
|
||||||
|
impl Style {
|
||||||
|
pub fn bold(&self) -> bool {
|
||||||
|
(self.0 & 0x01) > 0
|
||||||
|
}
|
||||||
|
pub fn underlined(&self) -> bool {
|
||||||
|
(self.0 & 0x02) > 0
|
||||||
|
}
|
||||||
|
pub fn italic(&self) -> bool {
|
||||||
|
(self.0 & 0x04) > 0
|
||||||
|
}
|
||||||
|
pub fn blinking(&self) -> bool {
|
||||||
|
(self.0 & 0x08) > 0
|
||||||
|
}
|
||||||
|
pub fn reversed(&self) -> bool {
|
||||||
|
(self.0 & 0x10) > 0
|
||||||
|
}
|
||||||
|
pub fn struck(&self) -> bool {
|
||||||
|
(self.0 & 0x20) > 0
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn set_bold(mut self, v: bool) -> Self {
|
||||||
|
if v {
|
||||||
|
self.0 |= 0x01;
|
||||||
|
} else {
|
||||||
|
self.0 &= 0x01u8.not();
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn set_underlined(mut self, v: bool) -> Self {
|
||||||
|
if v {
|
||||||
|
self.0 |= 0x02;
|
||||||
|
} else {
|
||||||
|
self.0 &= 0x02u8.not();
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn set_italic(mut self, v: bool) -> Self {
|
||||||
|
if v {
|
||||||
|
self.0 |= 0x04;
|
||||||
|
} else {
|
||||||
|
self.0 &= 0x04u8.not();
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn set_blinking(mut self, v: bool) -> Self {
|
||||||
|
if v {
|
||||||
|
self.0 |= 0x08;
|
||||||
|
} else {
|
||||||
|
self.0 &= 0x08u8.not();
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn set_reversed(mut self, v: bool) -> Self {
|
||||||
|
if v {
|
||||||
|
self.0 |= 0x10;
|
||||||
|
} else {
|
||||||
|
self.0 &= 0x10u8.not();
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn set_struck(mut self, v: bool) -> Self {
|
||||||
|
if v {
|
||||||
|
self.0 |= 0x20;
|
||||||
|
} else {
|
||||||
|
self.0 &= 0x20u8.not();
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VTerm {
|
||||||
|
iid: u32,
|
||||||
|
pub characters: [[VtermCharacter; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize],
|
||||||
|
/// The internal representation of the vterm
|
||||||
|
style: Style,
|
||||||
|
/// The cursor position in layout x,y
|
||||||
|
cursor_position: (u32, u32),
|
||||||
|
pub cursor_visible: bool,
|
||||||
|
key_buff: Vec<char>,
|
||||||
|
}
|
||||||
|
impl Default for VTerm {
|
||||||
|
fn default() -> Self {
|
||||||
|
VTerm {
|
||||||
|
iid: 0,
|
||||||
|
characters: [[VtermCharacter {
|
||||||
|
character: 0x00 as char,
|
||||||
|
char_color: (0xff_ff_ff_ff, 0x00_00_00_00),
|
||||||
|
style: Style::default(),
|
||||||
|
}; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize],
|
||||||
|
cursor_position: (0, 0),
|
||||||
|
cursor_visible: true,
|
||||||
|
style: Style::default(),
|
||||||
|
key_buff: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The primitive interface for a vterm
|
||||||
|
impl VTerm {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut vterm = VTerm::default();
|
||||||
|
let mut vtc = VIRTUAL_TERMINAL_COUNT.load(Ordering::Relaxed);
|
||||||
|
vterm.iid = vtc;
|
||||||
|
vtc += 1;
|
||||||
|
VIRTUAL_TERMINAL_COUNT.store(vtc, Ordering::Relaxed);
|
||||||
|
|
||||||
|
vterm
|
||||||
|
}
|
||||||
|
/// Set the vterm cursor to the given position
|
||||||
|
pub fn set_cursor_position(&mut self, x: u32, y: u32) {
|
||||||
|
if x > VTERM_WIDTH {
|
||||||
|
self.cursor_position.0 = VTERM_WIDTH;
|
||||||
|
error!("Cursor x position out of bounds");
|
||||||
|
} else {
|
||||||
|
self.cursor_position.0 = x;
|
||||||
|
}
|
||||||
|
if y > VTERM_HEIGHT {
|
||||||
|
error!("Cursor y position out of bounds");
|
||||||
|
self.cursor_position.1 = VTERM_HEIGHT;
|
||||||
|
} else {
|
||||||
|
self.cursor_position.1 = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Set the vterm style
|
||||||
|
pub fn set_vterm_style(&mut self, style: Style) {
|
||||||
|
self.style = style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharacterDevice for VTerm {
|
||||||
|
fn can_read(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_write(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_char(&mut self) -> Option<char> {
|
||||||
|
if let Some(c) = self.key_buff.pop() {
|
||||||
|
return Some(c);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_char(&mut self, c: char) -> bool {
|
||||||
|
match c {
|
||||||
|
'\n' => {
|
||||||
|
self.cursor_position.1 += 1;
|
||||||
|
self.cursor_position.0 = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
'\r' => {
|
||||||
|
self.cursor_position.0 = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
'\t' => {
|
||||||
|
self.cursor_position.0 += 4;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
'\x08' => {
|
||||||
|
self.cursor_position.0 -= 1;
|
||||||
|
self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize]
|
||||||
|
.character = ' ';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/// This is a form feed, which is used to clear the screen
|
||||||
|
'\x0c' => {
|
||||||
|
self.characters = [[VtermCharacter {
|
||||||
|
character: ' ',
|
||||||
|
char_color: (0xff_ff_ff_ff, 0x00_00_00_00),
|
||||||
|
style: Style::default(),
|
||||||
|
}; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize]
|
||||||
|
.character = c;
|
||||||
|
self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize]
|
||||||
|
.char_color = (0xff_ff_ff_ff, 0x00_00_00_00);
|
||||||
|
self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize]
|
||||||
|
.style = self.style;
|
||||||
|
|
||||||
|
if self.cursor_position.0 < VTERM_WIDTH {
|
||||||
|
self.cursor_position.0 += 1;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
self.cursor_position.0 = 0;
|
||||||
|
self.cursor_position.1 += 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.characters = [[VtermCharacter {
|
||||||
|
character: ' ',
|
||||||
|
char_color: (0xff_ff_ff_ff, 0x00_00_00_00),
|
||||||
|
style: Style::default(),
|
||||||
|
}; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize];
|
||||||
|
self.cursor_position = (0, 0);
|
||||||
|
self.cursor_visible = true;
|
||||||
|
self.style = Style::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
pub static ref VIRTUAL_TERMINAL_COUNT: AtomicU32 = AtomicU32::new(0);
|
||||||
|
}
|
||||||
|
use core::sync::atomic::AtomicU32;
|
||||||
|
use core::sync::atomic::Ordering;
|
|
@ -3,13 +3,14 @@ pub mod id;
|
||||||
pub mod pci_inner;
|
pub mod pci_inner;
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
mod dev_vterm;
|
||||||
|
use crate::devices::dev_vterm::VTerm;
|
||||||
use kernel::device_interface::character::CharacterDevice;
|
use kernel::device_interface::character::CharacterDevice;
|
||||||
|
|
||||||
// FIXME: This is a hack to hold a device.
|
// FIXME: This is a hack to hold a device.
|
||||||
// #[derive(Debug)]
|
// #[derive(Debug)]
|
||||||
pub enum Device {
|
pub enum Device {
|
||||||
Character(Box<dyn CharacterDevice>),
|
Character(Box<dyn CharacterDevice>),
|
||||||
|
Vterm(VTerm),
|
||||||
}
|
}
|
||||||
unsafe impl Sync for Device {}
|
unsafe impl Sync for Device {}
|
||||||
unsafe impl Send for Device {}
|
unsafe impl Send for Device {}
|
||||||
|
@ -31,6 +32,7 @@ impl DeviceTable {
|
||||||
next_read_char: 0x00 as char,
|
next_read_char: 0x00 as char,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
table.insert("kvterm".to_string(), Vterm(VTerm::new()));
|
||||||
DeviceTable { devices: table }
|
DeviceTable { devices: table }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
use acpi::AcpiTables;
|
use acpi::AcpiTables;
|
||||||
|
use kernel::device_interface::character::CharacterDevice;
|
||||||
|
|
||||||
|
use crate::devices::DEVICE_TABLE;
|
||||||
use crate::rhai_shell::shell;
|
use crate::rhai_shell::shell;
|
||||||
|
|
||||||
use crate::stdio::StdIO;
|
use crate::stdio::StdIO;
|
||||||
|
|
||||||
|
use crate::devices::Device::Vterm;
|
||||||
|
|
||||||
/// Experimental scratchpad for testing.
|
/// Experimental scratchpad for testing.
|
||||||
pub fn scratchpad() {
|
pub fn scratchpad() {
|
||||||
let mut stdio = StdIO::new(crate::stdio::Device::Serial);
|
|
||||||
stdio.write();
|
|
||||||
|
|
||||||
shell();
|
shell();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,42 @@
|
||||||
use core::fmt::Arguments;
|
use {
|
||||||
use core::fmt::Error;
|
crate::{
|
||||||
use core::fmt::Write;
|
devices::Device::{Character, Vterm},
|
||||||
|
kprintln,
|
||||||
|
},
|
||||||
|
core::fmt::{Arguments, Error, Write},
|
||||||
|
kernel::device_interface::character::CharacterDevice,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::kprintln;
|
#[derive(Debug, Clone)]
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum Device {
|
|
||||||
VTerm,
|
|
||||||
Serial,
|
|
||||||
}
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct StdIO {
|
pub struct StdIO {
|
||||||
device: Device,
|
device: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdIO {
|
impl StdIO {
|
||||||
pub fn new(device: Device) -> StdIO {
|
pub fn new(device: String) -> StdIO {
|
||||||
StdIO { device }
|
StdIO { device }
|
||||||
}
|
}
|
||||||
pub fn write(&mut self) {
|
pub fn write(&mut self, args: Arguments) -> Result<(), Error> {
|
||||||
match self.device {
|
use crate::devices::DEVICE_TABLE;
|
||||||
Device::VTerm => {
|
let mut dt = DEVICE_TABLE.lock();
|
||||||
println!("Hello, world!");
|
let key_device = dt.devices.get_mut(&self.device).unwrap();
|
||||||
|
|
||||||
|
match key_device {
|
||||||
|
Character(dev) => {
|
||||||
|
let mut buf = String::new();
|
||||||
|
write!(buf, "{}", args).unwrap();
|
||||||
|
for c in buf.chars() {
|
||||||
|
dev.write_char(c);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
Device::Serial => {
|
Vterm(vterm) => {
|
||||||
serial_println!("Hello, world!");
|
let mut buf = String::new();
|
||||||
|
write!(buf, "{}", args).unwrap();
|
||||||
|
for c in buf.chars() {
|
||||||
|
vterm.write_char(c);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue