Skip to content

Commit c87c266

Browse files
committed
Can list and change video modes.
1 parent 2439089 commit c87c266

File tree

5 files changed

+116
-7
lines changed

5 files changed

+116
-7
lines changed

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ panic = "abort"
4141
panic = "abort"
4242

4343
[dependencies]
44-
neotron-common-bios = "0.11"
44+
neotron-common-bios = { git = "https://github.com/neotron-compute/neotron-common-bios", branch = "make-things-inline" }
4545
pc-keyboard = "0.7"
4646
r0 = "1.0"
4747
heapless = "0.7"

src/commands/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub static OS_MENU: menu::Menu<Ctx> = menu::Menu {
2828
&ram::LOAD_ITEM,
2929
&fs::LOAD_ITEM,
3030
&screen::CLS_ITEM,
31+
&screen::MODE_ITEM,
3132
&input::KBTEST_ITEM,
3233
&hardware::SHUTDOWN_ITEM,
3334
&sound::MIXER_ITEM,

src/commands/screen.rs

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,116 @@
11
//! Screen-related commands for Neotron OS
22
3-
use crate::{osprint, Ctx};
3+
use crate::{osprint, osprintln, Ctx};
4+
use neotron_common_bios::{
5+
video::{Format, Mode},
6+
ApiResult,
7+
};
48

59
pub static CLS_ITEM: menu::Item<Ctx> = menu::Item {
610
item_type: menu::ItemType::Callback {
7-
function: cls,
11+
function: cls_cmd,
812
parameters: &[],
913
},
1014
command: "cls",
1115
help: Some("Clear the screen"),
1216
};
1317

18+
pub static MODE_ITEM: menu::Item<Ctx> = menu::Item {
19+
item_type: menu::ItemType::Callback {
20+
function: mode_cmd,
21+
parameters: &[menu::Parameter::Optional {
22+
parameter_name: "new_mode",
23+
help: Some("The new text mode to change to"),
24+
}],
25+
},
26+
command: "mode",
27+
help: Some("List possible video modes"),
28+
};
29+
1430
/// Called when the "cls" command is executed.
15-
fn cls(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) {
31+
fn cls_cmd(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) {
1632
// Reset SGR, go home, clear screen,
17-
let _ = osprint!("\u{001b}[0m\u{001b}[1;1H\u{001b}[2J");
33+
osprint!("\u{001b}[0m\u{001b}[1;1H\u{001b}[2J");
1834
}
35+
36+
/// Called when the "mode" command is executed
37+
fn mode_cmd(_menu: &menu::Menu<Ctx>, item: &menu::Item<Ctx>, args: &[&str], _ctx: &mut Ctx) {
38+
if let Some(new_mode) = menu::argument_finder(item, args, "new_mode").unwrap() {
39+
let Ok(mode_num) = new_mode.parse::<u8>() else {
40+
osprintln!("Invalid integer {:?}", new_mode);
41+
return;
42+
};
43+
let Some(mode) = Mode::try_from_u8(mode_num) else {
44+
osprintln!("Invalid mode {:?}", new_mode);
45+
return;
46+
};
47+
let has_vga = {
48+
let mut guard = crate::VGA_CONSOLE.lock();
49+
guard.as_mut().is_some()
50+
};
51+
if !has_vga {
52+
osprintln!("No VGA console.");
53+
return;
54+
}
55+
let api = crate::API.get();
56+
match mode.format() {
57+
Format::Text8x16 => {}
58+
Format::Text8x8 => {}
59+
_ => {
60+
osprintln!("Not a text mode?");
61+
return;
62+
}
63+
}
64+
match (api.video_set_mode)(mode) {
65+
ApiResult::Ok(_) => {
66+
let mut guard = crate::VGA_CONSOLE.lock();
67+
if let Some(console) = guard.as_mut() {
68+
console.change_mode(mode);
69+
}
70+
osprintln!("Now in mode {}", mode.as_u8());
71+
}
72+
ApiResult::Err(e) => {
73+
osprintln!("Failed to change mode: {:?}", e);
74+
}
75+
}
76+
} else {
77+
print_modes();
78+
}
79+
}
80+
81+
/// Print out all supported video modes
82+
fn print_modes() {
83+
let api = crate::API.get();
84+
let current_mode = (api.video_get_mode)();
85+
let mut any_mode = false;
86+
for mode_no in 0..255 {
87+
// Note (unsafe): we'll test if it's right before we try and use it
88+
let Some(m) = Mode::try_from_u8(mode_no) else {
89+
continue;
90+
};
91+
let is_supported = (api.video_is_valid_mode)(m);
92+
if is_supported {
93+
any_mode = true;
94+
let is_current = if current_mode == m { "*" } else { " " };
95+
let text_rows = m.text_height();
96+
let text_cols = m.text_width();
97+
let f = m.format();
98+
let width = m.horizontal_pixels();
99+
let height = m.vertical_lines();
100+
let hz = m.frame_rate_hz();
101+
if let (Some(text_rows), Some(text_cols)) = (text_rows, text_cols) {
102+
// It's a text mode
103+
osprintln!("{mode_no:3}{is_current}: {width} x {height} @ {hz} Hz {f} ({text_cols} x {text_rows})");
104+
} else {
105+
// It's a framebuffer mode
106+
let f = m.format();
107+
osprintln!("{mode_no:3}{is_current}: {width} x {height} @ {hz} Hz {f}");
108+
}
109+
}
110+
}
111+
if !any_mode {
112+
osprintln!("No valid modes found");
113+
}
114+
}
115+
116+
// End of file

src/vgaconsole.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,17 @@ impl VgaConsole {
7171
}
7272
}
7373

74+
/// Change the video mode
75+
///
76+
/// Non text modes are ignored.
77+
pub fn change_mode(&mut self, mode: neotron_common_bios::video::Mode) {
78+
if let (Some(height), Some(width)) = (mode.text_height(), mode.text_width()) {
79+
self.inner.height = height as isize;
80+
self.inner.width = width as isize;
81+
self.clear();
82+
}
83+
}
84+
7485
/// Clear the screen.
7586
///
7687
/// Every character on the screen is replaced with an space (U+0020).

0 commit comments

Comments
 (0)