Use embedded-cli for console

This commit is contained in:
Jakub Hlusička 2025-12-31 00:54:48 +01:00
parent 47340a63e5
commit 21282033b4
6 changed files with 335 additions and 46 deletions

226
firmware2/Cargo.lock generated
View file

@ -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"

View file

@ -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"

View file

@ -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();

View file

@ -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<usize, Self::Error> {
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::<Base, _>(
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();
}
}
}

View file

@ -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<RefCell<Option<UartTx<'static, Blocking>>>> = Mutex::new(RefCell::new(None));
pub fn with_uart_tx<R>(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();

View file

@ -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: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
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;
}