Skip to content

Commit 92f2dbc

Browse files
authored
Merge pull request #80 from Neotron-Compute/add-type-command
Add type and exec commands
2 parents f2d069a + 56faf4e commit 92f2dbc

File tree

20 files changed

+511
-156
lines changed

20 files changed

+511
-156
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
## Unreleased changes
44

5-
* None
5+
* Add `i2c` command.
6+
* Support printing `\t`, with 8 character tab-stops
7+
* Add `type` command to print files
8+
* Add `exec` command to execute scripts containing commands
69

710
## v0.6.0 (2023-10-08, [Github Release](https://github.com/neotron-compute/neotron-os/releases/tag/v0.6.0))
811

Cargo.lock

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

build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,5 @@ fn main() {
3131
println!("cargo:rustc-link-lib=dylib=msvcrt");
3232
}
3333
}
34+
35+
// End of file

src/bin/flash0002.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@
1414
#[link_section = ".entry_point"]
1515
#[used]
1616
pub static ENTRY_POINT_ADDR: extern "C" fn(&neotron_common_bios::Api) -> ! = neotron_os::os_main;
17+
18+
// End of file

src/bin/flash0802.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@
1414
#[link_section = ".entry_point"]
1515
#[used]
1616
pub static ENTRY_POINT_ADDR: extern "C" fn(&neotron_common_bios::Api) -> ! = neotron_os::os_main;
17+
18+
// End of file

src/bin/flash1002.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@
1414
#[link_section = ".entry_point"]
1515
#[used]
1616
pub static ENTRY_POINT_ADDR: extern "C" fn(&neotron_common_bios::Api) -> ! = neotron_os::os_main;
17+
18+
// End of file

src/commands/block.rs

Lines changed: 6 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
11
//! Block Device related commands for Neotron OS
22
3+
use super::{parse_u64, parse_u8};
34
use crate::{bios, osprint, osprintln, Ctx, API};
45

5-
pub static LSBLK_ITEM: menu::Item<Ctx> = menu::Item {
6-
item_type: menu::ItemType::Callback {
7-
function: lsblk,
8-
parameters: &[],
9-
},
10-
command: "lsblk",
11-
help: Some("List all the Block Devices"),
12-
};
13-
146
pub static READ_ITEM: menu::Item<Ctx> = menu::Item {
157
item_type: menu::ItemType::Callback {
168
function: read_block,
@@ -29,66 +21,21 @@ pub static READ_ITEM: menu::Item<Ctx> = menu::Item {
2921
help: Some("Display one disk block, as hex"),
3022
};
3123

32-
/// Called when the "lsblk" command is executed.
33-
fn lsblk(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) {
34-
let api = API.get();
35-
let mut found = false;
36-
37-
osprintln!("Block Devices:");
38-
for dev_idx in 0..=255u8 {
39-
if let bios::FfiOption::Some(device_info) = (api.block_dev_get_info)(dev_idx) {
40-
let (bsize, bunits, dsize, dunits) =
41-
match device_info.num_blocks * u64::from(device_info.block_size) {
42-
x if x < (1024 * 1024 * 1024) => {
43-
// Under 1 GiB, give it in 10s of MiB
44-
(10 * x / (1024 * 1024), "MiB", x / 100_000, "MB")
45-
}
46-
x => {
47-
// Anything else in GiB
48-
(10 * x / (1024 * 1024 * 1024), "GiB", x / 100_000_000, "GB")
49-
}
50-
};
51-
osprintln!("Device {}:", dev_idx);
52-
osprintln!(" Name: {}", device_info.name);
53-
osprintln!(" Type: {:?}", device_info.device_type);
54-
osprintln!(" Block size: {}", device_info.block_size);
55-
osprintln!(" Num Blocks: {}", device_info.num_blocks);
56-
osprintln!(
57-
" Card Size: {}.{} {} ({}.{} {})",
58-
bsize / 10,
59-
bsize % 10,
60-
bunits,
61-
dsize / 10,
62-
dsize % 10,
63-
dunits
64-
);
65-
osprintln!(" Ejectable: {}", device_info.ejectable);
66-
osprintln!(" Removable: {}", device_info.removable);
67-
osprintln!(" Media Present: {}", device_info.media_present);
68-
osprintln!(" Read Only: {}", device_info.read_only);
69-
found = true;
70-
}
71-
}
72-
if !found {
73-
osprintln!(" None");
74-
}
75-
}
76-
7724
/// Called when the "read_block" command is executed.
7825
fn read_block(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, args: &[&str], _ctx: &mut Ctx) {
7926
let api = API.get();
80-
let Ok(dev_idx) = args[0].parse::<u8>() else {
27+
let Ok(device_idx) = parse_u8(args[0]) else {
8128
osprintln!("Couldn't parse {:?}", args[0]);
8229
return;
8330
};
84-
let Ok(block_idx) = args[1].parse::<u64>() else {
31+
let Ok(block_idx) = parse_u64(args[1]) else {
8532
osprintln!("Couldn't parse {:?}", args[1]);
8633
return;
8734
};
8835
osprintln!("Reading block {}:", block_idx);
8936
let mut buffer = [0u8; 512];
9037
match (api.block_read)(
91-
dev_idx,
38+
device_idx,
9239
bios::block_dev::BlockIdx(block_idx),
9340
1,
9441
bios::FfiBuffer::new(&mut buffer),
@@ -110,3 +57,5 @@ fn read_block(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, args: &[&str], _
11057
}
11158
}
11259
}
60+
61+
// End of file

src/commands/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,5 @@ fn command(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, args: &[&str], ctx:
106106
}
107107
}
108108
}
109+
110+
// End of file

src/commands/fs.rs

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//! File Systems related commands for Neotron OS
22
3-
use embedded_sdmmc::VolumeIdx;
4-
53
use crate::{bios, osprint, osprintln, Ctx};
64

75
pub static DIR_ITEM: menu::Item<Ctx> = menu::Item {
@@ -25,6 +23,30 @@ pub static LOAD_ITEM: menu::Item<Ctx> = menu::Item {
2523
help: Some("Load a file into the application area"),
2624
};
2725

26+
pub static EXEC_ITEM: menu::Item<Ctx> = menu::Item {
27+
item_type: menu::ItemType::Callback {
28+
function: exec,
29+
parameters: &[menu::Parameter::Mandatory {
30+
parameter_name: "file",
31+
help: Some("The shell script to run"),
32+
}],
33+
},
34+
command: "exec",
35+
help: Some("Execute a shell script"),
36+
};
37+
38+
pub static TYPE_ITEM: menu::Item<Ctx> = menu::Item {
39+
item_type: menu::ItemType::Callback {
40+
function: typefn,
41+
parameters: &[menu::Parameter::Mandatory {
42+
parameter_name: "file",
43+
help: Some("The file to type"),
44+
}],
45+
},
46+
command: "type",
47+
help: Some("Type a file to the console"),
48+
};
49+
2850
/// Called when the "dir" command is executed.
2951
fn dir(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) {
3052
fn work() -> Result<(), embedded_sdmmc::Error<bios::Error>> {
@@ -33,7 +55,7 @@ fn dir(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &
3355
let time = crate::fs::BiosTime();
3456
let mut mgr = embedded_sdmmc::VolumeManager::new(bios_block, time);
3557
// Open the first partition
36-
let volume = mgr.open_volume(VolumeIdx(0))?;
58+
let volume = mgr.open_volume(embedded_sdmmc::VolumeIdx(0))?;
3759
let root_dir = mgr.open_root_dir(volume)?;
3860
let mut total_bytes = 0u64;
3961
let mut num_files = 0;
@@ -99,3 +121,76 @@ fn load(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, args: &[&str], ctx: &m
99121
}
100122
}
101123
}
124+
125+
/// Called when the "exec" command is executed.
126+
fn exec(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, args: &[&str], ctx: &mut Ctx) {
127+
fn work(ctx: &mut Ctx, filename: &str) -> Result<(), embedded_sdmmc::Error<bios::Error>> {
128+
let bios_block = crate::fs::BiosBlock();
129+
let time = crate::fs::BiosTime();
130+
let mut mgr = embedded_sdmmc::VolumeManager::new(bios_block, time);
131+
// Open the first partition
132+
let volume = mgr.open_volume(embedded_sdmmc::VolumeIdx(0))?;
133+
let root_dir = mgr.open_root_dir(volume)?;
134+
let file = mgr.open_file_in_dir(root_dir, filename, embedded_sdmmc::Mode::ReadOnly)?;
135+
let buffer = ctx.tpa.as_slice_u8();
136+
let count = mgr.read(file, buffer)?;
137+
if count != mgr.file_length(file)? as usize {
138+
osprintln!("File too large! Max {} bytes allowed.", buffer.len());
139+
return Ok(());
140+
}
141+
let Ok(s) = core::str::from_utf8(&buffer[0..count]) else {
142+
osprintln!("File is not valid UTF-8");
143+
return Ok(());
144+
};
145+
// tell the main loop to run from these bytes next
146+
ctx.exec_tpa = Some(s.len());
147+
Ok(())
148+
}
149+
150+
// index can't panic - we always have enough args
151+
let r = work(ctx, args[0]);
152+
match r {
153+
Ok(_) => {}
154+
Err(e) => {
155+
osprintln!("Error: {:?}", e);
156+
}
157+
}
158+
}
159+
160+
/// Called when the "type" command is executed.
161+
fn typefn(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, args: &[&str], ctx: &mut Ctx) {
162+
fn work(ctx: &mut Ctx, filename: &str) -> Result<(), embedded_sdmmc::Error<bios::Error>> {
163+
let bios_block = crate::fs::BiosBlock();
164+
let time = crate::fs::BiosTime();
165+
let mut mgr = embedded_sdmmc::VolumeManager::new(bios_block, time);
166+
// Open the first partition
167+
let volume = mgr.open_volume(embedded_sdmmc::VolumeIdx(0))?;
168+
let root_dir = mgr.open_root_dir(volume)?;
169+
let file = mgr.open_file_in_dir(root_dir, filename, embedded_sdmmc::Mode::ReadOnly)?;
170+
let buffer = ctx.tpa.as_slice_u8();
171+
let count = mgr.read(file, buffer)?;
172+
if count != mgr.file_length(file)? as usize {
173+
osprintln!("File too large! Max {} bytes allowed.", buffer.len());
174+
return Ok(());
175+
}
176+
let Ok(s) = core::str::from_utf8(&buffer[0..count]) else {
177+
osprintln!("File is not valid UTF-8");
178+
return Ok(());
179+
};
180+
osprintln!("{}", s);
181+
Ok(())
182+
}
183+
184+
// index can't panic - we always have enough args
185+
let r = work(ctx, args[0]);
186+
// reset SGR
187+
osprint!("\u{001b}[0m");
188+
match r {
189+
Ok(_) => {}
190+
Err(e) => {
191+
osprintln!("Error: {:?}", e);
192+
}
193+
}
194+
}
195+
196+
// End of file

0 commit comments

Comments
 (0)