From d5e14965422af55bec949196a9c9af2f2f40e614 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 7 Nov 2025 12:30:27 +0000 Subject: [PATCH 1/7] Update qemu-run so we can publish it and use it in the training examples. --- firmware/qemu/.cargo/config.toml | 2 +- qemu-run/Cargo.toml | 9 ++- qemu-run/README.md | 48 +++++++++++ qemu-run/src/main.rs | 132 ++++++++++++++++++++++++------- 4 files changed, 161 insertions(+), 30 deletions(-) create mode 100644 qemu-run/README.md diff --git a/firmware/qemu/.cargo/config.toml b/firmware/qemu/.cargo/config.toml index 58df65a7..97487aac 100644 --- a/firmware/qemu/.cargo/config.toml +++ b/firmware/qemu/.cargo/config.toml @@ -5,7 +5,7 @@ rrb = "-q run --target thumbv7m-none-eabi --release --bin" [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" -runner = "cargo -q run --manifest-path ../../qemu-run/Cargo.toml" +runner = "cargo -q run --manifest-path ../../qemu-run/Cargo.toml -- --machine lm3s6965evb --verbose" rustflags = [ # LLD (shipped with the Rust toolchain) is used as the default linker diff --git a/qemu-run/Cargo.toml b/qemu-run/Cargo.toml index 5450838c..d8ddba73 100644 --- a/qemu-run/Cargo.toml +++ b/qemu-run/Cargo.toml @@ -1,11 +1,16 @@ [package] authors = ["The Knurling-rs developers"] +categories = ["embedded"] +description = "Runs qemu-system-arm but decodes defmt data sent to semihosting" edition = "2021" +keywords = ["knurling", "logging", "formatting", "qemu"] license = "MIT OR Apache-2.0" name = "qemu-run" -publish = false -version = "0.0.0" +readme = "README.md" +repository = "https://github.com/knurling-rs/defmt" +version = "0.1.0" [dependencies] anyhow = "1" +clap = { version = "4.0", features = ["derive", "env"] } defmt-decoder = { version = "=1.0.0", path = "../decoder" } diff --git a/qemu-run/README.md b/qemu-run/README.md new file mode 100644 index 00000000..9cc88f7b --- /dev/null +++ b/qemu-run/README.md @@ -0,0 +1,48 @@ +# `qemu-run` + +> Runs [`qemu-system-arm`] but decodes [`defmt`] data sent to semihosting + +[`qemu-system-arm`]: https://www.qemu.org/docs/master/system/target-arm.html +[`defmt`]: https://crates.io/crates/defmt + +## Using + +Set as your cargo runner, e.g. in your `.cargo/config.toml` file: + +```toml +[target.thumbv7em-none-eabihf] +runner = "qemu-run -machine lm3s6965evb" +``` + +It will execute `qemu-system-arm`, pass the given `-machine` argument, pass +additional arguments to configure semihosting, and pipe semihosting data into +`defmt-decoder` to be decoded and printed to the console. + +## Support + +`defmt-print` is part of the [Knurling] project, [Ferrous Systems]' effort at +improving tooling used to develop for embedded systems. + +If you think that our work is useful, consider sponsoring it via [GitHub +Sponsors]. + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or + ) + +- MIT license ([LICENSE-MIT](../LICENSE-MIT) or ) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +licensed as above, without any additional terms or conditions. + +[Knurling]: https://knurling.ferrous-systems.com/ +[Ferrous Systems]: https://ferrous-systems.com/ +[GitHub Sponsors]: https://github.com/sponsors/knurling-rs diff --git a/qemu-run/src/main.rs b/qemu-run/src/main.rs index 5ea0c98f..f5e4320a 100644 --- a/qemu-run/src/main.rs +++ b/qemu-run/src/main.rs @@ -1,7 +1,9 @@ +//! # qemu-run +//! //! An alternative to the [`probe-run`](https://github.com/knurling-rs/probe-run) printer, //! used by [`defmt`](https://github.com/knurling-rs/defmt). +//! //! Parses data sent by QEMU over semihosting (ARM Cortex-M only). -//! *Printers* are *host* programs that receive log data, format it and display it. use std::{ env, fs, @@ -10,9 +12,35 @@ use std::{ }; use anyhow::{anyhow, bail}; +use clap::Parser; use defmt_decoder::{DecodeError, StreamDecoder, Table}; use process::Child; +/// Run qemu-system-arm, takes defmt logs from semihosting output and prints them to stdout +#[derive(clap::Parser, Clone)] +#[command(name = "qemu-run")] +struct Opts { + /// The firmware running on the device being logged + #[arg(required = false, conflicts_with("version"))] + elf: Option, + + /// Specify the QEMU machine type + #[arg(long, required = false)] + machine: Option, + + /// Specify the QEMU CPU type + #[arg(long, required = false)] + cpu: Option, + + /// Print the version number, and quit + #[arg(short = 'V', long)] + version: bool, + + /// Print the version number, and quit + #[arg(short = 'v', long)] + verbose: bool, +} + fn main() -> Result<(), anyhow::Error> { notmain().map(|opt_code| { if let Some(code) = opt_code { @@ -22,38 +50,69 @@ fn main() -> Result<(), anyhow::Error> { } fn notmain() -> Result, anyhow::Error> { - let args = env::args().skip(1 /* program name */).collect::>(); + let opts = Opts::parse(); + + if opts.version { + return print_version(); + } + + let Some(elf_path) = opts.elf else { + bail!("ELF filename is required. Syntax: `qemu-run -machine `."); + }; - if args.len() != 1 { - bail!("expected exactly one argument. Syntax: `qemu-run `"); + let Some(machine) = opts.machine else { + bail!("Machine type is required. Syntax: `qemu-run -machine `."); + }; + + if opts.verbose { + eprintln!("QEMU machine is {:?}", machine); + if let Some(cpu) = &opts.cpu { + eprintln!("QEMU cpu is {:?}", cpu); + } } - let path = &args[0]; - let bytes = fs::read(path)?; + let bytes = fs::read(&elf_path)?; let table = if env::var_os("QEMU_RUN_IGNORE_VERSION").is_some() { Table::parse_ignore_version(&bytes) } else { Table::parse(&bytes) }; - let table = table?.ok_or_else(|| anyhow!("`.defmt` section not found"))?; + let table = match table { + Ok(Some(table)) => table, + Ok(None) => { + bail!("Loaded ELF but did not find a .defmt section"); + } + Err(e) => { + bail!("Failed to load ELF: {:?}", e); + } + }; + + let mut command = Command::new("qemu-system-arm"); + command.args([ + "-machine", + &machine, + "-nographic", + "-monitor", + "none", + "-semihosting-config", + "enable=on,target=native", + "-kernel", + ]); + command.arg(elf_path); + command.stdout(Stdio::piped()); + + if let Some(cpu) = &opts.cpu { + command.arg("-cpu"); + command.arg(cpu); + } + + if opts.verbose { + eprintln!("Running: {:?}", command); + } let mut child = KillOnDrop( - Command::new("qemu-system-arm") - .args([ - "-cpu", - "cortex-m3", - "-machine", - "lm3s6965evb", - "-nographic", - "-monitor", - "none", - "-semihosting-config", - "enable=on,target=native", - "-kernel", - ]) - .arg(path) - .stdout(Stdio::piped()) + command .spawn() .expect("Error running qemu-system-arm; perhaps you haven't installed it yet?"), ); @@ -71,24 +130,25 @@ fn notmain() -> Result, anyhow::Error> { loop { let n = stdout.read(&mut readbuf)?; decoder.received(&readbuf[..n]); - decode(&mut *decoder)?; + decode_and_print(decoder.as_mut())?; if let Some(status) = child.0.try_wait()? { + // process finished - grab all remaining bytes and quit exit_code = status.code(); - let mut data = Vec::new(); stdout.read_to_end(&mut data)?; decoder.received(&data); - decode(&mut *decoder)?; - + decode_and_print(decoder.as_mut())?; break; } } + // pass back qemu exit code (if any) Ok(exit_code) } -fn decode(decoder: &mut dyn StreamDecoder) -> Result<(), DecodeError> { +/// Pump the decoder and print any new frames +fn decode_and_print(decoder: &mut dyn StreamDecoder) -> Result<(), DecodeError> { loop { match decoder.decode() { Ok(frame) => { @@ -110,3 +170,21 @@ impl Drop for KillOnDrop { self.0.kill().ok(); } } + +/// Report version from Cargo.toml _(e.g. "0.1.4")_ and supported `defmt`-versions. +/// +/// Used by `--version` flag. +#[allow(clippy::unnecessary_wraps)] +fn print_version() -> anyhow::Result> { + println!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); + let s = if defmt_decoder::DEFMT_VERSIONS.len() > 1 { + "s" + } else { + "" + }; + println!( + "supported defmt version{s}: {}", + defmt_decoder::DEFMT_VERSIONS.join(", ") + ); + Ok(Some(0)) +} From 5a8d9607d1c58deeabd59ccd519ade615b9928d5 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 7 Nov 2025 14:12:38 +0000 Subject: [PATCH 2/7] Add CHANGELOG. Assumes we'll do a 0.1.0 release as soon as this PR merges. --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18c96549..26b7c290 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ We have several packages which live in this repository. Changes are tracked sepa * [defmt-test](#defmt-test) * [defmt-test-macros](#defmt-test-macros) * [defmt-json-schema](#defmt-json-schema) +* [qemu-run](#qemu-run) * [defmt-elf2table](#defmt-elf2table) * [defmt-logger](#defmt-logger) @@ -943,6 +944,21 @@ Initial release Initial release +## qemu-run + +> Runs [`qemu-system-arm`] but decodes [`defmt`] data sent to semihosting + +[qemu-run-next]: https://github.com/knurling-rs/defmt/compare/qemu-run-v0.1.0...main +[qemu-run-v0.1.0]: https://github.com/knurling-rs/defmt/releases/tag/qemu-run-v0.1.0 + +### [qemu-run-next] + +* No changes + +### [qemu-run-v0.1.0] + +Initial release + ## defmt-elf2table > Reads ELF metadata and builds a defmt interner table From 02c40ba9e2befc7be0379bc9ecf645f4f70e0153 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 7 Nov 2025 15:53:29 +0000 Subject: [PATCH 3/7] Better logging from qemu-run Now uses log::info! etc to add host logs, which are mixed with device logs --- Cargo.lock | 4 +- qemu-run/Cargo.toml | 1 + qemu-run/src/main.rs | 176 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 156 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e9b6212..2eecaf0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1005,10 +1005,12 @@ dependencies = [ [[package]] name = "qemu-run" -version = "0.0.0" +version = "0.1.0" dependencies = [ "anyhow", + "clap", "defmt-decoder", + "log", ] [[package]] diff --git a/qemu-run/Cargo.toml b/qemu-run/Cargo.toml index d8ddba73..5e34d044 100644 --- a/qemu-run/Cargo.toml +++ b/qemu-run/Cargo.toml @@ -14,3 +14,4 @@ version = "0.1.0" anyhow = "1" clap = { version = "4.0", features = ["derive", "env"] } defmt-decoder = { version = "=1.0.0", path = "../decoder" } +log = "0.4.28" diff --git a/qemu-run/src/main.rs b/qemu-run/src/main.rs index f5e4320a..af5e779b 100644 --- a/qemu-run/src/main.rs +++ b/qemu-run/src/main.rs @@ -7,13 +7,19 @@ use std::{ env, fs, - io::Read as _, + io::prelude::*, process::{self, Command, Stdio}, }; -use anyhow::{anyhow, bail}; +use anyhow::{anyhow, bail, Context}; use clap::Parser; -use defmt_decoder::{DecodeError, StreamDecoder, Table}; +use defmt_decoder::{ + log::{ + format::{Formatter, FormatterConfig, HostFormatter}, + DefmtLoggerType, + }, + DecodeError, Frame, Locations, StreamDecoder, Table, +}; use process::Child; /// Run qemu-system-arm, takes defmt logs from semihosting output and prints them to stdout @@ -32,6 +38,10 @@ struct Opts { #[arg(long, required = false)] cpu: Option, + /// Custom defmt log format + #[arg(short = 'l', required = false, alias = "log-format")] + log_format: Option, + /// Print the version number, and quit #[arg(short = 'V', long)] version: bool, @@ -65,13 +75,18 @@ fn notmain() -> Result, anyhow::Error> { }; if opts.verbose { - eprintln!("QEMU machine is {:?}", machine); + log::info!("QEMU machine is {:?}", machine); if let Some(cpu) = &opts.cpu { - eprintln!("QEMU cpu is {:?}", cpu); + log::info!("QEMU cpu is {:?}", cpu); } } - let bytes = fs::read(&elf_path)?; + // + // Process the ELF file + // + + let bytes = fs::read(&elf_path) + .with_context(|| format!("Failed to load file {}", elf_path.display()))?; let table = if env::var_os("QEMU_RUN_IGNORE_VERSION").is_some() { Table::parse_ignore_version(&bytes) @@ -87,36 +102,98 @@ fn notmain() -> Result, anyhow::Error> { bail!("Failed to load ELF: {:?}", e); } }; + // check if the locations info contains all the indicies + let locs = table.get_locations(&bytes)?; + let locs = if table.indices().all(|idx| locs.contains_key(&(idx as u64))) { + Some(locs) + } else { + eprintln!("(BUG) location info is incomplete; it will be omitted from the output"); + None + }; - let mut command = Command::new("qemu-system-arm"); - command.args([ - "-machine", - &machine, - "-nographic", - "-monitor", - "none", - "-semihosting-config", - "enable=on,target=native", - "-kernel", - ]); - command.arg(elf_path); - command.stdout(Stdio::piped()); + // + // Configure defmt logging + // + let (mut formatter_config, host_formatter_config) = match &opts.log_format { + Some(config) => ( + FormatterConfig::custom(config), + FormatterConfig::custom(config), + ), + None => (FormatterConfig::default(), FormatterConfig::default()), + }; + formatter_config.is_timestamp_available = table.has_timestamp(); + let formatter = Formatter::new(formatter_config); + let host_formatter = HostFormatter::new(host_formatter_config); + defmt_decoder::log::init_logger(formatter, host_formatter, DefmtLoggerType::Stdout, |_| true); + // + // Open the TCP Server for UART traffic + // + + let uart_socket = std::net::TcpListener::bind("localhost:0") + .with_context(|| "Binding free port on localhost")?; + let uart_socket_addr = uart_socket + .local_addr() + .with_context(|| "Getting socket address")?; + if opts.verbose { + log::info!("Bound UART data socket to {:?}", uart_socket_addr); + } + std::thread::spawn(move || { + let _ = print_loop(uart_socket); + }); + + // + // Set up the qemu-system-arm command line + // + + let mut command = Command::new("qemu-system-arm"); + // set the mandatory machine type + command.args(["-machine", &machine]); + // set the optional CPU type if let Some(cpu) = &opts.cpu { command.arg("-cpu"); command.arg(cpu); } + // create a character device connected to `uart_socket` + command.arg("-chardev"); + command.arg(format!( + "socket,id=sock0,server=off,telnet=off,port={},host=localhost", + uart_socket_addr.port() + )); + // send UART0 output to the chardev we just made + command.args(["-serial", "chardev:sock0"]); + // disable the graphical output + command.arg("-nographic"); + // disable the command monitor + command.args(["-monitor", "none"]); + // send semihosting to stdout + command.args(["-semihosting-config", "enable=on,target=native"]); + // set the firmware to load + command.arg("-kernel"); + command.arg(elf_path); + // grab stdout + command.stdout(Stdio::piped()); if opts.verbose { - eprintln!("Running: {:?}", command); + log::debug!("Running: {:?}", command); } + // + // Run QEMU + // + let mut child = KillOnDrop( command .spawn() .expect("Error running qemu-system-arm; perhaps you haven't installed it yet?"), ); + // + // Decode stdout as defmt data + // + + let current_dir = std::env::current_dir()?; + let mut stdout = child .0 .stdout @@ -130,7 +207,7 @@ fn notmain() -> Result, anyhow::Error> { loop { let n = stdout.read(&mut readbuf)?; decoder.received(&readbuf[..n]); - decode_and_print(decoder.as_mut())?; + decode_and_print(decoder.as_mut(), ¤t_dir, &locs)?; if let Some(status) = child.0.try_wait()? { // process finished - grab all remaining bytes and quit @@ -138,7 +215,7 @@ fn notmain() -> Result, anyhow::Error> { let mut data = Vec::new(); stdout.read_to_end(&mut data)?; decoder.received(&data); - decode_and_print(decoder.as_mut())?; + decode_and_print(decoder.as_mut(), ¤t_dir, &locs)?; break; } } @@ -148,11 +225,16 @@ fn notmain() -> Result, anyhow::Error> { } /// Pump the decoder and print any new frames -fn decode_and_print(decoder: &mut dyn StreamDecoder) -> Result<(), DecodeError> { +fn decode_and_print( + decoder: &mut dyn StreamDecoder, + current_dir: &std::path::Path, + locs: &Option, +) -> Result<(), DecodeError> { loop { match decoder.decode() { Ok(frame) => { - println!("{}", frame.display(true)) + let (file, line, mod_path) = location_info(&locs, &frame, ¤t_dir); + defmt_decoder::log::log_defmt(&frame, file.as_deref(), line, mod_path.as_deref()); } Err(DecodeError::UnexpectedEof) => return Ok(()), Err(DecodeError::Malformed) => { @@ -163,6 +245,32 @@ fn decode_and_print(decoder: &mut dyn StreamDecoder) -> Result<(), DecodeError> } } +/// Describes the file, line and module a log message came from +type LocationInfo = (Option, Option, Option); + +/// Get location info for this log message +fn location_info( + locs: &Option, + frame: &Frame, + current_dir: &std::path::Path, +) -> LocationInfo { + let (mut file, mut line, mut mod_path) = (None, None, None); + + let loc = locs.as_ref().map(|locs| locs.get(&frame.index())); + + if let Some(Some(loc)) = loc { + // try to get the relative path, else the full one + let path = loc.file.strip_prefix(current_dir).unwrap_or(&loc.file); + + file = Some(path.display().to_string()); + line = Some(loc.line as u32); + mod_path = Some(loc.module.clone()); + } + + (file, line, mod_path) +} + +/// Wrapper to ensure qemu is cleaned up at the end struct KillOnDrop(Child); impl Drop for KillOnDrop { @@ -188,3 +296,23 @@ fn print_version() -> anyhow::Result> { ); Ok(Some(0)) } + +/// Dumps UTF-8 data received on a socket to stdout, line by line +fn print_loop(socket: std::net::TcpListener) { + for maybe_connection in socket.incoming() { + if let Ok(conn) = maybe_connection { + conn.set_read_timeout(Some(std::time::Duration::from_millis(100))) + .expect("Setting socket timeout"); + let mut reader = std::io::BufReader::new(conn); + loop { + let mut buffer = String::new(); + let Ok(_len) = reader.read_line(&mut buffer) else { + break; + }; + if !buffer.is_empty() { + log::info!("UART got {:?}", buffer); + } + } + } + } +} From 937c514ee94897d7ea0f2bb4803b0d8424621a2a Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 7 Nov 2025 15:53:48 +0000 Subject: [PATCH 4/7] Move "(HOST)" to the end of the line. It looks terrible at the start of the line. --- decoder/src/log/format/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/decoder/src/log/format/mod.rs b/decoder/src/log/format/mod.rs index 7d1f8e70..866f6965 100644 --- a/decoder/src/log/format/mod.rs +++ b/decoder/src/log/format/mod.rs @@ -430,7 +430,7 @@ impl InternalFormatter { DefaultStyle::get_string(with_location, config.is_timestamp_available) .to_string(); if source == Source::Host { - format.insert_str(0, "(HOST) "); + format.push_str(" (HOST)"); } format @@ -441,7 +441,7 @@ impl InternalFormatter { .to_string(); if source == Source::Host { - format.insert_str(0, "(HOST) "); + format.push_str(" (HOST)"); } format From f4a162fc61f4710c4fe6b164efc8c809776af12a Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 7 Nov 2025 16:15:56 +0000 Subject: [PATCH 5/7] Add AArch64 support and telnet server support. --- qemu-run/src/main.rs | 63 ++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/qemu-run/src/main.rs b/qemu-run/src/main.rs index af5e779b..2d8830d6 100644 --- a/qemu-run/src/main.rs +++ b/qemu-run/src/main.rs @@ -46,6 +46,14 @@ struct Opts { #[arg(short = 'V', long)] version: bool, + /// Set up UART0 as a telnet server instead of piping to the console + #[arg(short = 't', long, alias = "uart-telnet")] + uart_telnet: bool, + + /// Use qemu-system-aarch64 instead of qemu-system-arm + #[arg(long)] + aarch64: bool, + /// Print the version number, and quit #[arg(short = 'v', long)] verbose: bool, @@ -126,27 +134,15 @@ fn notmain() -> Result, anyhow::Error> { let host_formatter = HostFormatter::new(host_formatter_config); defmt_decoder::log::init_logger(formatter, host_formatter, DefmtLoggerType::Stdout, |_| true); - // - // Open the TCP Server for UART traffic - // - - let uart_socket = std::net::TcpListener::bind("localhost:0") - .with_context(|| "Binding free port on localhost")?; - let uart_socket_addr = uart_socket - .local_addr() - .with_context(|| "Getting socket address")?; - if opts.verbose { - log::info!("Bound UART data socket to {:?}", uart_socket_addr); - } - std::thread::spawn(move || { - let _ = print_loop(uart_socket); - }); - // // Set up the qemu-system-arm command line // - let mut command = Command::new("qemu-system-arm"); + let mut command = Command::new(if opts.aarch64 { + "qemu-system-aarch64" + } else { + "qemu-system-arm" + }); // set the mandatory machine type command.args(["-machine", &machine]); // set the optional CPU type @@ -155,11 +151,30 @@ fn notmain() -> Result, anyhow::Error> { command.arg(cpu); } // create a character device connected to `uart_socket` - command.arg("-chardev"); - command.arg(format!( - "socket,id=sock0,server=off,telnet=off,port={},host=localhost", - uart_socket_addr.port() - )); + if opts.uart_telnet { + command.arg("-chardev"); + command.arg("socket,id=sock0,server=on,telnet=on,port=4321,host=localhost"); + log::info!( + "Told QEMU to start telnet server on localhost:4321. Connect to interact with UART0." + ); + } else { + let uart_socket = std::net::TcpListener::bind("localhost:0") + .with_context(|| "Binding free port on localhost")?; + let uart_socket_addr = uart_socket + .local_addr() + .with_context(|| "Getting socket address")?; + if opts.verbose { + log::info!("Bound UART data socket to {:?}", uart_socket_addr); + } + std::thread::spawn(move || { + let _ = print_loop(uart_socket); + }); + command.arg("-chardev"); + command.arg(format!( + "socket,id=sock0,server=off,telnet=off,port={},host=localhost", + uart_socket_addr.port() + )); + } // send UART0 output to the chardev we just made command.args(["-serial", "chardev:sock0"]); // disable the graphical output @@ -174,10 +189,6 @@ fn notmain() -> Result, anyhow::Error> { // grab stdout command.stdout(Stdio::piped()); - if opts.verbose { - log::debug!("Running: {:?}", command); - } - // // Run QEMU // From d88cd9e403bdc3fc0d45c3be2cd0bd90f55820a2 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 7 Nov 2025 16:22:41 +0000 Subject: [PATCH 6/7] Resolve clippy lints in qemu-run --- qemu-run/src/main.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/qemu-run/src/main.rs b/qemu-run/src/main.rs index 2d8830d6..20051c0d 100644 --- a/qemu-run/src/main.rs +++ b/qemu-run/src/main.rs @@ -167,7 +167,7 @@ fn notmain() -> Result, anyhow::Error> { log::info!("Bound UART data socket to {:?}", uart_socket_addr); } std::thread::spawn(move || { - let _ = print_loop(uart_socket); + print_loop(uart_socket); }); command.arg("-chardev"); command.arg(format!( @@ -244,7 +244,7 @@ fn decode_and_print( loop { match decoder.decode() { Ok(frame) => { - let (file, line, mod_path) = location_info(&locs, &frame, ¤t_dir); + let (file, line, mod_path) = location_info(locs, &frame, current_dir); defmt_decoder::log::log_defmt(&frame, file.as_deref(), line, mod_path.as_deref()); } Err(DecodeError::UnexpectedEof) => return Ok(()), @@ -310,19 +310,17 @@ fn print_version() -> anyhow::Result> { /// Dumps UTF-8 data received on a socket to stdout, line by line fn print_loop(socket: std::net::TcpListener) { - for maybe_connection in socket.incoming() { - if let Ok(conn) = maybe_connection { - conn.set_read_timeout(Some(std::time::Duration::from_millis(100))) - .expect("Setting socket timeout"); - let mut reader = std::io::BufReader::new(conn); - loop { - let mut buffer = String::new(); - let Ok(_len) = reader.read_line(&mut buffer) else { - break; - }; - if !buffer.is_empty() { - log::info!("UART got {:?}", buffer); - } + for conn in socket.incoming().flatten() { + conn.set_read_timeout(Some(std::time::Duration::from_millis(100))) + .expect("Setting socket timeout"); + let mut reader = std::io::BufReader::new(conn); + loop { + let mut buffer = String::new(); + let Ok(_len) = reader.read_line(&mut buffer) else { + break; + }; + if !buffer.is_empty() { + log::info!("UART got {:?}", buffer); } } } From c93f823a5bf7d5b54d8b4cb4b21af031c35e2958 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 7 Nov 2025 16:40:49 +0000 Subject: [PATCH 7/7] Update snapshot expected outputs. Now that qemu-run uses defmt-decoder's log function rather than "frame.display()", we: * get padding on the log level (so "INFO" is "INFO ") * don't get timestamps in defmt::println! output * get asserts formatted differently This doesn't affect any output our users will see. If anything, it brings the snapshot tests closer in line with what users see currently (as qemu-run was a private internal tool and users use defmt-print or probe-rs). --- firmware/qemu/src/bin/alloc.out | 30 +-- firmware/qemu/src/bin/assert-eq.out | 5 +- firmware/qemu/src/bin/bitflags.out | 24 +- firmware/qemu/src/bin/dbg.out | 2 +- firmware/qemu/src/bin/hints.out | 152 ++++++------ firmware/qemu/src/bin/hints_inner.out | 20 +- firmware/qemu/src/bin/log.out | 336 +++++++++++++------------- firmware/qemu/src/bin/panic_info.out | 2 +- firmware/qemu/src/bin/timestamp.out | 4 +- firmware/qemu/src/bin/unwrap.out | 2 +- 10 files changed, 289 insertions(+), 288 deletions(-) diff --git a/firmware/qemu/src/bin/alloc.out b/firmware/qemu/src/bin/alloc.out index e94e483d..688eeeb1 100644 --- a/firmware/qemu/src/bin/alloc.out +++ b/firmware/qemu/src/bin/alloc.out @@ -1,15 +1,15 @@ -0.000000 INFO Box: 42 -0.000001 INFO Box>: 1337 -0.000002 INFO in nested 123 -0.000003 INFO Box: NestedStruct { a: 170, b: 305419896 } -0.000004 INFO Rc: 42 -0.000005 INFO Arc: 42 -0.000006 INFO Vec: [1, 2, 3, 4] -0.000007 INFO Vec: [-1, 2, 3, 4] -0.000008 INFO Vec>: [-1, 2, 3, 4] -0.000009 INFO Box>: [-1, 2, 3, 4] -0.000010 INFO String: Hello! I'm a heap-allocated String -0.000011 INFO Cow<[u32]>: [1, 2, 3, 4] -0.000012 INFO Cow>: [1, 2, 3, 4] -0.000013 INFO Cow: moo -0.000014 INFO Cow: moo, but allocated +0.000000 INFO Box: 42 +0.000001 INFO Box>: 1337 +0.000002 INFO in nested 123 +0.000003 INFO Box: NestedStruct { a: 170, b: 305419896 } +0.000004 INFO Rc: 42 +0.000005 INFO Arc: 42 +0.000006 INFO Vec: [1, 2, 3, 4] +0.000007 INFO Vec: [-1, 2, 3, 4] +0.000008 INFO Vec>: [-1, 2, 3, 4] +0.000009 INFO Box>: [-1, 2, 3, 4] +0.000010 INFO String: Hello! I'm a heap-allocated String +0.000011 INFO Cow<[u32]>: [1, 2, 3, 4] +0.000012 INFO Cow>: [1, 2, 3, 4] +0.000013 INFO Cow: moo +0.000014 INFO Cow: moo, but allocated diff --git a/firmware/qemu/src/bin/assert-eq.out b/firmware/qemu/src/bin/assert-eq.out index 16e771c4..1e92fb77 100644 --- a/firmware/qemu/src/bin/assert-eq.out +++ b/firmware/qemu/src/bin/assert-eq.out @@ -1,3 +1,4 @@ ERROR panicked at 'assertion failed: `(left == right)`: dev' - left: `41` -right: `43` +diff < left / right > +<41 +>43 diff --git a/firmware/qemu/src/bin/bitflags.out b/firmware/qemu/src/bin/bitflags.out index 913e1dc0..25041ab9 100644 --- a/firmware/qemu/src/bin/bitflags.out +++ b/firmware/qemu/src/bin/bitflags.out @@ -1,12 +1,12 @@ -INFO Flags::empty(): FLAG_0 -INFO Flags::empty(): FLAG_0 (fmt::Debug) -INFO Flags::all(): FLAG_1 | FLAG_2 | FLAG_7 | FLAG_7_COPY -INFO Flags::all(): FLAG_1 | FLAG_2 | FLAG_7 | FLAG_7_COPY (fmt::Debug) -INFO Flags::FLAG_1: FLAG_1 -INFO Flags::FLAG_1: FLAG_1 (fmt::Debug) -INFO Flags::FLAG_7: FLAG_7 | FLAG_7_COPY -INFO Flags::FLAG_7: FLAG_7 | FLAG_7_COPY (fmt::Debug) -INFO LargeFlags::ALL: MSB | ALL | NON_LITERAL -INFO LargeFlags::ALL: MSB | ALL | NON_LITERAL (fmt::Debug) -INFO LargeFlags::empty(): (empty) -INFO LargeFlags::empty(): (empty) (fmt::Debug) +INFO Flags::empty(): FLAG_0 +INFO Flags::empty(): FLAG_0 (fmt::Debug) +INFO Flags::all(): FLAG_1 | FLAG_2 | FLAG_7 | FLAG_7_COPY +INFO Flags::all(): FLAG_1 | FLAG_2 | FLAG_7 | FLAG_7_COPY (fmt::Debug) +INFO Flags::FLAG_1: FLAG_1 +INFO Flags::FLAG_1: FLAG_1 (fmt::Debug) +INFO Flags::FLAG_7: FLAG_7 | FLAG_7_COPY +INFO Flags::FLAG_7: FLAG_7 | FLAG_7_COPY (fmt::Debug) +INFO LargeFlags::ALL: MSB | ALL | NON_LITERAL +INFO LargeFlags::ALL: MSB | ALL | NON_LITERAL (fmt::Debug) +INFO LargeFlags::empty(): (empty) +INFO LargeFlags::empty(): (empty) (fmt::Debug) diff --git a/firmware/qemu/src/bin/dbg.out b/firmware/qemu/src/bin/dbg.out index 3c837487..318f75dd 100644 --- a/firmware/qemu/src/bin/dbg.out +++ b/firmware/qemu/src/bin/dbg.out @@ -1,6 +1,6 @@ TRACE x + 1 = 43 TRACE x - 1 = 41 -INFO the answer is 41 +INFO the answer is 41 TRACE x - 2 = 40 TRACE x + 2 = 44 TRACE diff --git a/firmware/qemu/src/bin/hints.out b/firmware/qemu/src/bin/hints.out index dc32f9bc..488743eb 100644 --- a/firmware/qemu/src/bin/hints.out +++ b/firmware/qemu/src/bin/hints.out @@ -1,76 +1,76 @@ -0.000000 INFO no hint 42 -0.000001 INFO hex 2a -0.000002 INFO hex alt 0x2a -0.000003 INFO HEX 2A -0.000004 INFO HEX alt 0x2A -0.000005 INFO octal 52 -0.000006 INFO octal alt 0o52 -0.000007 INFO binary 101010 -0.000008 INFO binary alt 0b101010 -0.000009 INFO ASCII 42 -0.000010 INFO Debug 42 -0.000011 INFO ---- -0.000012 INFO no-hint 42 -0.000013 INFO hex 2a -0.000014 INFO hex alt 0x2a -0.000015 INFO HEX 2A -0.000016 INFO HEX alt 0x2A -0.000017 INFO octal 52 -0.000018 INFO octal alt 0o52 -0.000019 INFO binary 101010 -0.000020 INFO binary alt 0b101010 -0.000021 INFO ASCII 42 -0.000022 INFO Debug 42 -0.000023 INFO ---- -0.000024 INFO no hint 42 -0.000025 INFO hex 2a -0.000026 INFO hex alt 0x2a -0.000027 INFO HEX 2A -0.000028 INFO HEX alt 0x2A -0.000029 INFO octal 52 -0.000030 INFO octal alt 0o52 -0.000031 INFO binary 101010 -0.000032 INFO binary alt 0b101010 -0.000033 INFO ASCII 42 -0.000034 INFO Debug 42 -0.000035 INFO ---- -0.000036 INFO S1 > S2 101010 -0.000037 INFO ---- -0.000038 INFO no hint [72, 101, 127, 108, 108, 111] -0.000039 INFO hex [48, 65, 7f, 6c, 6c, 6f] -0.000040 INFO hex alt [0x48, 0x65, 0x7f, 0x6c, 0x6c, 0x6f] -0.000041 INFO HEX [48, 65, 7F, 6C, 6C, 6F] -0.000042 INFO HEX alt [0x48, 0x65, 0x7F, 0x6C, 0x6C, 0x6F] -0.000043 INFO octal [110, 145, 177, 154, 154, 157] -0.000044 INFO octal alt [0o110, 0o145, 0o177, 0o154, 0o154, 0o157] -0.000045 INFO binary [1001000, 1100101, 1111111, 1101100, 1101100, 1101111] -0.000046 INFO binary alt [0b1001000, 0b1100101, 0b1111111, 0b1101100, 0b1101100, 0b1101111] -0.000047 INFO ASCII b"He\x7fllo" -0.000048 INFO Debug [72, 101, 127, 108, 108, 111] -0.000049 INFO ---- -0.000050 INFO b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" -0.000051 INFO b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" -0.000052 INFO ---- -0.000053 INFO no hint Hello -0.000054 INFO Debug "Hello" -0.000055 INFO no hint world -0.000056 INFO Debug "world" -0.000057 INFO ---- -0.000058 INFO no hint 10 -0.000059 INFO hex a -0.000060 INFO hex 0xa -0.000061 INFO HEX A -0.000062 INFO HEX 0xA -0.000063 INFO octal 12 -0.000064 INFO octal 0o12 -0.000065 INFO binary 1010 -0.000066 INFO binary 0b1010 -0.000067 INFO ASCII b"\n" -0.000068 INFO Debug 10 -0.000069 INFO ISO8601 2021-04-20T09:23:44.804Z -0.000070 INFO ISO8601 +53271-03-27T11:46:44Z -0.000071 INFO Sec ms 1234.567 -0.000072 INFO Sec us 1.234567 -0.000073 INFO Time s 14:06:56:07 -0.000074 INFO Time ms 00:20:34.567 -0.000075 INFO Time us 00:00:01.234567 +0.000000 INFO no hint 42 +0.000001 INFO hex 2a +0.000002 INFO hex alt 0x2a +0.000003 INFO HEX 2A +0.000004 INFO HEX alt 0x2A +0.000005 INFO octal 52 +0.000006 INFO octal alt 0o52 +0.000007 INFO binary 101010 +0.000008 INFO binary alt 0b101010 +0.000009 INFO ASCII 42 +0.000010 INFO Debug 42 +0.000011 INFO ---- +0.000012 INFO no-hint 42 +0.000013 INFO hex 2a +0.000014 INFO hex alt 0x2a +0.000015 INFO HEX 2A +0.000016 INFO HEX alt 0x2A +0.000017 INFO octal 52 +0.000018 INFO octal alt 0o52 +0.000019 INFO binary 101010 +0.000020 INFO binary alt 0b101010 +0.000021 INFO ASCII 42 +0.000022 INFO Debug 42 +0.000023 INFO ---- +0.000024 INFO no hint 42 +0.000025 INFO hex 2a +0.000026 INFO hex alt 0x2a +0.000027 INFO HEX 2A +0.000028 INFO HEX alt 0x2A +0.000029 INFO octal 52 +0.000030 INFO octal alt 0o52 +0.000031 INFO binary 101010 +0.000032 INFO binary alt 0b101010 +0.000033 INFO ASCII 42 +0.000034 INFO Debug 42 +0.000035 INFO ---- +0.000036 INFO S1 > S2 101010 +0.000037 INFO ---- +0.000038 INFO no hint [72, 101, 127, 108, 108, 111] +0.000039 INFO hex [48, 65, 7f, 6c, 6c, 6f] +0.000040 INFO hex alt [0x48, 0x65, 0x7f, 0x6c, 0x6c, 0x6f] +0.000041 INFO HEX [48, 65, 7F, 6C, 6C, 6F] +0.000042 INFO HEX alt [0x48, 0x65, 0x7F, 0x6C, 0x6C, 0x6F] +0.000043 INFO octal [110, 145, 177, 154, 154, 157] +0.000044 INFO octal alt [0o110, 0o145, 0o177, 0o154, 0o154, 0o157] +0.000045 INFO binary [1001000, 1100101, 1111111, 1101100, 1101100, 1101111] +0.000046 INFO binary alt [0b1001000, 0b1100101, 0b1111111, 0b1101100, 0b1101100, 0b1101111] +0.000047 INFO ASCII b"He\x7fllo" +0.000048 INFO Debug [72, 101, 127, 108, 108, 111] +0.000049 INFO ---- +0.000050 INFO b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" +0.000051 INFO b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" +0.000052 INFO ---- +0.000053 INFO no hint Hello +0.000054 INFO Debug "Hello" +0.000055 INFO no hint world +0.000056 INFO Debug "world" +0.000057 INFO ---- +0.000058 INFO no hint 10 +0.000059 INFO hex a +0.000060 INFO hex 0xa +0.000061 INFO HEX A +0.000062 INFO HEX 0xA +0.000063 INFO octal 12 +0.000064 INFO octal 0o12 +0.000065 INFO binary 1010 +0.000066 INFO binary 0b1010 +0.000067 INFO ASCII b"\n" +0.000068 INFO Debug 10 +0.000069 INFO ISO8601 2021-04-20T09:23:44.804Z +0.000070 INFO ISO8601 +53271-03-27T11:46:44Z +0.000071 INFO Sec ms 1234.567 +0.000072 INFO Sec us 1.234567 +0.000073 INFO Time s 14:06:56:07 +0.000074 INFO Time ms 00:20:34.567 +0.000075 INFO Time us 00:00:01.234567 diff --git a/firmware/qemu/src/bin/hints_inner.out b/firmware/qemu/src/bin/hints_inner.out index 4ba5a686..396699bd 100644 --- a/firmware/qemu/src/bin/hints_inner.out +++ b/firmware/qemu/src/bin/hints_inner.out @@ -1,10 +1,10 @@ -0.000000 INFO S1 { x: "hi", y: 0x2a } -0.000001 INFO S2 { x: 0x2a } -0.000002 WARN Debug hint: S { x: "hello", y: 512 } -0.000003 WARN no hint: S { x: "hello", y: 1024 } -0.000004 INFO S2 { s: S1 { x: 0b100, y: 12 }, z: 20 } -0.000005 INFO S2 { s: S1 { x: 0b100, y: 12 }, z: 20 } -0.000006 INFO S2 { s: S1 { x: 0b100, y: 12 }, z: 0x14 } -0.000007 INFO S2 { s: S1 { x: 0b100, y: 12 }, z: 0b10100 } -0.000008 INFO S1 { x: "hi", y: 42 } -0.000009 INFO S1 { x: "hi", y: 0x2a } +0.000000 INFO S1 { x: "hi", y: 0x2a } +0.000001 INFO S2 { x: 0x2a } +0.000002 WARN Debug hint: S { x: "hello", y: 512 } +0.000003 WARN no hint: S { x: "hello", y: 1024 } +0.000004 INFO S2 { s: S1 { x: 0b100, y: 12 }, z: 20 } +0.000005 INFO S2 { s: S1 { x: 0b100, y: 12 }, z: 20 } +0.000006 INFO S2 { s: S1 { x: 0b100, y: 12 }, z: 0x14 } +0.000007 INFO S2 { s: S1 { x: 0b100, y: 12 }, z: 0b10100 } +0.000008 INFO S1 { x: "hi", y: 42 } +0.000009 INFO S1 { x: "hi", y: 0x2a } diff --git a/firmware/qemu/src/bin/log.out b/firmware/qemu/src/bin/log.out index e8c8e2fd..95cd4451 100644 --- a/firmware/qemu/src/bin/log.out +++ b/firmware/qemu/src/bin/log.out @@ -1,171 +1,171 @@ -INFO Hello! -INFO World! -INFO The answer is 42 -INFO Hello 42 42! -INFO Hello 256 42 false -INFO 🍕 slice [3, 14] -INFO 🍕 array [3, 14, 1] -INFO float like a butterfly 5.67 5.67 -INFO double like a butterfly 5.000000000000067 5.000000000000067 -INFO Hello 42 -INFO Hex lower ff, fffe, fffffffd, fffffffffffffffc, fffffffffffffffffffffffffffffffb -INFO Hex lower 0xff, 0xfffe, 0xfffffffd, 0xfffffffffffffffc, 0xfffffffffffffffffffffffffffffffb -INFO Hex upper FF, FFFE, FFFFFFFD, FFFFFFFFFFFFFFFC, FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB -INFO Hex upper 0xFF, 0xFFFE, 0xFFFFFFFD, 0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB -INFO Hex unsigned 0001, 0x000002, 30d40, 0x00000004, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -INFO u64: 0 = 0, 1 = 1, MAX = 18446744073709551615, MIN = 0 -INFO i64: 0 = 0, -1 = -1, MAX = 9223372036854775807, MIN = -9223372036854775808 -INFO isize: 0 = 0, -1 = -1, MAX = 2147483647, MIN = -2147483648 -INFO isize: 0 = 0, -1 = -1, MAX = 2147483647, MIN = -2147483648 -INFO usize: 0 = 0, MAX = 4294967295 -INFO bitfields 6 2 +INFO Hello! +INFO World! +INFO The answer is 42 +INFO Hello 42 42! +INFO Hello 256 42 false +INFO 🍕 slice [3, 14] +INFO 🍕 array [3, 14, 1] +INFO float like a butterfly 5.67 5.67 +INFO double like a butterfly 5.000000000000067 5.000000000000067 +INFO Hello 42 +INFO Hex lower ff, fffe, fffffffd, fffffffffffffffc, fffffffffffffffffffffffffffffffb +INFO Hex lower 0xff, 0xfffe, 0xfffffffd, 0xfffffffffffffffc, 0xfffffffffffffffffffffffffffffffb +INFO Hex upper FF, FFFE, FFFFFFFD, FFFFFFFFFFFFFFFC, FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB +INFO Hex upper 0xFF, 0xFFFE, 0xFFFFFFFD, 0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB +INFO Hex unsigned 0001, 0x000002, 30d40, 0x00000004, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +INFO u64: 0 = 0, 1 = 1, MAX = 18446744073709551615, MIN = 0 +INFO i64: 0 = 0, -1 = -1, MAX = 9223372036854775807, MIN = -9223372036854775808 +INFO isize: 0 = 0, -1 = -1, MAX = 2147483647, MIN = -2147483648 +INFO isize: 0 = 0, -1 = -1, MAX = 2147483647, MIN = -2147483648 +INFO usize: 0 = 0, MAX = 4294967295 +INFO bitfields 6 2 TRACE log trace DEBUG log debug -INFO log info -WARN log warn +INFO log info +WARN log warn ERROR log error -INFO S { x: 1, y: 256 } -INFO X { y: Y { z: 42 } } -INFO &str = string slice -INFO &str = string slice -INFO &Str = interned string -INFO &Str = interned string -INFO Arr { arr1: [31], arr0: [], arr32: [85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85] } -INFO [256, 257, 258] -INFO [S { x: 128, y: 256 }, S { x: 129, y: 257 }] -INFO [X { y: Y { z: 128 } }, X { y: Y { z: 129 } }] -INFO [[256, 257, 258], [259, 260]] -INFO e1=A -INFO e2=B -INFO e3=Some(42) -INFO e4=None -INFO e5=Ok(42) -INFO e6=Err(256) -INFO e7=Some(X { y: Y { z: 42 } }) -INFO true Flags { a: true, b: false, c: true } -INFO [true, true, false] -INFO usize slice: [1, 2, 3] -INFO isize slice: [-1, -2, -3] -INFO S { x: 42, y: 43 } -INFO S { x: 44, y: 45 } -INFO S { x: 46, y: Some(47) } -INFO S { x: Some(48), y: 49 } -INFO A -INFO B(42) -INFO C { y: 43 } -INFO A -INFO B(44) -INFO C { y: 45 } -INFO A -INFO B(Some(46)) -INFO C { y: Ok(47) } -INFO A -INFO B(Some(48)) -INFO C { y: 49 } -INFO [None, Some(42)] -INFO [Ok(42), Err(43)] -INFO [A, B(42)] -INFO [S { x: 42, y: None }, S { x: 43, y: Some(44) }] -INFO [None, Some(S { x: 42, y: 256 })] -INFO [None, Some([42, 43])] -INFO in nested 123 -INFO after nested log: NestedStruct { a: 170, b: 305419896 } -INFO I can now print the @ symbol! -INFO @nd @lso vi@ interned strings: this is @n interned string -INFO empty tuple: () -INFO tuple of ints: (1, 2, 3) -INFO nested tuple of ints: (1, 2, (3, 4, 5), (6, 7, 8)) -INFO super nested tuples: (((((((())))))), (((((((), ()))))))) -INFO slice of tuples: [(1, 2), (3, 4), (5, 6)] -INFO tuple of slices: ([1, 2, 3], [4, 5, 6]) -INFO tuple of [u8;4]: ([1, 2, 3, 4], [5, 6, 7, 8]) -INFO [u8;0]: [] -INFO [u8;4]: [1, 2, 3, 4] -INFO [i8;4]: [-1, 2, 3, -4] -INFO [(u32,u32);4]: [(1, 2), (3, 4), (5, 6), (7, 8)] -INFO [u8;0]: [] -INFO [u8;4]: [1, 2, 3, 4] -INFO [i8;4]: [-1, 2, 3, -4] -INFO [u32;4]: [1, 2, 3, 4] -INFO [i32;4]: [-1, 2, 3, -4] -INFO [[u32;4];4]: [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]] -INFO [Option;4]: [Some(1), None, Some(3), None] -INFO [(u32,u32);4]: [(1, 2), (3, 4), (5, 6), (7, 8)] -INFO [u8; 33]: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] -INFO 1-variant enum: A { fld: 123 } -INFO wrapped: A(A { fld: 200 }) -INFO (A(true), B(true)), (A(false), B(true)), (A(true), B(false)) -INFO true, [1, 2]: DhcpReprMin { broadcast: true, a: [1, 2] } -INFO nested `Format` impls using `write!`: outer value (inner value (42)) -INFO manual `Format` impl with multiple `write!`: MyMultiStruct@0 IS ZERO -INFO manual `Format` impl with multiple `write!`: MyMultiStruct@20 IS NOT ZERO, division result: 5 -INFO S { x: -1, y: 2 } -INFO Some(S { x: -1, y: 2 }) -INFO [S { x: -1, y: 2 }, S { x: -1, y: 2 }] -INFO [Some(S { x: -1, y: 2 }), None] -INFO 127.0.0.1:8888 -INFO i128: 0 = 0, -1 = -1, MAX = 170141183460469231731687303715884105727, MIN = -170141183460469231731687303715884105728 -INFO u128: 0 = 0, -1 = 1, MAX = 340282366920938463463374607431768211455, MIN = 0 -INFO 340282366920938 -INFO -170141183460469 -INFO Hello 💜 -INFO Hello 💜 & 🍕 -INFO EnumLarge::A051 -INFO EnumLarge::A269 -INFO S { x: "hi" } -INFO State: 13| -INFO S { x: PhantomData, y: 42 } -INFO bitfields 97 10000100 12 b"42" b"hello" -INFO b"Hi" -INFO b"Hi" -INFO b"Hi" -INFO [45054, 49406] -INFO [Data { name: b"Hi", value: true }] -INFO true true -INFO 0xaabbccdd -INFO 0xddccbbaa -INFO 1..2 -INFO 1.. -INFO ..2 -INFO .. -INFO 1..=2 -INFO ..=2 -INFO Zip(..) -INFO ChunksExact(..) -INFO Iter { slice: [0, 1, 2], position: ? } -INFO Windows(..) -INFO 1 -INFO 1 -INFO 1 -INFO 1 -INFO 1 -INFO 1 -INFO 1 -INFO 1 -INFO 1 -INFO 1 -INFO 1 -INFO 1 -INFO 0xccbbaadd -INFO log data: 43981 -INFO flush! 🚽 -INFO log more data! 🎉 -INFO Cell: Cell { value: 43981 }) -INFO RefCell: RefCell { value: 43981 } -INFO borrowed RefCell: RefCell { value: } -INFO BorrowMutError: BorrowMutError -INFO BorrowError: BorrowError -INFO NonNull: 0xccbbaadd -INFO fn() -> i32: 0xccbbaadd -INFO extern "C" fn() -> i32: 0xccbbaadd -INFO unsafe fn() -> i32: 0xccbbaadd -INFO unsafe extern "C" fn() -> i32: 0xccbbaadd -INFO fn(i32) -> i32: 0xccbbaadd -INFO extern "C" fn(i32) -> i32: 0xccbbaadd -INFO unsafe fn(i32) -> i32: 0xccbbaadd -INFO unsafe extern "C" fn(i32) -> i32: 0xccbbaadd -INFO fn(i32, i32, i32, i32, i32) -> i32: 0xccbbaadd -INFO extern "C" fn(i32, i32, i32, i32, i32) -> i32: 0xccbbaadd -INFO unsafe fn(i32, i32, i32, i32, i32) -> i32: 0xccbbaadd -INFO unsafe extern "C" fn(i32, i32, i32, i32, i32) -> i32: 0xccbbaadd -INFO QEMU test finished! +INFO S { x: 1, y: 256 } +INFO X { y: Y { z: 42 } } +INFO &str = string slice +INFO &str = string slice +INFO &Str = interned string +INFO &Str = interned string +INFO Arr { arr1: [31], arr0: [], arr32: [85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85] } +INFO [256, 257, 258] +INFO [S { x: 128, y: 256 }, S { x: 129, y: 257 }] +INFO [X { y: Y { z: 128 } }, X { y: Y { z: 129 } }] +INFO [[256, 257, 258], [259, 260]] +INFO e1=A +INFO e2=B +INFO e3=Some(42) +INFO e4=None +INFO e5=Ok(42) +INFO e6=Err(256) +INFO e7=Some(X { y: Y { z: 42 } }) +INFO true Flags { a: true, b: false, c: true } +INFO [true, true, false] +INFO usize slice: [1, 2, 3] +INFO isize slice: [-1, -2, -3] +INFO S { x: 42, y: 43 } +INFO S { x: 44, y: 45 } +INFO S { x: 46, y: Some(47) } +INFO S { x: Some(48), y: 49 } +INFO A +INFO B(42) +INFO C { y: 43 } +INFO A +INFO B(44) +INFO C { y: 45 } +INFO A +INFO B(Some(46)) +INFO C { y: Ok(47) } +INFO A +INFO B(Some(48)) +INFO C { y: 49 } +INFO [None, Some(42)] +INFO [Ok(42), Err(43)] +INFO [A, B(42)] +INFO [S { x: 42, y: None }, S { x: 43, y: Some(44) }] +INFO [None, Some(S { x: 42, y: 256 })] +INFO [None, Some([42, 43])] +INFO in nested 123 +INFO after nested log: NestedStruct { a: 170, b: 305419896 } +INFO I can now print the @ symbol! +INFO @nd @lso vi@ interned strings: this is @n interned string +INFO empty tuple: () +INFO tuple of ints: (1, 2, 3) +INFO nested tuple of ints: (1, 2, (3, 4, 5), (6, 7, 8)) +INFO super nested tuples: (((((((())))))), (((((((), ()))))))) +INFO slice of tuples: [(1, 2), (3, 4), (5, 6)] +INFO tuple of slices: ([1, 2, 3], [4, 5, 6]) +INFO tuple of [u8;4]: ([1, 2, 3, 4], [5, 6, 7, 8]) +INFO [u8;0]: [] +INFO [u8;4]: [1, 2, 3, 4] +INFO [i8;4]: [-1, 2, 3, -4] +INFO [(u32,u32);4]: [(1, 2), (3, 4), (5, 6), (7, 8)] +INFO [u8;0]: [] +INFO [u8;4]: [1, 2, 3, 4] +INFO [i8;4]: [-1, 2, 3, -4] +INFO [u32;4]: [1, 2, 3, 4] +INFO [i32;4]: [-1, 2, 3, -4] +INFO [[u32;4];4]: [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]] +INFO [Option;4]: [Some(1), None, Some(3), None] +INFO [(u32,u32);4]: [(1, 2), (3, 4), (5, 6), (7, 8)] +INFO [u8; 33]: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +INFO 1-variant enum: A { fld: 123 } +INFO wrapped: A(A { fld: 200 }) +INFO (A(true), B(true)), (A(false), B(true)), (A(true), B(false)) +INFO true, [1, 2]: DhcpReprMin { broadcast: true, a: [1, 2] } +INFO nested `Format` impls using `write!`: outer value (inner value (42)) +INFO manual `Format` impl with multiple `write!`: MyMultiStruct@0 IS ZERO +INFO manual `Format` impl with multiple `write!`: MyMultiStruct@20 IS NOT ZERO, division result: 5 +INFO S { x: -1, y: 2 } +INFO Some(S { x: -1, y: 2 }) +INFO [S { x: -1, y: 2 }, S { x: -1, y: 2 }] +INFO [Some(S { x: -1, y: 2 }), None] +INFO 127.0.0.1:8888 +INFO i128: 0 = 0, -1 = -1, MAX = 170141183460469231731687303715884105727, MIN = -170141183460469231731687303715884105728 +INFO u128: 0 = 0, -1 = 1, MAX = 340282366920938463463374607431768211455, MIN = 0 +INFO 340282366920938 +INFO -170141183460469 +INFO Hello 💜 +INFO Hello 💜 & 🍕 +INFO EnumLarge::A051 +INFO EnumLarge::A269 +INFO S { x: "hi" } +INFO State: 13| +INFO S { x: PhantomData, y: 42 } +INFO bitfields 97 10000100 12 b"42" b"hello" +INFO b"Hi" +INFO b"Hi" +INFO b"Hi" +INFO [45054, 49406] +INFO [Data { name: b"Hi", value: true }] +INFO true true +INFO 0xaabbccdd +INFO 0xddccbbaa +INFO 1..2 +INFO 1.. +INFO ..2 +INFO .. +INFO 1..=2 +INFO ..=2 +INFO Zip(..) +INFO ChunksExact(..) +INFO Iter { slice: [0, 1, 2], position: ? } +INFO Windows(..) +INFO 1 +INFO 1 +INFO 1 +INFO 1 +INFO 1 +INFO 1 +INFO 1 +INFO 1 +INFO 1 +INFO 1 +INFO 1 +INFO 1 +INFO 0xccbbaadd +INFO log data: 43981 +INFO flush! 🚽 +INFO log more data! 🎉 +INFO Cell: Cell { value: 43981 }) +INFO RefCell: RefCell { value: 43981 } +INFO borrowed RefCell: RefCell { value: } +INFO BorrowMutError: BorrowMutError +INFO BorrowError: BorrowError +INFO NonNull: 0xccbbaadd +INFO fn() -> i32: 0xccbbaadd +INFO extern "C" fn() -> i32: 0xccbbaadd +INFO unsafe fn() -> i32: 0xccbbaadd +INFO unsafe extern "C" fn() -> i32: 0xccbbaadd +INFO fn(i32) -> i32: 0xccbbaadd +INFO extern "C" fn(i32) -> i32: 0xccbbaadd +INFO unsafe fn(i32) -> i32: 0xccbbaadd +INFO unsafe extern "C" fn(i32) -> i32: 0xccbbaadd +INFO fn(i32, i32, i32, i32, i32) -> i32: 0xccbbaadd +INFO extern "C" fn(i32, i32, i32, i32, i32) -> i32: 0xccbbaadd +INFO unsafe fn(i32, i32, i32, i32, i32) -> i32: 0xccbbaadd +INFO unsafe extern "C" fn(i32, i32, i32, i32, i32) -> i32: 0xccbbaadd +INFO QEMU test finished! diff --git a/firmware/qemu/src/bin/panic_info.out b/firmware/qemu/src/bin/panic_info.out index 4f76222f..31dd6816 100644 --- a/firmware/qemu/src/bin/panic_info.out +++ b/firmware/qemu/src/bin/panic_info.out @@ -1 +1 @@ -INFO PanicInfo: panicked at qemu/src/bin/panic_info.rs:14:5 +INFO PanicInfo: panicked at qemu/src/bin/panic_info.rs:14:5 diff --git a/firmware/qemu/src/bin/timestamp.out b/firmware/qemu/src/bin/timestamp.out index 4efe629f..af883c9f 100644 --- a/firmware/qemu/src/bin/timestamp.out +++ b/firmware/qemu/src/bin/timestamp.out @@ -1,2 +1,2 @@ -It is 10:20:30 true false INFO test true -It is 10:20:30 true false Hello World! +It is 10:20:30 true false INFO test true +Hello World! diff --git a/firmware/qemu/src/bin/unwrap.out b/firmware/qemu/src/bin/unwrap.out index 61a93507..d543f6e8 100644 --- a/firmware/qemu/src/bin/unwrap.out +++ b/firmware/qemu/src/bin/unwrap.out @@ -1,3 +1,3 @@ -INFO The answer is 42 +INFO The answer is 42 ERROR panicked at 'unwrap failed: x' error: `Bar`