Skip to content

Commit d4bf6c3

Browse files
authored
Merge pull request #12 from Neotron-Compute/config-support
Add support for reading/writing OS config.
2 parents 07c8e47 + 076c303 commit d4bf6c3

File tree

4 files changed

+84
-25
lines changed

4 files changed

+84
-25
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
# Shared libraries from OS build
99
*.dylib
1010
*.so
11+
*.dll
1112

1213
# Our uncompressed disk image
1314
disk.img
1415

16+
# This where you should store your OS config
17+
nvram.dat

README.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ Build and run this BIOS (and use it to boot Neotron OS) with...
2828
```console
2929
~ $ git checkout https://github.com/neotron-compute/Neotron-Desktop-BIOS.git
3030
~ $ cd Neotron-Desktop-BIOS
31-
~/Neotron-Desktop-BIOS $ RUST_LOG=debug cargo run -- --serial=/dev/ttyS0 --peripheral=sdmmc,./disk.img --os=./libneotron_os.so
31+
~/Neotron-Desktop-BIOS $ gunzip -c disk.img.gz > disk.img
32+
~/Neotron-Desktop-BIOS $ RUST_LOG=debug cargo run -- --nvram=./nvram.dat --os=./libneotron_os.so --disk=./disk.img
3233
```
3334

34-
Press `Esc` with the GUI window selected to quit the BIOS.
35+
In the OS run the `shutdown` command to quit.
3536

3637
The file `libneotron_os.so` is not supplied. You can build it with:
3738

@@ -61,20 +62,40 @@ The file `libneotron_os.so` is not supplied. You can build it with:
6162
C:\Users\user\Documents> set LIB=%LIB%;C:\Users\user\Documents\vcpkg\installed\x64-windows\lib
6263
```
6364

65+
4. Build as usual:
66+
67+
```console
68+
C:\Users\user\Documents\neotron-desktop-bios> cargo run --release -- --nvram=.\nvram.dat --os=.\neotron_os.dll
69+
```
70+
71+
Sorry, if you want to use the disk image you'll need a Windows version of `gunzip` to unpack it. Git Bash might work.
72+
73+
In the OS run the `shutdown` command to quit.
74+
75+
The file `neotron_os.dll` is not supplied. You can build it with:
76+
77+
```console
78+
C:\Users\user\Documents> git checkout https://github.com/neotron-compute/neotron-os.git
79+
C:\Users\user\Documents> cd neotron-os
80+
C:\Users\user\Documents\neotron-os> cargo build --release --lib
81+
C:\Users\user\Documents\neotron-os> copy .\target\release\neotron_os.dll ..\Neotron-Desktop-BIOS
82+
```
83+
6484
## Features
6585

6686
* GUI window with pixel-perfect video rendering
6787
* Block device support
6888
* Keyboard support
6989
* Power-off support
90+
* Config file support
7091
* TODO: Audio support
7192
* TODO: UART support
7293

7394
## Changelog
7495

7596
### Unreleased Changes ([Source](https://github.com/neotron-compute/Neotron-Desktop-BIOS/tree/main))
7697

77-
* None
98+
* Added config get/set
7899

79100
### v0.1.0 ([Source](https://github.com/neotron-compute/Neotron-Desktop-BIOS/tree/v0.1.0))
80101

disk.img.gz

-379 KB
Binary file not shown.

src/main.rs

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@
2828
// ===========================================================================
2929

3030
use std::io::prelude::*;
31-
use std::sync::atomic::{AtomicU32, AtomicU8, Ordering};
31+
use std::path::PathBuf;
32+
use std::sync::{
33+
atomic::{AtomicU32, AtomicU8, Ordering},
34+
mpsc, Mutex,
35+
};
3236

3337
use clap::Parser;
3438
use common::video::RGBColour;
@@ -47,7 +51,7 @@ struct MyApp {
4751
mode: common::video::Mode,
4852
font8x16: Vec<TextureId>,
4953
font8x8: Vec<TextureId>,
50-
sender: std::sync::mpsc::Sender<AppEvent>,
54+
sender: mpsc::Sender<AppEvent>,
5155
}
5256

5357
#[derive(Debug, PartialEq, Eq)]
@@ -68,10 +72,13 @@ struct Framebuffer<const N: usize> {
6872
struct Args {
6973
/// Path to the OS library
7074
#[arg(long)]
71-
os: std::path::PathBuf,
75+
os: PathBuf,
7276
/// Path to a file to use as a disk image
7377
#[arg(long)]
74-
disk: Option<std::path::PathBuf>,
78+
disk: Option<PathBuf>,
79+
/// Path to NVRAM file
80+
#[arg(long)]
81+
nvram: Option<PathBuf>,
7582
}
7683

7784
/// All our emulated hardware
@@ -99,7 +106,7 @@ static FRAMEBUFFER: Framebuffer<{ 640 * 480 }> = Framebuffer::new();
99106
const SCALE_FACTOR: f32 = 2.0;
100107

101108
/// When we booted up
102-
static HARDWARE: std::sync::Mutex<Option<Hardware>> = std::sync::Mutex::new(None);
109+
static HARDWARE: Mutex<Option<Hardware>> = Mutex::new(None);
103110

104111
/// The functions we export to the OS
105112
static BIOS_API: common::Api = common::Api {
@@ -673,8 +680,11 @@ static PALETTE: [AtomicU32; 256] = [
673680

674681
static VIDEO_MODE: AtomicU8 = AtomicU8::new(0);
675682

676-
static EV_QUEUE: std::sync::Mutex<Option<std::sync::mpsc::Receiver<AppEvent>>> =
677-
std::sync::Mutex::new(None);
683+
/// HID events come from here
684+
static EV_QUEUE: Mutex<Option<mpsc::Receiver<AppEvent>>> = Mutex::new(None);
685+
686+
/// Where the OS config is read from or written to.
687+
static CONFIG_FILE_PATH: Mutex<Option<PathBuf>> = Mutex::new(None);
678688

679689
// ===========================================================================
680690
// Macros
@@ -722,15 +732,14 @@ fn main() {
722732
}
723733

724734
// Process args
725-
let mut lib = None;
726-
for arg in std::env::args() {
727-
if let Some(os_path) = arg.strip_prefix("--os=") {
728-
info!("Loading OS from {:?}", os_path);
729-
lib = unsafe { Some(libloading::Library::new(os_path).expect("library to load")) };
730-
println!("Loaded!");
731-
}
735+
info!("Loading OS from: {}", args.os.display());
736+
let lib = unsafe { libloading::Library::new(args.os).expect("library to load") };
737+
println!("Loaded!");
738+
739+
if let Some(config_path) = args.nvram {
740+
info!("Loading OS config from: {}", config_path.display());
741+
*CONFIG_FILE_PATH.lock().unwrap() = Some(config_path);
732742
}
733-
let lib = lib.expect("Fetching --os=filename from args");
734743

735744
// Make a window
736745
let mut engine = Engine::builder()
@@ -740,7 +749,7 @@ fn main() {
740749
.target_frame_rate(60)
741750
.build()
742751
.unwrap();
743-
let (sender, receiver) = std::sync::mpsc::channel();
752+
let (sender, receiver) = mpsc::channel();
744753
let mut app = MyApp {
745754
mode: unsafe { common::video::Mode::from_u8(0) },
746755
font8x16: Vec::new(),
@@ -883,17 +892,43 @@ extern "C" fn time_clock_set(time: common::Time) {
883892
/// Configuration data is, to the BIOS, just a block of bytes of a given
884893
/// length. How it stores them is up to the BIOS - it could be EEPROM, or
885894
/// battery-backed SRAM.
886-
extern "C" fn configuration_get(_buffer: common::FfiBuffer) -> common::ApiResult<usize> {
887-
debug!("configuration_get()");
888-
Err(common::Error::Unimplemented).into()
895+
extern "C" fn configuration_get(mut os_buffer: common::FfiBuffer) -> common::ApiResult<usize> {
896+
let file_path = CONFIG_FILE_PATH.lock().unwrap().clone();
897+
let Some(os_buffer) = os_buffer.as_mut_slice() else {
898+
return common::ApiResult::Err(common::Error::DeviceError(0));
899+
};
900+
match file_path.as_ref() {
901+
Some(path) => match std::fs::read(path) {
902+
Ok(read_data) => {
903+
for (src, dest) in read_data.iter().zip(os_buffer.iter_mut()) {
904+
*dest = *src;
905+
}
906+
common::ApiResult::Ok(read_data.len())
907+
}
908+
Err(_e) => {
909+
println!("Failed to get config from {:?}", path);
910+
common::ApiResult::Err(common::Error::DeviceError(0))
911+
}
912+
},
913+
None => common::ApiResult::Err(common::Error::Unimplemented),
914+
}
889915
}
890916

891917
/// Set the configuration data block.
892918
///
893919
/// See `configuration_get`.
894-
extern "C" fn configuration_set(_buffer: common::FfiByteSlice) -> common::ApiResult<()> {
895-
debug!("configuration_set()");
896-
Err(common::Error::Unimplemented).into()
920+
extern "C" fn configuration_set(buffer: common::FfiByteSlice) -> common::ApiResult<()> {
921+
let file_path = CONFIG_FILE_PATH.lock().unwrap().clone();
922+
match file_path.as_ref() {
923+
Some(path) => match std::fs::write(path, buffer.as_slice()) {
924+
Ok(_) => common::ApiResult::Ok(()),
925+
Err(_e) => {
926+
println!("Failed to write config to {:?}", path);
927+
common::ApiResult::Err(common::Error::DeviceError(0))
928+
}
929+
},
930+
None => common::ApiResult::Err(common::Error::Unimplemented),
931+
}
897932
}
898933

899934
/// Does this Neotron BIOS support this video mode?

0 commit comments

Comments
 (0)