Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VgaFont device #653

Merged
merged 10 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,8 @@ You can also set the `TZ` environment variable to use your preferred timezone:
Add `env TZ 7200` to `/ini/boot.sh` before `shell` to save the timezone:

> read /ini/boot.sh
vga set font /ini/fonts/zap-light-8x16.psf
shell /ini/palettes/gruvbox-dark.sh
read /ini/fonts/zap-light-8x16.psf => /dev/vga/font
read /ini/banner.txt
user login
env TZ 7200
Expand Down
2 changes: 1 addition & 1 deletion dsk/ini/boot.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
vga set font /ini/fonts/zap-light-8x16.psf
shell /ini/palettes/gruvbox-dark.sh
read /ini/fonts/zap-light-8x16.psf => /dev/vga/font
read /ini/banner.txt
user login
shell
57 changes: 31 additions & 26 deletions src/api/font.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use alloc::vec::Vec;
use core::convert::TryFrom;

#[derive(Clone)]
pub struct Font {
Expand All @@ -7,39 +8,43 @@ pub struct Font {
pub data: Vec<u8>,
}

// http://www.fifi.org/doc/console-tools-dev/file-formats/psf
pub fn from_bytes(buf: &[u8]) -> Result<Font, ()> {
// Header
if buf.len() < 4 || buf[0] != 0x36 || buf[1] != 0x04 {
return Err(());
}
let mode = buf[2];
let height = buf[3];
let size = match mode {
0 | 2 => 256,
1 | 3 => 512,
_ => return Err(()),
};

// Data
let n = (4 + size * height as u16) as usize;
if buf.len() < n {
return Err(());
}
let data = buf[4..n].to_vec();
impl TryFrom<&[u8]> for Font {
type Error = ();

fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
// See: http://www.fifi.org/doc/console-tools-dev/file-formats/psf
// Header
if buf.len() < 4 || buf[0] != 0x36 || buf[1] != 0x04 {
return Err(());
}
let mode = buf[2];
let height = buf[3];
let size = match mode {
0 | 2 => 256,
1 | 3 => 512,
_ => return Err(()),
};

// TODO: Unicode Table
// Data
let n = (4 + size * height as u16) as usize;
if buf.len() < n {
return Err(());
}
let data = buf[4..n].to_vec();

Ok(Font { height, size, data })
// TODO: Unicode Table

Ok(Font { height, size, data })
}
}

#[test_case]
fn parse_psf_font() {
assert!(from_bytes(include_bytes!("../../dsk/ini/boot.sh")).is_err());
let buf = include_bytes!("../../dsk/ini/boot.sh");
assert!(Font::try_from(&buf[..]).is_err());

let font = from_bytes(
include_bytes!("../../dsk/ini/fonts/zap-light-8x16.psf")
).unwrap();
let buf = include_bytes!("../../dsk/ini/fonts/zap-light-8x16.psf");
let font = Font::try_from(&buf[..]).unwrap();
assert_eq!(font.height, 16);
assert_eq!(font.size, 256);
assert_eq!(font.data.len(), 256 * 16);
Expand Down
31 changes: 13 additions & 18 deletions src/api/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ pub fn is_file(path: &str) -> bool {
}
}

pub fn is_device(path: &str) -> bool {
if let Some(info) = syscall::info(path) {
info.is_device()
} else {
false
}
}

pub fn delete(path: &str) -> Result<(), ()> {
syscall::delete(path)
}
Expand Down Expand Up @@ -144,6 +152,7 @@ fn device_type(name: &str) -> Result<DeviceType, ()> {
"rtc" => Ok(DeviceType::RTC),
"tcp" => Ok(DeviceType::TcpSocket),
"udp" => Ok(DeviceType::UdpSocket),
"font" => Ok(DeviceType::VgaFont),
"ata" => Ok(DeviceType::Drive),
_ => Err(()),
}
Expand Down Expand Up @@ -173,14 +182,14 @@ pub fn read_to_string(path: &str) -> Result<String, ()> {

pub fn read_to_bytes(path: &str) -> Result<Vec<u8>, ()> {
if let Some(info) = syscall::info(path) {
let f = if info.is_device() {
let res = if info.is_device() {
open_device(path)
} else if info.is_dir() {
open_dir(path)
} else {
open_file(path)
};
if let Some(handle) = f {
if let Some(handle) = res {
let n = info.size() as usize;
let mut buf = vec![0; n];
if let Some(bytes) = syscall::read(handle, &mut buf) {
Expand All @@ -194,22 +203,8 @@ pub fn read_to_bytes(path: &str) -> Result<Vec<u8>, ()> {
}

pub fn write(path: &str, buf: &[u8]) -> Result<usize, ()> {
if let Some(handle) = create_file(path) {
if let Some(bytes) = syscall::write(handle, buf) {
syscall::close(handle);
return Ok(bytes);
}
}
Err(())
}

pub fn append(path: &str, buf: &[u8]) -> Result<usize, ()> {
let res = if let Some(info) = syscall::info(path) {
if info.is_device() {
open_device(path)
} else {
append_file(path)
}
let res = if is_device(path) {
open_device(path)
} else {
create_file(path)
};
Expand Down
31 changes: 20 additions & 11 deletions src/sys/fs/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::sys::console::Console;
use crate::sys::net::socket::tcp::TcpSocket;
use crate::sys::net::socket::udp::UdpSocket;
use crate::sys::rng::Random;
use crate::sys::vga::VgaFont;

use alloc::vec;
use alloc::vec::Vec;
Expand All @@ -29,24 +30,26 @@ pub enum DeviceType {
TcpSocket = 7,
UdpSocket = 8,
Drive = 9,
VgaFont = 10,
}

impl TryFrom<&[u8]> for DeviceType {
type Error = ();

fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
match buf.first().ok_or(())? {
0 => Ok(DeviceType::Null),
1 => Ok(DeviceType::File),
2 => Ok(DeviceType::Console),
3 => Ok(DeviceType::Random),
4 => Ok(DeviceType::Uptime),
5 => Ok(DeviceType::Realtime),
6 => Ok(DeviceType::RTC),
7 => Ok(DeviceType::TcpSocket),
8 => Ok(DeviceType::UdpSocket),
9 => Ok(DeviceType::Drive),
_ => Err(()),
0 => Ok(DeviceType::Null),
1 => Ok(DeviceType::File),
2 => Ok(DeviceType::Console),
3 => Ok(DeviceType::Random),
4 => Ok(DeviceType::Uptime),
5 => Ok(DeviceType::Realtime),
6 => Ok(DeviceType::RTC),
7 => Ok(DeviceType::TcpSocket),
8 => Ok(DeviceType::UdpSocket),
9 => Ok(DeviceType::Drive),
10 => Ok(DeviceType::VgaFont),
_ => Err(()),
}
}
}
Expand Down Expand Up @@ -83,6 +86,7 @@ pub enum Device {
RTC(RTC),
TcpSocket(TcpSocket),
UdpSocket(UdpSocket),
VgaFont(VgaFont),
Drive(Drive),
}

Expand All @@ -100,6 +104,7 @@ impl TryFrom<&[u8]> for Device {
DeviceType::RTC => Ok(Device::RTC(RTC::new())),
DeviceType::TcpSocket => Ok(Device::TcpSocket(TcpSocket::new())),
DeviceType::UdpSocket => Ok(Device::UdpSocket(UdpSocket::new())),
DeviceType::VgaFont => Ok(Device::VgaFont(VgaFont::new())),
DeviceType::Drive if buf.len() > 2 => {
let bus = buf[1];
let dsk = buf[2];
Expand Down Expand Up @@ -158,6 +163,7 @@ impl FileIO for Device {
Device::RTC(io) => io.read(buf),
Device::TcpSocket(io) => io.read(buf),
Device::UdpSocket(io) => io.read(buf),
Device::VgaFont(io) => io.read(buf),
Device::Drive(io) => io.read(buf),
}
}
Expand All @@ -173,6 +179,7 @@ impl FileIO for Device {
Device::RTC(io) => io.write(buf),
Device::TcpSocket(io) => io.write(buf),
Device::UdpSocket(io) => io.write(buf),
Device::VgaFont(io) => io.write(buf),
Device::Drive(io) => io.write(buf),
}
}
Expand All @@ -188,6 +195,7 @@ impl FileIO for Device {
Device::RTC(io) => io.close(),
Device::TcpSocket(io) => io.close(),
Device::UdpSocket(io) => io.close(),
Device::VgaFont(io) => io.close(),
Device::Drive(io) => io.close(),
}
}
Expand All @@ -203,6 +211,7 @@ impl FileIO for Device {
Device::RTC(io) => io.poll(event),
Device::TcpSocket(io) => io.poll(event),
Device::UdpSocket(io) => io.poll(event),
Device::VgaFont(io) => io.poll(event),
Device::Drive(io) => io.poll(event),
}
}
Expand Down
36 changes: 36 additions & 0 deletions src/sys/vga.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::api::font::Font;
use crate::api::fs::{FileIO, IO};
use crate::api::vga::color;
use crate::api::vga::{Color, Palette};
use crate::sys;

use alloc::string::String;
use bit_field::BitField;
use core::convert::TryFrom;
use core::cmp;
use core::fmt;
use core::fmt::Write;
Expand Down Expand Up @@ -461,6 +463,39 @@ impl fmt::Write for Writer {
}
}

#[derive(Debug, Clone)]
pub struct VgaFont;

impl VgaFont {
pub fn new() -> Self {
Self
}
}

impl FileIO for VgaFont {
fn read(&mut self, _buf: &mut [u8]) -> Result<usize, ()> {
Err(()) // TODO
}

fn write(&mut self, buf: &[u8]) -> Result<usize, ()> {
if let Ok(font) = Font::try_from(buf) {
set_font(&font);
Ok(buf.len()) // TODO: Use font.data.len() ?
} else {
Err(())
}
}

fn close(&mut self) {}

fn poll(&mut self, event: IO) -> bool {
match event {
IO::Read => false, // TODO
IO::Write => true,
}
}
}

#[doc(hidden)]
pub fn print_fmt(args: fmt::Arguments) {
interrupts::without_interrupts(||
Expand Down Expand Up @@ -489,6 +524,7 @@ pub fn is_printable(c: u8) -> bool {
matches!(c, 0x20..=0x7E | 0x08 | 0x0A | 0x0D | 0x7F..=0xFF)
}

// TODO: Remove this
pub fn set_font(font: &Font) {
interrupts::without_interrupts(||
WRITER.lock().set_font(font)
Expand Down
2 changes: 2 additions & 0 deletions src/usr/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub fn copy_files(verbose: bool) {
create_dir("/dev/ata/1", verbose);
create_dir("/dev/clk", verbose); // Clock
create_dir("/dev/net", verbose); // Network
create_dir("/dev/vga", verbose);

create_dev("/dev/ata/0/0", "ata-0-0", verbose);
create_dev("/dev/ata/0/1", "ata-0-1", verbose);
Expand All @@ -53,6 +54,7 @@ pub fn copy_files(verbose: bool) {
create_dev("/dev/console", "console", verbose);
create_dev("/dev/net/tcp", "tcp", verbose);
create_dev("/dev/net/udp", "udp", verbose);
create_dev("/dev/vga/font", "font", verbose);

copy_file!("/ini/banner.txt", verbose);
copy_file!("/ini/boot.sh", verbose);
Expand Down
4 changes: 2 additions & 2 deletions src/usr/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
}
} else if let Some(info) = syscall::info(path) {
if info.is_file() {
if let Ok(contents) = api::fs::read_to_string(path) {
print!("{}", contents);
if let Ok(buf) = api::fs::read_to_bytes(path) {
syscall::write(1, &buf);
Ok(())
} else {
error!("Could not read '{}'", path);
Expand Down
10 changes: 7 additions & 3 deletions src/usr/vga.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::api::console::Style;
use crate::api::fs;
use crate::api::process::ExitCode;
use crate::api::font::Font;
use crate::api::vga::palette;
use crate::{api, sys};
use crate::sys;

// TODO: Remove this command when everything can be done from userspace
use core::convert::TryFrom;

// TODO: Remove this command in the next version of MOROS
pub fn main(args: &[&str]) -> Result<(), ExitCode> {
if args.len() == 1 {
help();
Expand All @@ -18,8 +21,9 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
}
"set" => {
if args.len() == 4 && args[2] == "font" {
warning!("Use VGA font device");
if let Ok(buf) = fs::read_to_bytes(args[3]) {
if let Ok(font) = api::font::from_bytes(&buf) {
if let Ok(font) = Font::try_from(buf.as_slice()) {
sys::vga::set_font(&font);
Ok(())
} else {
Expand Down
2 changes: 1 addition & 1 deletion www/manual.html
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ <h2>Time</h2>
<p>Add <code>env TZ 7200</code> to <code>/ini/boot.sh</code> before <code>shell</code> to save the timezone:</p>

<pre><code>&gt; read /ini/boot.sh
vga set font /ini/fonts/zap-light-8x16.psf
shell /ini/palettes/gruvbox-dark.sh
read /ini/fonts/zap-light-8x16.psf =&gt; /dev/vga/font
read /ini/banner.txt
user login
env TZ 7200
Expand Down
Loading