From 808c9afc1bdea5dae4af7f94945a1fd21c7aa8e7 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Thu, 30 Mar 2023 20:44:42 +0100 Subject: [PATCH 1/9] Better output from build script. --- build.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.sh b/build.sh index aae1a5b..d235682 100755 --- a/build.sh +++ b/build.sh @@ -8,8 +8,11 @@ mkdir -p ${RELEASE_DIR} # Build the embedded binaries for each core type and each flash layout for TARGET_ARCH in thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi; do + echo "TARGET is ${TARGET_ARCH}" for BINARY in flash0002 flash0802 flash1002; do - # objcopy will do the build for us first + echo "BINARY is ${BINARY}" + cargo build --verbose --release --target=${TARGET_ARCH} --bin ${BINARY} + # objcopy would do the build for us first, but it doesn't have good build output cargo objcopy --verbose --release --target=${TARGET_ARCH} --bin ${BINARY} -- -O binary ${RELEASE_DIR}/${TARGET_ARCH}-${BINARY}-libneotron_os.bin # Keep the ELF file too (for debugging) cp ./target/${TARGET_ARCH}/release/${BINARY} ${RELEASE_DIR}/${TARGET_ARCH}-${BINARY}-libneotron_os.elf @@ -17,5 +20,6 @@ for TARGET_ARCH in thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi; do done # Build the host version +echo "Building HOST" cargo build --verbose --lib --release --target=x86_64-unknown-linux-gnu cp ./target/x86_64-unknown-linux-gnu/release/libneotron_os.so ${RELEASE_DIR}/x86_64-unknown-linux-gnu-libneotron_os.so From 67b43f42614d97f2aeeda10b8e4d581aa83feb4c Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Thu, 30 Mar 2023 20:46:12 +0100 Subject: [PATCH 2/9] screen_fill emits colours. --- src/commands/screen.rs | 50 ++++++++++++++++++++++++++++----------- src/vgaconsole.rs | 53 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/src/commands/screen.rs b/src/commands/screen.rs index ee8f7a3..b524b8b 100644 --- a/src/commands/screen.rs +++ b/src/commands/screen.rs @@ -1,6 +1,8 @@ //! Screen-related commands for Neotron OS -use crate::{print, println, Ctx, API, VGA_CONSOLE}; +use neotron_common_bios::video::{Attr, TextBackgroundColour, TextForegroundColour}; + +use crate::{println, Ctx, API, VGA_CONSOLE}; pub static CLEAR_ITEM: menu::Item = menu::Item { item_type: menu::ItemType::Callback { @@ -31,19 +33,39 @@ fn clear(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: fn fill(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: &mut Ctx) { if let Some(ref mut console) = unsafe { &mut VGA_CONSOLE } { console.clear(); - } - let api = API.get(); - let mode = (api.video_get_mode)(); - let (Some(width), Some(height)) = (mode.text_width(), mode.text_height()) else { - println!("Unable to get console size"); - return; - }; - // A range of printable ASCII compatible characters - let mut char_cycle = (' '..='~').cycle(); - // Scroll two screen fulls - for _row in 0..height * 2 { - for _col in 0..width { - print!("{}", char_cycle.next().unwrap()); + let api = API.get(); + let mode = (api.video_get_mode)(); + let (Some(width), Some(height)) = (mode.text_width(), mode.text_height()) else { + println!("Unable to get console size"); + return; + }; + // A range of printable ASCII compatible characters + let mut char_cycle = (b' '..=b'~').cycle(); + let mut remaining = height * width; + + // Scroll two screen fulls + 'outer: for bg in (0..=7).cycle() { + let bg_colour = TextBackgroundColour::new(bg).unwrap(); + for fg in 1..=15 { + if fg == bg { + continue; + } + let fg_colour = TextForegroundColour::new(fg).unwrap(); + remaining -= 1; + if remaining == 0 { + break 'outer; + } + let attr = Attr::new(fg_colour, bg_colour, false); + let glyph = char_cycle.next().unwrap(); + console.set_attr(attr); + console.write_bstr(&[glyph]); + } } + let attr = Attr::new( + TextForegroundColour::WHITE, + TextBackgroundColour::BLACK, + false, + ); + console.set_attr(attr); } } diff --git a/src/vgaconsole.rs b/src/vgaconsole.rs index 63e8c05..c21ca97 100644 --- a/src/vgaconsole.rs +++ b/src/vgaconsole.rs @@ -5,13 +5,13 @@ use neotron_common_bios::video::{Attr, TextBackgroundColour, TextForegroundColour}; -#[derive(Debug)] pub struct VgaConsole { addr: *mut u8, width: isize, height: isize, row: isize, col: isize, + attr: Attr, } impl VgaConsole { @@ -29,6 +29,7 @@ impl VgaConsole { height, row: 0, col: 0, + attr: Self::DEFAULT_ATTR, } } @@ -60,24 +61,56 @@ impl VgaConsole { pub fn clear(&mut self) { for row in 0..self.height { for col in 0..self.width { - self.write_at(row, col, b' ', Some(Self::DEFAULT_ATTR)); + self.write_at(row, col, b' '); } } self.reset_cursor(); } - fn write(&mut self, glyph: u8, attr: Option) { - self.write_at(self.row, self.col, glyph, attr); + pub fn write_bstr(&mut self, bstr: &[u8]) { + for b in bstr { + self.scroll_as_required(); + match b { + 0x08 => { + // This is a backspace, so we go back one character (if we + // can). We expect the caller to provide "\u{0008} \u{0008}" + // to actually erase the char then move the cursor over it. + if self.col > 0 { + self.col -= 1; + } + } + b'\r' => { + self.col = 0; + } + b'\n' => { + self.col = 0; + self.move_char_down(); + } + _ => { + self.write(*b); + self.move_char_right(); + } + } + } } - fn write_at(&mut self, row: isize, col: isize, glyph: u8, attr: Option) { + /// Set the default attribute for any future text. + pub fn set_attr(&mut self, attr: Attr) { + self.attr = attr; + } + + /// Put a glyph at the next position on the screen. + fn write(&mut self, glyph: u8) { + self.write_at(self.row, self.col, glyph); + } + + /// Put a glyph at a given position on the screen. + fn write_at(&mut self, row: isize, col: isize, glyph: u8) { assert!(row < self.height, "{} >= {}?", row, self.height); assert!(col < self.width, "{} => {}?", col, self.width); let offset = ((row * self.width) + col) * 2; unsafe { core::ptr::write_volatile(self.addr.offset(offset), glyph) }; - if let Some(a) = attr { - unsafe { core::ptr::write_volatile(self.addr.offset(offset + 1), a.0) }; - } + unsafe { core::ptr::write_volatile(self.addr.offset(offset + 1), self.attr.as_u8()) }; } fn scroll_page(&mut self) { @@ -91,7 +124,7 @@ impl VgaConsole { ); // Blank the bottom line of the screen (rows[height-1]). for col in 0..self.width { - self.write_at(self.height - 1, col, b' ', Some(Self::DEFAULT_ATTR)); + self.write_at(self.height - 1, col, b' '); } } } @@ -260,7 +293,7 @@ impl core::fmt::Write for VgaConsole { self.move_char_down(); } _ => { - self.write(Self::map_char_to_glyph(ch), None); + self.write(Self::map_char_to_glyph(ch)); self.move_char_right(); } } From 3d5850c9b14b678ab52bd9e76401ff9bddf85eeb Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Fri, 31 Mar 2023 19:08:49 +0100 Subject: [PATCH 3/9] Add screen_bench command. Times how long to put 1,000,000 chars on the screen (with scrolling). --- src/commands/mod.rs | 1 + src/commands/screen.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/commands/mod.rs b/src/commands/mod.rs index a7b0dd4..41c5769 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -20,6 +20,7 @@ pub static OS_MENU: menu::Menu = menu::Menu { #[cfg(target_os = "none")] &ram::RUN_ITEM, &screen::CLEAR_ITEM, + &screen::BENCH_ITEM, &screen::FILL_ITEM, &input::KBTEST_ITEM, ], diff --git a/src/commands/screen.rs b/src/commands/screen.rs index b524b8b..136e816 100644 --- a/src/commands/screen.rs +++ b/src/commands/screen.rs @@ -22,6 +22,15 @@ pub static FILL_ITEM: menu::Item = menu::Item { help: Some("Fill the screen with characters"), }; +pub static BENCH_ITEM: menu::Item = menu::Item { + item_type: menu::ItemType::Callback { + function: bench, + parameters: &[], + }, + command: "screen_bench", + help: Some("Time how long to put 1,000,000 characters on the screen, with scrolling."), +}; + /// Called when the "clear" command is executed. fn clear(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: &mut Ctx) { if let Some(ref mut console) = unsafe { &mut VGA_CONSOLE } { @@ -69,3 +78,24 @@ fn fill(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: console.set_attr(attr); } } + +/// Called when the "bench" command is executed. +fn bench(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: &mut Ctx) { + const NUM_CHARS: u64 = 1_000_000; + if let Some(ref mut console) = unsafe { &mut VGA_CONSOLE } { + let api = API.get(); + let start = (api.time_ticks_get)(); + console.clear(); + let glyphs = &[b'x']; + for _idx in 0..NUM_CHARS { + console.write_bstr(glyphs); + } + let end = (api.time_ticks_get)(); + let delta = end.0 - start.0; + let chars_per_second = (NUM_CHARS * (api.time_ticks_per_second)().0) / delta; + println!( + "{} chars in {} ticks, or {} chars per second", + NUM_CHARS, delta, chars_per_second + ); + } +} From 0d0b20c5aa0afa30e9da07b1903b9c9f855ae7d4 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Fri, 31 Mar 2023 19:43:46 +0100 Subject: [PATCH 4/9] Added a mandelbrot set. --- src/commands/mod.rs | 1 + src/commands/screen.rs | 48 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 41c5769..de07048 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -22,6 +22,7 @@ pub static OS_MENU: menu::Menu = menu::Menu { &screen::CLEAR_ITEM, &screen::BENCH_ITEM, &screen::FILL_ITEM, + &screen::MANDEL_ITEM, &input::KBTEST_ITEM, ], entry: None, diff --git a/src/commands/screen.rs b/src/commands/screen.rs index 136e816..3a75ee9 100644 --- a/src/commands/screen.rs +++ b/src/commands/screen.rs @@ -2,7 +2,7 @@ use neotron_common_bios::video::{Attr, TextBackgroundColour, TextForegroundColour}; -use crate::{println, Ctx, API, VGA_CONSOLE}; +use crate::{print, println, Ctx, API, VGA_CONSOLE}; pub static CLEAR_ITEM: menu::Item = menu::Item { item_type: menu::ItemType::Callback { @@ -31,6 +31,15 @@ pub static BENCH_ITEM: menu::Item = menu::Item { help: Some("Time how long to put 1,000,000 characters on the screen, with scrolling."), }; +pub static MANDEL_ITEM: menu::Item = menu::Item { + item_type: menu::ItemType::Callback { + function: mandel, + parameters: &[], + }, + command: "screen_mandel", + help: Some("Calculate the Mandelbrot set"), +}; + /// Called when the "clear" command is executed. fn clear(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: &mut Ctx) { if let Some(ref mut console) = unsafe { &mut VGA_CONSOLE } { @@ -99,3 +108,40 @@ fn bench(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: ); } } + +/// Called when the "mandel" command is executed. +fn mandel(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: &mut Ctx) { + fn mandelbrot(cx: f64, cy: f64, max_loops: u32) -> u32 { + let mut x = cx; + let mut y = cy; + for i in 1..max_loops { + let x_squared = x * x; + let y_squared = y * y; + if x_squared + y_squared > 4.0 { + return i; + } + let x1 = x_squared - y_squared + cx; + let y1 = (2.0 * x * y) + cy; + x = x1; + y = y1; + } + 0 + } + + let api = API.get(); + let mode = (api.video_get_mode)(); + let (Some(width), Some(height)) = (mode.text_width(), mode.text_height()) else { + println!("Unable to get screen size"); + return; + }; + + let glyphs = b" .,'~!^:;[/<&?oxOX# "; + for y_pos in 0..height - 2 { + let y = (f64::from(y_pos) * 4.0 / f64::from(height)) - 2.0; + for x_pos in 0..width { + let x = (f64::from(x_pos) * 4.0 / f64::from(width)) - 2.0; + let result = mandelbrot(x, y, 20); + print!("{}", glyphs[result as usize] as char); + } + } +} From 70e11f042b3d1bd7f8b2d18af7c7e8a661f6c74c Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Thu, 6 Apr 2023 21:45:59 +0100 Subject: [PATCH 5/9] Add 'date' command. Lets you get and set the current time/date. --- Cargo.toml | 1 + src/commands/mod.rs | 2 ++ src/commands/timedate.rs | 43 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 43 +++++++++++++++++++++++++++++++++++----- 4 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 src/commands/timedate.rs diff --git a/Cargo.toml b/Cargo.toml index 96bb39e..2c38191 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,3 +43,4 @@ r0 = "1.0" postcard = "0.5" serde = { version = "1.0", default-features = false } menu = "0.3" +chrono = { version = "0.4", default-features = false } diff --git a/src/commands/mod.rs b/src/commands/mod.rs index a7b0dd4..c31bb13 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -9,10 +9,12 @@ mod hardware; mod input; mod ram; mod screen; +mod timedate; pub static OS_MENU: menu::Menu = menu::Menu { label: "root", items: &[ + &timedate::DATE_ITEM, &config::COMMAND_ITEM, &hardware::LSHW_ITEM, &ram::HEXDUMP_ITEM, diff --git a/src/commands/timedate.rs b/src/commands/timedate.rs new file mode 100644 index 0000000..f575d9d --- /dev/null +++ b/src/commands/timedate.rs @@ -0,0 +1,43 @@ +//! CLI commands for getting/setting time/date + +use chrono::{Datelike, Timelike}; + +use crate::{println, Ctx, API}; + +pub static DATE_ITEM: menu::Item = menu::Item { + item_type: menu::ItemType::Callback { + function: date, + parameters: &[menu::Parameter::Optional { + parameter_name: "timestamp", + help: Some("The new date/time, in ISO8601 format"), + }], + }, + command: "date", + help: Some("Get/set the time and date"), +}; + +/// Called when the "date" command is executed. +fn date(_menu: &menu::Menu, item: &menu::Item, args: &[&str], _ctx: &mut Ctx) { + if let Ok(Some(timestamp)) = menu::argument_finder(item, args, "timestamp") { + println!("Setting date/time to {:?}", timestamp); + static DATE_FMT: &str = "%Y-%m-%dT%H:%M:%S"; + let Ok(timestamp) = chrono::NaiveDateTime::parse_from_str(timestamp, DATE_FMT) else { + println!("Unable to parse date/time"); + return; + }; + API.set_time(timestamp); + } + + let time = API.get_time(); + // Ensure this matches `DATE_FMT`, for consistency + println!( + "The time is {:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:09}", + time.year(), + time.month(), + time.day(), + time.hour(), + time.minute(), + time.second(), + time.nanosecond() + ); +} diff --git a/src/lib.rs b/src/lib.rs index 836ca5e..dbdb67d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,9 @@ mod vgaconsole; /// The OS version string const OS_VERSION: &str = concat!("Neotron OS, version ", env!("OS_VERSION")); +/// Used to convert between POSIX epoch (for `chrono`) and Neotron epoch (for BIOS APIs). +const SECONDS_BETWEEN_UNIX_AND_NEOTRON_EPOCH: i64 = 946684800; + /// We store the API object supplied by the BIOS here static API: Api = Api::new(); @@ -72,25 +75,55 @@ macro_rules! println { // Local types // =========================================================================== +/// Represents the API supplied by the BIOS +struct Api { + bios: core::sync::atomic::AtomicPtr, +} + impl Api { + /// Create a new object with a null pointer for the BIOS API. const fn new() -> Api { Api { bios: core::sync::atomic::AtomicPtr::new(core::ptr::null_mut()), } } - fn store(&self, api: *const bios::Api) { + /// Change the stored BIOS API pointer. + /// + /// The pointed-at object must have static lifetime. + unsafe fn store(&self, api: *const bios::Api) { self.bios .store(api as *mut bios::Api, core::sync::atomic::Ordering::SeqCst) } + /// Get the BIOS API as a reference. + /// + /// Will panic if the stored pointer is null. fn get(&self) -> &'static bios::Api { - unsafe { &*(self.bios.load(core::sync::atomic::Ordering::SeqCst) as *const bios::Api) } + let ptr = self.bios.load(core::sync::atomic::Ordering::SeqCst) as *const bios::Api; + let api_ref = unsafe { ptr.as_ref() }.expect("BIOS API should be non-null"); + api_ref } -} -struct Api { - bios: core::sync::atomic::AtomicPtr, + /// Get the current time + fn get_time(&self) -> chrono::NaiveDateTime { + let api = self.get(); + let bios_time = (api.time_clock_get)(); + let secs = i64::from(bios_time.secs) + SECONDS_BETWEEN_UNIX_AND_NEOTRON_EPOCH; + let nsecs = bios_time.nsecs; + chrono::NaiveDateTime::from_timestamp_opt(secs, nsecs).unwrap() + } + + /// Set the current time + fn set_time(&self, timestamp: chrono::NaiveDateTime) { + let api = self.get(); + let nanos = timestamp.timestamp_nanos(); + let bios_time = bios::Time { + secs: ((nanos / 1_000_000_000) - SECONDS_BETWEEN_UNIX_AND_NEOTRON_EPOCH) as u32, + nsecs: (nanos % 1_000_000_000) as u32, + }; + (api.time_clock_set)(bios_time); + } } /// Represents the serial port we can use as a text input/output device. From d11a25bf8badc94fb6ea22e2b2ed8662346e4483 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Mon, 1 May 2023 13:59:29 +0100 Subject: [PATCH 6/9] Add commands for testing the SD card. --- src/commands/block.rs | 117 ++++++++++++++++++++++++++++++++++++++++++ src/commands/mod.rs | 3 ++ 2 files changed, 120 insertions(+) create mode 100644 src/commands/block.rs diff --git a/src/commands/block.rs b/src/commands/block.rs new file mode 100644 index 0000000..87fab98 --- /dev/null +++ b/src/commands/block.rs @@ -0,0 +1,117 @@ +//! Block Device related commands for Neotron OS + +use crate::{bios, print, println, Ctx, API}; + +pub static LSBLK_ITEM: menu::Item = menu::Item { + item_type: menu::ItemType::Callback { + function: lsblk, + parameters: &[], + }, + command: "lsblk", + help: Some("List all the Block Devices"), +}; + +pub static READ_ITEM: menu::Item = menu::Item { + item_type: menu::ItemType::Callback { + function: read_block, + parameters: &[ + menu::Parameter::Mandatory { + parameter_name: "device_idx", + help: Some("The block device ID to fetch from"), + }, + menu::Parameter::Mandatory { + parameter_name: "block_idx", + help: Some("The block to fetch, 0..num_blocks"), + }, + ], + }, + command: "readblk", + help: Some("List all the Block Devices"), +}; + +/// Called when the "lsblk" command is executed. +fn lsblk(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: &mut Ctx) { + let api = API.get(); + let mut found = false; + + println!("Block Devices:"); + for dev_idx in 0..=255u8 { + if let bios::Option::Some(device_info) = (api.block_dev_get_info)(dev_idx) { + let (bsize, bunits, dsize, dunits) = + match device_info.num_blocks * u64::from(device_info.block_size) { + x if x < (1024 * 1024 * 1024) => { + // Under 1 GiB, give it in 10s of MiB + (10 * x / (1024 * 1024), "MiB", x / 100_000, "MB") + } + x => { + // Anything else in GiB + (10 * x / (1024 * 1024 * 1024), "GiB", x / 100_000_000, "GB") + } + }; + println!("Device {}:", dev_idx); + println!(" Name: {}", device_info.name); + println!(" Type: {:?}", device_info.device_type); + println!(" Block size: {}", device_info.block_size); + println!(" Num Blocks: {}", device_info.num_blocks); + println!( + " Card Size: {}.{} {} ({}.{} {})", + bsize / 10, + bsize % 10, + bunits, + dsize / 10, + dsize % 10, + dunits + ); + println!(" Ejectable: {}", device_info.ejectable); + println!(" Removable: {}", device_info.removable); + println!(" Media Present: {}", device_info.media_present); + println!(" Read Only: {}", device_info.read_only); + found = true; + } + } + if !found { + println!(" None"); + } +} + +/// Called when the "read_block" command is executed. +fn read_block(_menu: &menu::Menu, _item: &menu::Item, args: &[&str], _ctx: &mut Ctx) { + let api = API.get(); + let Ok(dev_idx) = args[0].parse::() else { + println!("Couldn't parse {:?}", args[0]); + return; + }; + let Ok(block_idx) = args[1].parse::() else { + println!("Couldn't parse {:?}", args[1]); + return; + }; + println!("Reading block {}:", block_idx); + let mut buffer = [0u8; 512]; + match (api.block_read)( + dev_idx, + bios::block_dev::BlockIdx(block_idx), + 1, + bios::ApiBuffer::new(&mut buffer), + ) { + bios::Result::Ok(_) => { + // Carry on + let mut count = 0; + for chunk in buffer.chunks(16) { + print!("{:03x}: ", count); + for b in chunk { + print!("{:02x} ", *b); + } + print!(" "); + for b in chunk { + let c = char::from(*b); + print!("{}", if c.is_ascii_graphic() { c } else { '.' }); + } + count += chunk.len(); + println!(); + } + } + bios::Result::Err(e) => { + println!("Failed to read: {:?}", e); + } + } +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 57e7537..fe0989f 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -4,6 +4,7 @@ pub use super::Ctx; +mod block; mod config; mod hardware; mod input; @@ -16,6 +17,8 @@ pub static OS_MENU: menu::Menu = menu::Menu { items: &[ &timedate::DATE_ITEM, &config::COMMAND_ITEM, + &block::LSBLK_ITEM, + &block::READ_ITEM, &hardware::LSHW_ITEM, &ram::HEXDUMP_ITEM, &ram::LOAD_ITEM, From 8d2e17722ce6049169c0670d29ea72790ceaf86b Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Mon, 1 May 2023 13:59:46 +0100 Subject: [PATCH 7/9] Rename bioshw to lshw. --- src/commands/hardware.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/hardware.rs b/src/commands/hardware.rs index 7068b9e..92f4c79 100644 --- a/src/commands/hardware.rs +++ b/src/commands/hardware.rs @@ -4,15 +4,15 @@ use crate::{bios, println, Ctx, API}; pub static LSHW_ITEM: menu::Item = menu::Item { item_type: menu::ItemType::Callback { - function: bioshw, + function: lshw, parameters: &[], }, - command: "bioshw", + command: "lshw", help: Some("List all the BIOS hardware"), }; -/// Called when the "bioshw" command is executed. -fn bioshw(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: &mut Ctx) { +/// Called when the "lshw" command is executed. +fn lshw(_menu: &menu::Menu, _item: &menu::Item, _args: &[&str], _ctx: &mut Ctx) { let api = API.get(); let mut found = false; From cf12616440a0fca8fef69ca3cf809b2ff8132258 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Mon, 1 May 2023 14:18:11 +0100 Subject: [PATCH 8/9] Update CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 384c17e..259308a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## Unrelease changes + +* Add `date` command. +* Add `lsblk` and `blkread` commands. +* Renamed `bioshw` to `lshw` + ## v0.3.1 * Add `hexdump`, `load` and `run` commands. From 7577423ee4a2b129737844a8ae47692c1ad3cefb Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (Ferrous Systems)" Date: Fri, 5 May 2023 15:14:21 +0100 Subject: [PATCH 9/9] Bump to 0.3.2 --- CHANGELOG.md | 4 +++- Cargo.toml | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 259308a..3020dfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Change Log -## Unrelease changes +## Unreleased changes + +## v0.3.2 * Add `date` command. * Add `lsblk` and `blkread` commands. diff --git a/Cargo.toml b/Cargo.toml index 2c38191..8ad29bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "neotron-os" -version = "0.3.1" -authors = ["Jonathan 'theJPster' Pallant "] +version = "0.3.2" +authors = ["Jonathan 'theJPster' Pallant ", "The Neotron Developers"] edition = "2018" description = "The Neotron Operating System" license = "GPL-3.0-or-later"