sylveos

Toy Operating System
Log | Files | Refs

commit 7c133958420c19f0164d3bab656879df546bc793
parent 08f6d99ec1ea7a58092f57136bfd1f5706b3b287
Author: Sylvia Ivory <git@sivory.net>
Date:   Mon,  9 Feb 2026 21:48:42 -0800

Add better UI

Diffstat:
Mtools/Cargo.lock | 262++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtools/Cargo.toml | 3+++
Mtools/src/bootload.rs | 33+++++++++++++++++++++++++++++----
Mtools/src/main.rs | 38++++++++++++++++++++++++++++++--------
4 files changed, 323 insertions(+), 13 deletions(-)

diff --git a/tools/Cargo.lock b/tools/Cargo.lock @@ -3,6 +3,15 @@ version = 4 [[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] name = "anstream" version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -71,6 +80,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] name = "bytes" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -135,6 +150,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] +name = "console" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.61.2", +] + +[[package]] name = "core-foundation" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -180,13 +208,42 @@ dependencies = [ ] [[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] name = "errno" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -295,6 +352,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] +name = "indicatif" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88" +dependencies = [ + "console", + "portable-atomic", + "unicode-width", + "unit-prefix", + "web-time", +] + +[[package]] +name = "indicatif-log-bridge" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63703cf9069b85dbe6fe26e1c5230d013dee99d3559cd3d02ba39e099ef7ab02" +dependencies = [ + "indicatif", + "log", +] + +[[package]] name = "io-kit-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -311,6 +391,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] +name = "jiff" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89a5b5e10d5a9ad6e5d1f4bd58225f655d6fe9767575a5e8ac5a6fe64e04495" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff7a39c8862fc1369215ccf0a8f12dd4598c7f6484704359f0351bd617034dbf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] name = "libc" version = "0.2.181" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -395,6 +509,12 @@ dependencies = [ ] [[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] name = "once_cell_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -436,6 +556,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +dependencies = [ + "portable-atomic", +] + +[[package]] name = "proc-macro2" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -463,12 +598,67 @@ dependencies = [ ] [[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "serialport" version = "4.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -611,6 +801,9 @@ dependencies = [ "anyhow", "clap", "crc-fast", + "env_logger", + "indicatif", + "indicatif-log-bridge", "log", "thiserror", "tokio", @@ -639,6 +832,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unit-prefix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" + +[[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -657,6 +862,61 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/tools/Cargo.toml b/tools/Cargo.toml @@ -7,6 +7,9 @@ edition = "2024" anyhow = "1.0.101" clap = { version = "4.5.57", features = ["derive"] } crc-fast = "1.10.0" +env_logger = "0.11.8" +indicatif = "0.18.3" +indicatif-log-bridge = "0.2.3" log = "0.4.29" thiserror = "2.0.18" tokio = { version = "1.49.0", features = ["full"] } diff --git a/tools/src/bootload.rs b/tools/src/bootload.rs @@ -1,6 +1,7 @@ use std::path::Path; use crc_fast::{CrcAlgorithm::Crc32IsoHdlc, checksum}; +use indicatif::{MultiProgress, ProgressBar}; use log::{debug, info}; use tokio::{ fs::File, @@ -32,7 +33,12 @@ pub enum Error { Io(#[from] std::io::Error), } -pub async fn boot(port: &mut SerialStream, bin: &Path, base_address: u32) -> Result<(), Error> { +pub async fn boot( + multi: &MultiProgress, + port: &mut SerialStream, + bin: &Path, + base_address: u32, +) -> Result<(), Error> { // Technically blocking but it doesn't matter here let mut code = Vec::new(); @@ -41,11 +47,14 @@ pub async fn boot(port: &mut SerialStream, bin: &Path, base_address: u32) -> Res let checksum = checksum(Crc32IsoHdlc, &code) as u32; info!("crc32={:x}", checksum); + info!("waiting for a start"); while port.read_u32_le().await? != (Message::GetProgInfo as u32) { debug!("got invalid GetProgInfo") } + info!("got response"); + port.write_u32_le(Message::PutProgInfo as u32).await?; port.write_u32_le(base_address).await?; port.write_u32_le(code.len() as u32).await?; @@ -56,7 +65,10 @@ pub async fn boot(port: &mut SerialStream, bin: &Path, base_address: u32) -> Res match port.read_u32_le().await? { v if v == (Message::GetCode as u32) => break, v if v == (Message::BadCodeAddr as u32) => return Err(Error::BadAddress), - _ => continue, + v => { + debug!("got invalid GetCode: {v}"); + continue; + } } } @@ -67,16 +79,29 @@ pub async fn boot(port: &mut SerialStream, bin: &Path, base_address: u32) -> Res } port.write_u32_le(Message::PutCode as u32).await?; - port.write_all(&code).await?; + let pg = multi.add(ProgressBar::new(code.len() as u64)); + + for b in code.iter() { + port.write_u8(*b).await?; + pg.inc(1); + } port.flush().await?; + pg.finish(); + + info!("waiting for response"); loop { match port.read_u32_le().await? { v if v == (Message::BootSuccess as u32) => break, v if v == (Message::BadCodeChecksum as u32) => return Err(Error::BadAddress), - _ => continue, + v => { + debug!("got invalid BootSuccess: {v}"); + continue; + } } } + info!("boot successful"); + Ok(()) } diff --git a/tools/src/main.rs b/tools/src/main.rs @@ -1,8 +1,11 @@ use clap::Parser; +use indicatif::MultiProgress; +use indicatif_log_bridge::LogWrapper; +use log::{info, warn}; use tokio::io; use tokio_serial::{DataBits, FlowControl, Parity, SerialPortBuilderExt, SerialStream, StopBits}; -use std::{path::PathBuf, time::Duration}; +use std::{path::PathBuf, process::exit, time::Duration}; mod bootload; @@ -36,16 +39,31 @@ async fn default_action(port: SerialStream) -> anyhow::Result<()> { let mut stdin = io::stdin(); let mut stdout = io::stdout(); - let stdin_to_port = tokio::spawn(async move { io::copy(&mut stdin, &mut port_write).await }); - let port_to_stdout = tokio::spawn(async move { io::copy(&mut port_read, &mut stdout).await }); - - let _ = tokio::try_join!(stdin_to_port, port_to_stdout)?; - - Ok(()) + // let stdin_to_port = tokio::spawn(async move { io::copy(&mut stdin, &mut port_write).await }); + // let port_to_stdout = tokio::spawn(async move { io::copy(&mut port_read, &mut stdout).await }); + + tokio::select!( + _ = io::copy(&mut stdin, &mut port_write) => { + warn!("stdin disconnected, exiting"); + exit(0); + }, + _ = io::copy(&mut port_read, &mut stdout) => { + warn!("serial port disconnected, exiting"); + exit(0); + }, + ); } #[tokio::main] async fn main() -> anyhow::Result<()> { + let logger = + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).build(); + let level = logger.filter(); + let multi = MultiProgress::new(); + + LogWrapper::new(multi.clone(), logger).try_init().unwrap(); + log::set_max_level(level); + let args = Args::parse(); if !PathBuf::from(&args.device).exists() { @@ -64,7 +82,11 @@ async fn main() -> anyhow::Result<()> { .timeout(Duration::from_secs_f64(args.timeout)) .open_native_async()?; - bootload::boot(&mut port, &args.file, args.arm_base).await?; + info!( + "tty=<{}> baud=<{}> program=<{:?}> base address=<0x{:X}> timeout=<{}s>", + &args.device, args.baud, &args.file, args.arm_base, args.timeout + ); + bootload::boot(&multi, &mut port, &args.file, args.arm_base).await?; default_action(port).await?;