diff --git a/firmware2/Cargo.lock b/firmware2/Cargo.lock index face15f..7710415 100644 --- a/firmware2/Cargo.lock +++ b/firmware2/Cargo.lock @@ -15,6 +15,8 @@ dependencies = [ "embassy-embedded-hal", "embassy-executor", "embassy-time", + "embedded-cli", + "embedded-io 0.6.1", "embuild", "esp-alloc", "esp-backtrace", @@ -31,6 +33,7 @@ dependencies = [ "paste", "rand_core 0.6.4", "rmk", + "shadow-rs", "slint", "slint-build", "static_cell", @@ -944,6 +947,26 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "convert_case" version = "0.6.0" @@ -1256,6 +1279,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive_more" version = "2.1.1" @@ -1614,6 +1646,31 @@ dependencies = [ "nb 1.1.0", ] +[[package]] +name = "embedded-cli" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e0bae60fe7389ddcb0a95e5ed1bf007e4c2a13d3925bd2db6f4c4923c08af" +dependencies = [ + "bitflags 2.10.0", + "embedded-cli-macros", + "embedded-io 0.6.1", + "ufmt", +] + +[[package]] +name = "embedded-cli-macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c10085b0b308f1fb243fb19c739766a13030ddd7b281bc8034acc431932522bf" +dependencies = [ + "convert_case 0.6.0", + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "embedded-hal" version = "0.2.7" @@ -1805,7 +1862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2605,6 +2662,19 @@ dependencies = [ "weezl", ] +[[package]] +name = "git2" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2b37e2f62729cdada11f0e6b3b6fe383c69c29fc619e391223e12856af308c" +dependencies = [ + "bitflags 2.10.0", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "gl_generator" version = "0.14.0" @@ -3317,6 +3387,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "is_debug" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe266d2e243c931d8190177f20bf7f24eed45e96f39e87dc49a27b32d12d407" + [[package]] name = "itertools" version = "0.13.0" @@ -3494,6 +3570,18 @@ dependencies = [ "cc", ] +[[package]] +name = "libgit2-sys" +version = "0.18.3+1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + [[package]] name = "libloading" version = "0.8.9" @@ -3531,6 +3619,18 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libz-sys" +version = "1.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linebender_resource_handle" version = "0.1.1" @@ -3851,6 +3951,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.4.2" @@ -3914,6 +4020,15 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "objc-sys" version = "0.3.5" @@ -4600,6 +4715,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -5208,7 +5329,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -5421,6 +5542,19 @@ dependencies = [ "digest", ] +[[package]] +name = "shadow-rs" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff351910f271e7065781b6b4f0f43cb515d474d812f31176a0246d9058e47d5d" +dependencies = [ + "const_format", + "git2", + "is_debug", + "time", + "tzdb", +] + [[package]] name = "shlex" version = "1.3.0" @@ -5813,7 +5947,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix 1.1.3", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -5885,6 +6019,39 @@ dependencies = [ "zune-jpeg 0.4.21", ] +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -6106,6 +6273,32 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "tz-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14eff19b8dc1ace5bf7e4d920b2628ae3837f422ff42210cb1567cbf68b5accf" + +[[package]] +name = "tzdb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d4e985b6dda743ae7fd4140c28105316ffd75bc58258ee6cc12934e3eb7a0c" +dependencies = [ + "iana-time-zone", + "tz-rs", + "tzdb_data", +] + +[[package]] +name = "tzdb_data" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42302a846dea7ab786f42dc5f519387069045acff793e1178d9368414168fe95" +dependencies = [ + "tz-rs", +] + [[package]] name = "ucd-trie" version = "0.1.7" @@ -6135,6 +6328,27 @@ dependencies = [ "winapi", ] +[[package]] +name = "ufmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a64846ec02b57e9108d6469d98d1648782ad6bb150a95a9baac26900bbeab9d" +dependencies = [ + "ufmt-macros", + "ufmt-write", +] + +[[package]] +name = "ufmt-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d337d3be617449165cb4633c8dece429afd83f84051024079f97ad32a9663716" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ufmt-write" version = "0.1.0" @@ -6376,6 +6590,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" diff --git a/firmware2/Cargo.toml b/firmware2/Cargo.toml index dbb7cb7..afdceeb 100644 --- a/firmware2/Cargo.toml +++ b/firmware2/Cargo.toml @@ -49,6 +49,11 @@ itertools = { version = "0.14.0", default-features = false } bytemuck = "1.24.0" slint = { version = "1.14.1", default-features = false, features = ["compat-1-2", "libm", "log", "unsafe-single-threaded", "renderer-software"]} critical-section = "1.2.0" +shadow-rs = { version = "1.5.0", default-features = false } + +# Crates for serial UART CLI +embedded-cli = { version = "0.2.1", default-features = false, features = ["help", "macros"] } +embedded-io = "0.6.1" [build-dependencies] xz2 = "0.1.7" @@ -57,6 +62,7 @@ const-gen = "1.6" embuild = "0.33" cc = "1.2.9" slint-build = "1.14.1" +shadow-rs = { version = "1.5.0", features = ["no_std"]} [[bin]] name = "acid-firmware" diff --git a/firmware2/build.rs b/firmware2/build.rs index 3734adc..7cc70be 100644 --- a/firmware2/build.rs +++ b/firmware2/build.rs @@ -6,8 +6,14 @@ use std::{env, fs}; use const_gen::*; use slint_build::{CompilerConfiguration, EmbedResourcesKind}; use xz2::read::XzEncoder; +use shadow_rs::ShadowBuilder; fn main() { + ShadowBuilder::builder() + .deny_const(Default::default()) + .build() + .unwrap(); + // Generate vial config at the root of project println!("cargo:rerun-if-changed=vial.json"); generate_vial_config(); diff --git a/firmware2/src/console.rs b/firmware2/src/console.rs index 5cf74aa..eb9fe75 100644 --- a/firmware2/src/console.rs +++ b/firmware2/src/console.rs @@ -1,14 +1,60 @@ -use esp_hal::{Async, uart::UartRx}; +use core::fmt::write; + +use embedded_cli::cli::CliBuilder; +use embedded_cli::Command; +use esp_hal::{Async, uart::{TxError, UartRx}}; use log::{debug, info, error}; +use crate::logging::with_uart_tx; + +struct Writer; + +impl embedded_io::ErrorType for Writer { + type Error = TxError; +} + +impl embedded_io::Write for Writer { + fn write(&mut self, buf: &[u8]) -> Result { + with_uart_tx(|_, uart| { + uart.write(buf) + }) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + with_uart_tx(|_, uart| { + uart.flush() + }) + } +} + +#[derive(Command)] +enum Base/*<'a>*/ { + // /// Say hello to World or someone else + // Hello { + // /// To whom to say hello (World by default) + // name: Option<&'a str>, + // }, + + /// Display the version of the firmware. + Version, + + /// Stop CLI and exit. + Reset, +} + pub async fn run_console(mut uart_rx: UartRx<'_, Async>) { let mut buf = [0_u8; 32]; + let command_buffer = [0_u8; 32]; + let mut cli = CliBuilder::default() + .writer(Writer) + .command_buffer(command_buffer) + .prompt("") + .build() + .unwrap(); info!("Debugging console opened."); loop { - use log::warn; - let len = match uart_rx.read_async(&mut buf[..]).await { Ok(len) => len, Err(error) => { @@ -16,22 +62,26 @@ pub async fn run_console(mut uart_rx: UartRx<'_, Async>) { continue; } }; - let mut read_data = match str::from_utf8(&buf[0..len]) { - Ok(utf8) => utf8, - Err(error) => { - error!("Failed to parse data from the UART port as UTF-8: {error:?}"); - continue; - } - }; - debug!("Read from alt UART: {read_data:?}"); - - match read_data.trim() { - "reset" | "reboot" | "rst" | "r" => { - info!("Performing software reset."); - esp_hal::system::software_reset(); - } - _ => warn!("Command not recognized: {read_data:?}"), + for &byte in &buf[0..len] { + cli.process_byte::( + byte, + &mut Base::processor(|cli, command| { + match command { + // Base::Hello { name } => { + // write!(cli.writer(), "Hello, {}", name.unwrap_or("World"))?; + // } + Base::Version => { + cli.writer().write_str(crate::build::CLAP_LONG_VERSION).unwrap(); + } + Base::Reset => { + cli.writer().write_str("Performing software reset.").unwrap(); + esp_hal::system::software_reset(); + } + } + Ok(()) + }), + ).unwrap(); } } } diff --git a/firmware2/src/logging.rs b/firmware2/src/logging.rs index 73ce3b9..09c6cd7 100644 --- a/firmware2/src/logging.rs +++ b/firmware2/src/logging.rs @@ -7,7 +7,7 @@ use alloc::boxed::Box; use alloc::rc::Rc; use alloc::vec; use bt_hci::controller::ExternalController; -use critical_section::Mutex; +use critical_section::{CriticalSection, Mutex}; use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_time::Timer; @@ -53,6 +53,15 @@ use static_cell::StaticCell; static ALT_LOGGER_UART: Mutex>>> = Mutex::new(RefCell::new(None)); +pub fn with_uart_tx(mut f: impl FnOnce(CriticalSection<'_>, &'_ mut UartTx<'static, Blocking>) -> R) -> R { + critical_section::with(|cs| { + let mut uart = ALT_LOGGER_UART.borrow(cs).borrow_mut(); + let mut uart = uart.as_mut().unwrap(); + + (f)(cs, &mut uart) + }) +} + struct AlternativeLogger; impl Log for AlternativeLogger { @@ -64,23 +73,20 @@ impl Log for AlternativeLogger { #[allow(unused)] fn log(&self, record: &log::Record) { - critical_section::with(|cs| { - let mut uart = ALT_LOGGER_UART.borrow(cs).borrow_mut(); - let mut uart = uart.as_mut().unwrap(); - - print_log_record(&mut uart, record); + with_uart_tx(|cs, uart| { + print_log_record(uart, record); }) } fn flush(&self) {} } - const RESET: &str = "\u{001B}[0m"; - const RED: &str = "\u{001B}[31m"; - const GREEN: &str = "\u{001B}[32m"; - const YELLOW: &str = "\u{001B}[33m"; - const BLUE: &str = "\u{001B}[34m"; - const CYAN: &str = "\u{001B}[35m"; +const RESET: &str = "\u{001B}[0m"; +const RED: &str = "\u{001B}[31m"; +const GREEN: &str = "\u{001B}[32m"; +const YELLOW: &str = "\u{001B}[33m"; +const BLUE: &str = "\u{001B}[34m"; +const CYAN: &str = "\u{001B}[35m"; #[cfg(feature = "alt-log")] macro_rules! println { @@ -97,9 +103,7 @@ macro_rules! println { use esp_println::println; fn do_print(args: core::fmt::Arguments<'_>) { - critical_section::with(|cs| { - let mut uart = ALT_LOGGER_UART.borrow(cs).borrow_mut(); - let mut uart = uart.as_mut().unwrap(); + with_uart_tx(|cs, uart| { uart.write_fmt(args).unwrap(); uart.write_str("\n").unwrap(); uart.flush().unwrap(); diff --git a/firmware2/src/main.rs b/firmware2/src/main.rs index 532ced2..f0bac2d 100644 --- a/firmware2/src/main.rs +++ b/firmware2/src/main.rs @@ -4,14 +4,6 @@ extern crate alloc; -mod keymap; -mod matrix; -mod peripherals; -mod vial; -mod ui; -mod logging; -mod console; - use core::alloc::Layout; use core::cell::{OnceCell, RefCell}; use core::fmt::Write; @@ -20,6 +12,7 @@ use core::time::Duration; use alloc::boxed::Box; use alloc::rc::Rc; use alloc::vec; +use shadow_rs::shadow; use bt_hci::controller::ExternalController; use critical_section::Mutex; use embassy_embedded_hal::adapter::BlockingAsync; @@ -71,6 +64,16 @@ use crate::matrix::IoeMatrix; use crate::peripherals::st7701s::St7701s; use crate::vial::{VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID}; +mod keymap; +mod matrix; +mod peripherals; +mod vial; +mod ui; +mod logging; +mod console; + +shadow!(build); + // This creates a default app-descriptor required by the esp-idf bootloader. // For more information see: esp_bootloader_esp_idf::esp_app_desc!(); @@ -299,7 +302,6 @@ async fn main(_spawner: Spawner) { ); join_all![ - alt_uart_rx_task, // We currently send the framebuffer data using the main core, which does not seem to slow // down the rest of the tasks too much. run_lcd(st7701s, framebuffer), @@ -315,7 +317,8 @@ async fn main(_spawner: Spawner) { &stack, &mut storage, rmk_config, - ) + ), + alt_uart_rx_task ] .await; }