### Example Output with DEFMT_LOG Source: https://github.com/knurling-rs/defmt/blob/main/book/src/filtering.md These console examples show the output of defmt logging macros when different DEFMT_LOG values are set. The first example shows output with 'warn' enabled, and the second with 'trace' enabled. ```console $ DEFMT_LOG=warn cargo run --bin all-logging-levels WARN warn ERROR error ``` ```console $ DEFMT_LOG=trace cargo run --bin all-logging-levels TRACE trace DEBUG debug INFO info WARN warn ERROR error ``` -------------------------------- ### Run defmt example (release build) Source: https://github.com/knurling-rs/defmt/blob/main/firmware/qemu/README.md Execute the defmt log example using a release build. This command uses a cargo-run alias for the release binary. ```console $ # alias for cargo-run --release --bin as set in .cargo/config $ cargo rrb log (...) 0.000000 INFO Hello! 0.000001 INFO World! (...) ``` -------------------------------- ### Run defmt example (development build) Source: https://github.com/knurling-rs/defmt/blob/main/firmware/qemu/README.md Execute the defmt log example using a development build. This command uses a cargo-run alias for the binary. ```console $ # alias for cargo-run --bin as set in .cargo/config $ cargo rb log (...) 0.000000 INFO Hello! 0.000001 INFO World! (...) ``` -------------------------------- ### Build the defmt book Source: https://github.com/knurling-rs/defmt/blob/main/book/README.md Build the defmt book using the mdbook build command after installation. ```bash $ mdbook build ``` -------------------------------- ### Core Panic Handler Example Source: https://github.com/knurling-rs/defmt/blob/main/book/src/panic.md This is an example of a core panic handler that prints panic information and then resets the system. It is provided for comparison with the `defmt` panic handler. ```rust #[panic_handler] fn core_panic(info: &core::panic::PanicInfo) -> ! { print(info); // e.g. using RTT reset() } ``` -------------------------------- ### Install mdBook Source: https://github.com/knurling-rs/defmt/blob/main/book/README.md Install mdBook version 0.5.1 using cargo. Ensure to use the --locked flag for a reproducible build. ```bash $ cargo install mdbook@0.5.1 --locked ``` -------------------------------- ### Run All Tests with `cargo xtask` Source: https://github.com/knurling-rs/defmt/blob/main/README.md Execute all defined tests using the `cargo xtask` command. Ensure `qemu-system-arm` is installed and in your PATH for certain tests. ```console cargo xtask test-all ``` -------------------------------- ### Defmt-test Execution Log with State Source: https://github.com/knurling-rs/defmt/blob/main/firmware/defmt-test/README.md Example console output demonstrating the execution flow of tests with state management, including `before_each` and `after_each` hooks. ```console $ cargo test -p testsuite 0.000000 (1/2) running `assert_true`... └─ integration::tests::__defmt_test_entry @ tests/integration.rs:37 0.000001 State flag before is true └─ integration::tests::before_each @ tests/integration.rs:26 0.000002 State flag after is true └─ integration::tests::after_each @ tests/integration.rs:32 0.000003 (2/2) running `assert_flag`... └─ integration::tests::__defmt_test_entry @ tests/integration.rs:43 0.000004 State flag before is true └─ integration::tests::before_each @ tests/integration.rs:26 0.000005 State flag after is false └─ integration::tests::after_each @ tests/integration.rs:32 0.000006 all tests passed! └─ integration::tests::__defmt_test_entry @ tests/integration.rs:11 ``` -------------------------------- ### Nested Formatting Example 2 Source: https://github.com/knurling-rs/defmt/blob/main/book/src/custom-log-output.md Shows nested formatting for width and alignment of log segments. This example aligns the file and line number information to a width of 35 characters. Ensure the `{s}` specifier is present. ```text [DEBUG] main.rs:20 hello [DEBUG] goodbye.rs:304 goodbye ``` -------------------------------- ### defmt-print JSON Output Example Source: https://github.com/knurling-rs/defmt/blob/main/book/src/json-output.md Demonstrates the console output when `defmt-print` is run with the `--json` flag. Each line represents a log statement as a JSON object. ```console $ ./capture_data | defmt-print --json ./target/thumbv7m-none-eabi/example.elf {"schema_version":1} {"data":"info","host_timestamp":1643113115873940726,"level":"INFO","location":{"file":"src/bin/levels.rs","line":10,"module_path":{"crate_name":"levels","modules":[],"function":"__cortex_m_rt_main"}},"target_timestamp":"0"} {"data":"warn","host_timestamp":1643113115873952269,"level":"WARN","location":{"file":"src/bin/levels.rs","line":12,"module_path":{"crate_name":"levels","modules":[],"function":"__cortex_m_rt_main"}},"target_timestamp":"1"} {"data":"debug","host_timestamp":1643113115873957827,"level":"DEBUG","location":{"file":"src/bin/levels.rs","line":13,"module_path":{"crate_name":"levels","modules":[],"function":"__cortex_m_rt_main"}},"target_timestamp":"2"} {"data":"error","host_timestamp":1643113115873981443,"level":"ERROR","location":{"file":"src/bin/levels.rs","line":14,"module_path":{"crate_name":"levels","modules":[],"function":"__cortex_m_rt_main"}},"target_timestamp":"3"} {"data":"println","host_timestamp":1643113115873987212,"level":null,"location":{"file":"src/bin/levels.rs","line":15,"module_path":{"crate_name":"levels","modules":[],"function":"__cortex_m_rt_main"}},"target_timestamp":"4"} ``` -------------------------------- ### Basic Display Hints (Hex, Binary) Source: https://github.com/knurling-rs/defmt/blob/main/book/src/hints.md Demonstrates the use of lowercase hexadecimal, uppercase hexadecimal, and binary display hints for unsigned 8-bit integers. Includes an example with the alternate form for hexadecimal. ```rust # extern crate defmt; defmt::info("{=u8:x}", 42); // -> INFO 2a defmt::info("{=u8:X}", 42); // -> INFO 2A defmt::info("{=u8:#x}", 42); // -> INFO 0x2a defmt::info("{=u8:b}", 42); // -> INFO 101010 ``` -------------------------------- ### Get `cargo xtask` Help Source: https://github.com/knurling-rs/defmt/blob/main/README.md Display available options and commands for `cargo xtask`. This command helps in understanding the testing and development utilities provided. ```console cargo xtask help ``` -------------------------------- ### Use `Debug2Format` and `Display2Format` Adapters Source: https://github.com/knurling-rs/defmt/blob/main/book/src/format.md Employ `Debug2Format` or `Display2Format` adapters for uncompressed formatting, useful for quick setups where efficiency is not critical. These adapters use `core::fmt` on-device and disable compression. ```rust # extern crate defmt; # use defmt::Format; # mod serde_json { # #[derive(Debug)] # pub enum Error {} # } #[derive(Format)] enum Error { Serde(#[defmt(Debug2Format)] serde_json::Error), ResponseTooLarge, } # struct Celsius(); # impl std::fmt::Display for Celsius { # fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { Ok(()) } # } #[derive(Format)] struct Reading { #[defmt(Display2Format)] temperature: Celsius, } ``` -------------------------------- ### Logging an Info Message with Timestamp Source: https://github.com/knurling-rs/defmt/blob/main/book/src/log-frame.md This example shows how to log an informational message including a timestamp. The comment indicates the resulting on-the-wire format, showing the string index, timestamp, and argument. ```rust # extern crate defmt; defmt::info!("answer={=u8}", 42); // on the wire: [2, 125, 42] <- arguments // string index ^ ^^^ timestamp ``` -------------------------------- ### Rust Example: Potential Duplicate Symbols in Logging Source: https://github.com/knurling-rs/defmt/blob/main/book/src/duplicates.md Illustrates how multiple calls to the `defmt::info!` macro with identical string literals can lead to duplicate symbols in the generated code. ```rust # extern crate defmt; fn foo() { defmt::info!("foo started .."); // .. defmt::info!(".. DONE"); // <- } fn bar() { defmt::info!("bar started .."); // .. defmt::info!(".. DONE"); // <- } ``` -------------------------------- ### Bitfield Range Inclusivity Example Source: https://github.com/knurling-rs/defmt/blob/main/book/src/bitfields.md Illustrates that bitfield ranges are not inclusive. This example shows how the first three bits (0..3) of the number 254 are extracted and displayed. ```rust # extern crate defmt; // -> TRACE: first three bits: 110 defmt::trace!("first three bits: {0=0..3}", 254u32); ``` -------------------------------- ### Zero Padding for Numbers Source: https://github.com/knurling-rs/defmt/blob/main/book/src/hints.md Demonstrates zero padding for numeric formatting, including examples with and without the alternate form for hexadecimal. ```rust # extern crate defmt; defmt::info("{=u8}", 42); // -> INFO 42 defmt::info("{=u8:04}", 42); // -> INFO 0042 defmt::info("{=u8:08X}", 42); // -> INFO 0000002A defmt::info("{=u8:#08X}", 42); // -> INFO 0x00002A ``` -------------------------------- ### Adapt Logger trait implementation (v0.2) Source: https://github.com/knurling-rs/defmt/blob/main/book/src/migration-02-03.md Example of a manual `Logger` trait implementation in defmt v0.2.x, showing the previous `Write` trait and `acquire`/`release` methods. ```rust,ignore #[defmt::global_logger] struct Logger; static TAKEN: AtomicBool = AtomicBool::new(false); unsafe impl defmt::Logger for Logger { fn acquire() -> Option> { // disable interrupts if !TAKEN.load(Ordering::Relaxed) { // acquire the lock TAKEN.store(true, Ordering::Relaxed); Some(NonNull::from(&Logger as &dyn defmt::Write)) } else { None } } unsafe fn release(_: NonNull) { // release the lock TAKEN.store(false, Ordering::Relaxed); // re-enable interrupts } } impl defmt::Write for Logger { fn write(&mut self, bytes: &[u8]) { unsafe { itm::write_all(&mut (*ITM::ptr()).stim[0], bytes) } } } ``` -------------------------------- ### Adapt Logger trait implementation (v0.3) Source: https://github.com/knurling-rs/defmt/blob/main/book/src/migration-02-03.md Conceptual example of a manual `Logger` trait implementation in defmt v0.3.0, demonstrating the updated signatures and integrated `write` method. ```rust # extern crate cortex_m; # extern crate defmt; # # use std::sync::atomic::{AtomicBool,Ordering}; # use cortex_m::{itm,peripheral::ITM}; ``` -------------------------------- ### Including Log Level and Message Source: https://github.com/knurling-rs/defmt/blob/main/book/src/custom-log-output.md Multiple specifiers can be combined in any order. For example, "[{L}] {s}" prints the log level and the message. ```text [DEBUG] hello ``` -------------------------------- ### Rust Logger Acquire-Release Example Source: https://github.com/knurling-rs/defmt/blob/main/book/src/acq-rel.md Demonstrates how a logger can be acquired and released to prevent re-entrancy. Inner take attempts will silently fail if the logger is already held. This pattern is used to avoid interleaving log frames, which would be treated as corrupted by decoders. ```rust # struct Logger; # impl Logger { # fn acquire() -> Option { None } # fn serialize_interned_string_and_etc(&self) {} # } # fn release(_: T) {} if let Some(logger) = Logger::acquire() { logger.serialize_interned_string_and_etc(); release(logger); // <- logger can be acquired again after this } else { // silent failure: do nothing here } ``` -------------------------------- ### Rust Code Using Defmt Logging Macros Source: https://github.com/knurling-rs/defmt/blob/main/book/src/linker-sections.md Example of using defmt's logging macros to emit messages. These macros will be expanded by the compiler into static definitions that are placed into specific linker sections based on their log level. ```rust # extern crate defmt; defmt::warn!("Hello"); defmt::warn!("Hi"); defmt::error!("Good"); defmt::error!("Bye"); ``` -------------------------------- ### Custom `defmt` Panic Handler Source: https://github.com/knurling-rs/defmt/blob/main/book/src/panic.md This example shows how to define a custom panic handler using `#[defmt::panic_handler]`. It omits the printing part to avoid duplicate messages when `defmt::panic!` is used. ```rust # extern crate defmt; # fn reset() -> ! { todo!() } # #[defmt::panic_handler] fn defmt_panic() -> ! { // leave out the printing part here reset() } ``` -------------------------------- ### defmt Logging with Potential Re-entrancy Source: https://github.com/knurling-rs/defmt/blob/main/book/src/eval-order.md This example shows a defmt::info! macro invocation where a function call is used as a format argument. This can lead to re-entrancy if the function itself performs logging. ```rust # extern crate defmt; defmt::info!("x={=?}", foo()); fn foo() -> u8 { defmt::info!("Hello"); 42 } ``` -------------------------------- ### Serialize Bitfield with Byte Truncation Source: https://github.com/knurling-rs/defmt/blob/main/book/src/ser-bitfield.md Demonstrates how defmt removes leading and trailing bytes that are not needed to display a bitfield. The example shows a u32 serialized into a smaller byte representation. ```rust # extern crate defmt; defmt::error!("m: {0=8..12}", 0b0110_0011_0000_1111_u32); // on the wire: [1, 0b0110_0011] // string index ^ ^^^^^^^^^^ argument truncated into u8: // leading and trailing byte are irrelevant ``` -------------------------------- ### Customizing Log Output with Format Parameters Source: https://github.com/knurling-rs/defmt/blob/main/book/src/custom-log-output.md Format parameters, separated by colons, customize specifiers. Example: "{L:bold:5} {f:white:<10} {s}" applies bold to the log level, white color and left-alignment to the file name, and prints the message. ```text [DEBUG] main.rs: hello ``` -------------------------------- ### Set DEFMT_LOG Environment Variable Source: https://github.com/knurling-rs/defmt/blob/main/book/src/filtering.md Use the DEFMT_LOG environment variable to control which logging levels are enabled. Enabling a level also enables higher severity levels. This example sets the level to 'warn'. ```console $ export DEFMT_LOG=warn $ cargo build --bin app ``` ```console $ DEFMT_LOG=warn cargo run --bin app ``` -------------------------------- ### Override Example Output Source: https://github.com/knurling-rs/defmt/blob/main/book/src/filtering.md This console output illustrates the effect of overriding logging directives. The first directive sets a global trace level, but the second directive overrides `app::inner` to only emit error messages. ```console $ DEFMT_LOG=trace,app::inner=error cargo run --bin app TRACE root trace ERROR inner error ``` -------------------------------- ### String Formatting with Debug Hint Source: https://github.com/knurling-rs/defmt/blob/main/book/src/hints.md Shows how to format a string using the default behavior and the debug-like display hint (`:?`). ```rust # extern crate defmt; defmt::info("{=str}", "hello\tworld"); // -> INFO hello world defmt::info("{=str:?}", "hello\tworld"); // -> INFO "hello\tworld" ``` -------------------------------- ### Basic defmt Logging Source: https://github.com/knurling-rs/defmt/blob/main/book/src/re-entrancy.md Demonstrates a simple use of the `defmt::info!` macro to log a string and a variable. Ensure `defmt` is imported. ```rust # extern crate defmt; # let x = 0u8; defmt::info!("The answer is {=?}!", x /*: Struct */); ``` -------------------------------- ### Adding Arbitrary Text to Log Output Source: https://github.com/knurling-rs/defmt/blob/main/book/src/custom-log-output.md Arbitrary text can be included in the format string, which will be printed with each log. For example, "Log: {s}". ```text Log: hello ``` -------------------------------- ### Compile-time Error: Reusing Argument Source: https://github.com/knurling-rs/defmt/blob/main/book/src/bitfields.md This example demonstrates a compile-time error that occurs when the same argument is used in both a bitfield and a non-bitfield parameter within the same trace call. ```rust # extern crate defmt; defmt::trace!("{0=5..13} {0=u16}", 256u16); ``` -------------------------------- ### Configure qemu-run as Cargo Runner Source: https://github.com/knurling-rs/defmt/blob/main/qemu-run/README.md Set this TOML configuration in your `.cargo/config.toml` file to use `qemu-run` as the default runner for a specific target. This automatically passes machine and CPU configurations to `qemu-run`. ```toml [target.thumbv7em-none-eabihf] runner = "qemu-run --machine lm3s6965evb --cpu cortex-m3" ``` -------------------------------- ### Configure Log Format in .cargo/config.toml Source: https://github.com/knurling-rs/defmt/blob/main/book/src/custom-log-output.md Illustrates how to pass a custom log format string to `probe-rs run` via the `.cargo/config.toml` file. Note the required splitting of the command due to cargo limitations. ```toml # .cargo/config.toml runner = [ "probe-rs", "run", "--chip", "nRF52840_xxAA", "--log-format", "{L} {s}", ] ``` -------------------------------- ### Initialize and Manage Test Suite State Source: https://github.com/knurling-rs/defmt/blob/main/firmware/defmt-test/README.md Use `#[init]` to create shared state before tests run. Access this state in `#[before_each]`, `#[after_each]`, and test functions to manage data across test executions. ```rust // state shared across unit tests struct MyState { flag: bool, } #[defmt_test::tests] mod tests { #[init] fn init() -> super::MyState { // state initial value super::MyState { flag: true, } } // This function is called before each test case. // It accesses the state created in `init`, // though like with `test`, state access is optional. #[before_each] fn before_each(state: &mut super::MyState) { defmt::println!("State flag before is {}", state.flag); } // This function is called after each test #[after_each] fn after_each(state: &mut super::MyState) { defmt::println!("State flag after is {}", state.flag); } // this unit test doesn't access the state #[test] fn assert_true() { assert!(true); } // but this test does #[test] fn assert_flag(state: &mut super::MyState) { assert!(state.flag) state.flag = false; } } ``` -------------------------------- ### Using defmt Logging Macros Source: https://github.com/knurling-rs/defmt/blob/main/book/src/macros.md Demonstrates the usage of info! and debug! macros with arguments. The info! macro logs a message with a length parameter, while debug! logs a formatted representation of a value. ```rust # extern crate defmt; # let len = 80u8; // -> INFO: message arrived (length=80) defmt::info!("message arrived (length={})", len); # struct Message; # impl Message { fn header(&self) -> u8 { 0 } } # let message = Message; // -> DEBUG: Header { source: 2, destination: 3, sequence: 16 } defmt::debug!("{:?}", message.header()); ``` -------------------------------- ### Rust Compile-Fail Example: Duplicate Symbol Error Source: https://github.com/knurling-rs/defmt/blob/main/book/src/duplicates.md Demonstrates a compile-time error in Rust when two static variables are defined with the same exported name, causing a linker conflict. ```rust #[no_mangle] static X: u32 = 0; #[export_name = "X"] static Y: u32 = 0; //~ error: symbol `X` is already defined ``` -------------------------------- ### Compare `{=str}` and `{=istr}` Bandwidth Usage Source: https://github.com/knurling-rs/defmt/blob/main/book/src/istr.md Demonstrates the difference in bandwidth usage between transmitting a full string with `{=str}` and an interned string with `{=istr}`. The `{=istr}` parameter requires an argument of type `defmt::Str`, created using the `intern!` macro. ```rust # extern crate defmt; let s = "The quick brown fox jumps over the lazy dog"; defmt::info!("{=str}", s); // ^ bandwidth-use = 43 bytes ``` ```rust # use defmt::Str; let interned: Str = defmt::intern!("The quick brown fox jumps over the lazy dog"); defmt::info!("{=istr}", interned); // ^^^^^^^^^ bandwidth-use <= 2 bytes ``` -------------------------------- ### Padding Line Numbers with Zeros Source: https://github.com/knurling-rs/defmt/blob/main/book/src/custom-log-output.md The `{l:03}` specifier pads the line number with leading zeros to a minimum width of 3 characters. For example, line 24 is printed as `024`. ```text 024 ``` -------------------------------- ### ASCII Display Hint for Bytes Source: https://github.com/knurling-rs/defmt/blob/main/book/src/hints.md Illustrates formatting a byte array using the ASCII display hint (`:a`), which renders bytes as a Rust byte string literal. ```rust # extern crate defmt; let bytes = [104, 101, 255, 108, 108, 111]; defmt::info("{=[u8]:a}", bytes); // -> INFO b"he\xffllo" ``` -------------------------------- ### Logging Primitive Types with Defmt Source: https://github.com/knurling-rs/defmt/blob/main/book/src/primitives.md Demonstrates how to log boolean and integer types using Defmt's `info!` and `trace!` macros. Arguments are type-checked and can be compressed into a single byte for booleans. ```rust # extern crate defmt; # let enabled = false; # let ready = false; # let timeout = false; // arguments can be compressed into a single byte defmt::info!( "enabled: {=bool}, ready: {=bool}, timeout: {=bool}", enabled, ready, timeout, ); # let x = 0u16; // arguments will be type checked defmt::trace!("{=u16}", x); // ^ must have type `u16` ``` -------------------------------- ### Module Filtering Example Output Source: https://github.com/knurling-rs/defmt/blob/main/book/src/filtering.md This console output demonstrates how module-specific logging directives in DEFMT_LOG affect the filtered messages. Here, `app::important` is set to `info` and `app::noisy` to `error`. ```console $ DEFMT_LOG=app::important=info,app::noisy=error cargo run --bin app INFO important info WARN important warn ERROR important error ERROR noisy error ERROR inner error ``` -------------------------------- ### Display Hints for Byte Slice Elements Source: https://github.com/knurling-rs/defmt/blob/main/book/src/hints.md Shows how individual elements within a byte slice can be formatted using hexadecimal, octal, binary, and ASCII hints, including padding and alternate forms. ```rust # extern crate defmt; let bytes = [4, 101, 5, 108, 6, 111]; defmt::info("{=[u8]}", bytes); // -> INFO [4, 101, 5, 108, 6, 111] defmt::info("{=[u8]:x}", bytes); // -> INFO [4, 65, 5, 6c, 6, 6f] defmt::info("{=[u8]:#04x}", bytes); // -> INFO [0x04, 0x65, 0x05, 0x6c, 0x06, 0x6f] defmt::info("{=[u8]:#010b}", bytes); // -> INFO [0b00000100, 0b01100101, 0b00000101, 0b01101100, 0b00000110, 0b01101111] ``` -------------------------------- ### Alternate Printing with Base Indicators Source: https://github.com/knurling-rs/defmt/blob/main/book/src/hints.md Shows how to use the `#` flag with binary, octal, and hexadecimal hints to prepend base indicators (e.g., `0b`, `0o`, `0x`). ```rust # extern crate defmt; defmt::info("{=u8:b}", 42); // -> INFO 101010 defmt::info("{=u8:#b}", 42); // -> INFO 0b101010 defmt::info("{=u8:o}", 42); // -> INFO 52 defmt::info("{=u8:#o}", 42); // -> INFO 0o52 defmt::info("{=u8:x}", 42); // -> INFO 2a defmt::info("{=u8:#x}", 42); // -> INFO 0x2a defmt::info("{=u8:X}", 42); // -> INFO 2A defmt::info("{=u8:#X}", 42); // -> INFO 0x2A ``` -------------------------------- ### CBOR Display Hint for Byte Slices Source: https://github.com/knurling-rs/defmt/blob/main/book/src/hints.md Demonstrates formatting a byte slice containing CBOR encoded data using the `:cbor` hint, rendering it in EDN format. ```rust # extern crate defmt; # fn parse(slice: &[u8]) -> Result<(), ()> { # Ok(()) # } # fn main() -> Result<(), ()> { let id_cred = [0xa1, 0x04, 0x44, 0x6b, 0x69, 0x64, 0x31].as_slice(); defmt::info!("Peer ID: {=[u8]:cbor}", id_cred); // -> INFO Peer ID: {4: 'kid1'} let parsed = parse(id_cred)?; # Ok(()) # } ``` -------------------------------- ### Configuring `Cargo.toml` for `defmt-test` Source: https://github.com/knurling-rs/defmt/blob/main/firmware/defmt-test/README.md To add `defmt-test` to an existing project, set `harness = false` for the library and any test crates in `Cargo.toml` to disable the default test harness. ```toml # Cargo.toml # for the library crate (src/lib.rs) [lib] harness = false # for each crate in the `tests` directory [[test]] name = "test-name" # tests/test-name.rs harness = false [[test]] name = "second" # tests/second.rs harness = false ``` -------------------------------- ### Disable Logs with 'off' Source: https://github.com/knurling-rs/defmt/blob/main/book/src/filtering.md The 'off' logging level can be used in DEFMT_LOG to disable logs globally, for a specific crate, or for a specific module. These examples show disabling logs globally, from a dependency crate, and from a local module. ```console $ # globally disable logs $ DEFMT_LOG=off cargo run --bin app ``` ```console $ # disable logs from the `noisy` crate (dependency) $ DEFMT_LOG=trace,noisy=off cargo run --bin app ``` ```console $ # disable logs from the `noisy` module $ DEFMT_LOG=trace,app::noisy=off cargo run --bin app ``` -------------------------------- ### Display Hint Propagation in Structs Source: https://github.com/knurling-rs/defmt/blob/main/book/src/hints.md Illustrates how display hints applied to a struct's formatting parameter can propagate to its fields if they do not have their own explicit hints. ```rust # extern crate defmt; #[derive(defmt::Format)] struct S { x: u8 } let x = S { x: 42 }; defmt::info("{}", x); // -> INFO S { x: 42 } defmt::info("{:#x}", x); // -> INFO S { x: 0x2a } ``` -------------------------------- ### Running Library Unit Tests Source: https://github.com/knurling-rs/defmt/blob/main/firmware/defmt-test/README.md Execute library unit tests using `cargo test --lib`. This command runs `#[test]` functions within the library crate (`src/lib.rs`). ```console $ cargo test --lib (..) (1/1) running `it_works`... └─ app::unit_tests::__defmt_test_entry @ src/lib.rs:33 all tests passed! └─ app::unit_tests::__defmt_test_entry @ src/lib.rs:28 (..) (HOST) INFO device halted without error ``` -------------------------------- ### Basic Bool Compression Source: https://github.com/knurling-rs/defmt/blob/main/book/src/ser-bool.md Demonstrates the basic serialization of multiple booleans. The first boolean in a sequence allocates a byte, and subsequent booleans are packed into it. ```rust # extern crate defmt; defmt::error!("x: {=bool}, y: {=bool}, z: {=bool}", false, false, true); // on the wire: [1, 0b001] // string index ^ ^^^^^ the booleans: `0bxyz` ``` -------------------------------- ### Override Logging Directives Source: https://github.com/knurling-rs/defmt/blob/main/book/src/filtering.md This Rust code shows how later logging directives in DEFMT_LOG can override earlier ones. This example sets a global trace level and then overrides the `app::inner` module to only show errors. ```rust # extern crate defmt; // crate-name = app pub fn function() { defmt::trace!("root trace"); } mod inner { pub fn function() { defmt::trace!("inner trace"); defmt::error!("inner error"); } } function(); inner::function(); ``` -------------------------------- ### Overriding Display Hints in Custom Formatters Source: https://github.com/knurling-rs/defmt/blob/main/book/src/hints.md Shows how to define a custom `Format` implementation for a struct, allowing specific fields to have overridden display hints, while others inherit. ```rust # extern crate defmt; struct S { x: u8, y: u8 } impl defmt::Format for S { fn format(&self, f: defmt::Formatter) { // `y`'s display hint cannot be overridden (see below) defmt::write!(f, "S {{ x: {=u8}, y: {=u8:x} }}", self.x, self.y) } } let x = S { x: 42, y: 42 }; defmt::info("{}", x); // -> INFO S { x: 42, y: 2a } defmt::info("{:b}", x); // -> INFO S { x: 101010, y: 2a } ``` -------------------------------- ### Defmt Linker Script for Logging Levels Source: https://github.com/knurling-rs/defmt/blob/main/book/src/linker-sections.md This linker script defines how defmt sections are organized in memory. It clusters log strings by severity (ERROR, WARN, INFO, DEBUG, TRACE) and creates symbols to mark the boundaries between these clusters. ```text SECTIONS { .defmt (INFO) : 0 { *(.defmt.error.*); /* cluster of ERROR level log strings */ _defmt_warn = .; /* creates a symbol between the clusters */ *(.defmt.warn.*); /* cluster of WARN level log strings */ _defmt_info = .; *(.defmt.info.*); _defmt_debug = .; *(.defmt.debug.*); _defmt_trace = .; *(.defmt.trace.*); } } ``` -------------------------------- ### Configure probe-run backtrace options Source: https://github.com/knurling-rs/defmt/blob/main/book/src/migration-02-03.md Use the `--backtrace` and `--backtrace-limit` arguments with `cargo run` to control backtrace generation. Options for `--backtrace` include `never`, `always`, and `auto` (default). The limit can be set to a specific number or `0` for unlimited. ```console cargo run --bin panic --backtrace=always --backtrace-limit=5 ``` -------------------------------- ### Linker Script for Grouping Interned Strings Source: https://github.com/knurling-rs/defmt/blob/main/book/src/interning.md A linker script is necessary to collect all symbols defined in custom input sections (e.g., `.my_custom_section.*`) into a single output section (e.g., `.my_custom_section`). This ensures strings are packed contiguously and enables garbage collection. ```text SECTIONS { /* NOTE: simplified */ .my_custom_section 0 (INFO) : /* ^^^^^^ metadata section: not placed in Flash */ /* ^ start address of this section */ /* ^^^^^^^^^^^^^^^ name of the OUTPUT linker section */ { *(.my_custom_section); *(.my_custom_section.*); /* ^ glob pattern for sub-sections */ /* ^^^^^^^^^^^^^^^^^ name of the INPUT linker section */ /* ^ from any object file (~= crate) */ } } ``` -------------------------------- ### Recommended Usage of Interned Strings Source: https://github.com/knurling-rs/defmt/blob/main/book/src/istr.md This is the recommended and most common way to log strings with defmt. It automatically interns the log string, providing the same bandwidth efficiency as `{=istr}` without explicit macro usage. ```rust # extern crate defmt; defmt::info!("The quick brown fox jumps over the lazy dog"); ``` -------------------------------- ### Running Integration Tests Source: https://github.com/knurling-rs/defmt/blob/main/firmware/defmt-test/README.md Execute integration tests using `cargo test --test integration`. This command runs tests defined in files like `tests/integration.rs`. ```console $ cargo test --test integration (..) 0.000000 INFO (1/2) running `assert_true`... └─ test::tests::__defmt_test_entry @ tests/test.rs:7 0.000001 INFO (2/2) running `assert_false`... └─ test::tests::__defmt_test_entry @ tests/test.rs:7 0.000002 ERROR panicked at 'TODO: write actual tests', testsuite/tests/test.rs:16:9 └─ panic_probe::print_defmt::print @ (..omitted..) stack backtrace: 0: HardFaultTrampoline 1: __udf 2: cortex_m::asm::udf at (..omitted..) 3: rust_begin_unwind at (..omitted..) 4: core::panicking::panic_fmt at (..omitted..) 5: core::panicking::panic at (..omitted..) 6: test::tests::assert_false at tests/test.rs:16 7: main at tests/test.rs:7 8: ResetTrampoline at (..omitted..) 9: Reset at (..omitted..) ``` -------------------------------- ### Inspecting Interned Strings with `nm` Source: https://github.com/knurling-rs/defmt/blob/main/book/src/interning.md After linking, the `nm` tool can be used to list symbols in the ELF file. The output shows the address, size, type, and name of each symbol, including the interned strings which appear as their exported names. ```console $ arm-none-eabi-nm -CSn elf-file 00000000 00000001 N USB controller is ready 00000001 00000001 N entering low power mode 00000002 00000001 N leaving low power mode (..) ``` -------------------------------- ### Basic Log Output Source: https://github.com/knurling-rs/defmt/blob/main/book/src/custom-log-output.md The simplest format string "{s}" prints only the log message content. ```text hello ``` -------------------------------- ### Serialize Signed and Unsigned Integers with Defmt Source: https://github.com/knurling-rs/defmt/blob/main/book/src/ser-integers.md Demonstrates serializing `i16` and `u32` integers using `defmt::error!`. Note the byte representation on the wire for each. ```rust # extern crate defmt; defmt::error!("The answer is {=i16}!", 300); // on the wire: [3, 44, 1] // string index ^ ^^^^^ `300.to_le_bytes()` // ^ = intern("The answer is {=i16}!") defmt::error!("The answer is {=u32}!", 131000); // on the wire: [4, 184, 255, 1, 0] // ^^^^^^^^^^^^^^^ 131000.to_le_bytes()) ``` -------------------------------- ### Manual `Format` Implementation with `defmt::write!` Source: https://github.com/knurling-rs/defmt/blob/main/book/src/format.md Implement the `Format` trait manually by defining the `format` method. Use the `defmt::write!` macro within this method to format the value into the provided `Formatter`. ```rust # extern crate defmt; // value read from a MMIO register named "CRCCNF" struct CRCCNF { bits: u32, } impl defmt::Format for CRCCNF { fn format(&self, f: defmt::Formatter) { // format the bitfields of the register as struct fields defmt::write!( f, "CRCCNF {{ LEN: {0=0..2}, SKIPADDR: {0=8..10} }}", self.bits, ) } } ``` -------------------------------- ### Defmt Macro Expansion for Log Strings Source: https://github.com/knurling-rs/defmt/blob/main/book/src/linker-sections.md Illustrates how defmt macros like `warn!` and `error!` expand into static symbol definitions. Each log message is placed into a specific linker section corresponding to its severity and includes a unique export name containing package, tag, data, and a disambiguator. ```rust,no_run,noplayground // first warn! invocation { #[export_name = "{\"package\":\"my-app\",\"tag\":\"defmt_warn\",\"data\":\"Hello\",\"disambiguator\":\"8864866341617976971\"}"] #[link_section = ".defmt.{\"package\":\"my-app\",\"tag\":\"defmt_warn\",\"data\":\"Hello\",\"disambiguator\":\"8864866341617976971\"}"] static SYM: u8 = 0; } // .. // first error! invocation { #[export_name = "{\"package\":\"my-app\",\"tag\":\"defmt_error\",\"data\":\"Bye\",\"disambiguator\":\"2879057613697528561\"}"] #[link_section = ".defmt.{\"package\":\"my-app\",\"tag\":\"defmt_error\",\"data\":\"Bye\",\"disambiguator\":\"2879057613697528561\"}"] static SYM: u8 = 0; } ``` -------------------------------- ### Configure Linker Flags in .cargo/config.toml Source: https://github.com/knurling-rs/defmt/blob/main/book/src/setup.md Add the `-C link-arg=-Tdefmt.x` flag to the rustflags section for the target architecture to include the defmt linker script. Ensure existing flags are preserved. ```toml # .cargo/config.toml [target.thumbv7m-none-eabi] rustflags = [ # --- KEEP existing `link-arg` flags --- "-C", "link-arg=-Tlink.x", "-C", "link-arg=--nmagic", # --- ADD following new flag --- "-C", "link-arg=-Tdefmt.x", ] ``` -------------------------------- ### defmt Format Trait Usage Source: https://github.com/knurling-rs/defmt/blob/main/book/src/macros.md Illustrates the use of the trace! macro with a placeholder that requires the argument to implement the defmt Format trait. This is analogous to Rust's core::fmt traits but consolidated into a single trait. ```rust # extern crate defmt; # let x = 0; defmt::trace!("{}", x); // ^ must implement the `Format` trait ``` -------------------------------- ### Formatting Bitfields from a Register Source: https://github.com/knurling-rs/defmt/blob/main/book/src/bitfields.md Demonstrates how to use bitfield formatting to extract and display specific fields (MAXLEN, STATLEN, BALEN) from a register value (pcnf1). The argument type must be large enough to hold the specified bit ranges. ```rust # extern crate defmt; # let pcnf1 = 0u32; // -> TRACE: PCNF1 { MAXLEN: 125, STATLEN: 3, BALEN: 2 } defmt::trace!( "PCNF1: {{ MAXLEN: {0=0..8}, STATLEN: {0=8..16}, BALEN: {0=16..19} }}", // ^ ^ ^ same argument pcnf1, // <- type must be `u32` ); ``` -------------------------------- ### Hardware Timestamp with defmt Source: https://github.com/knurling-rs/defmt/blob/main/book/src/timestamps.md Integrate device-specific monotonic timers for timestamps. The `us` display hint formats the value in microseconds. It's acceptable for the function to return 0 if the timer is disabled. ```rust # extern crate defmt; # fn monotonic_timer_counter_register() -> *mut u32 { # static mut X: u32 = 0; # unsafe { &mut X as *mut u32 } # } // WARNING may overflow and wrap-around in long lived apps defmt::timestamp!("{=u32:us}", { // NOTE(interrupt-safe) single instruction volatile read operation unsafe { monotonic_timer_counter_register().read_volatile() } }); # fn enable_monotonic_counter() {} fn main() { defmt::info!(".."); // timestamp = 0 defmt::debug!(".."); // timestamp = 0 enable_monotonic_counter(); defmt::info!(".."); // timestamp >= 0 // .. } ``` -------------------------------- ### nm Output Showing Clustered Log Strings Source: https://github.com/knurling-rs/defmt/blob/main/book/src/linker-sections.md This console output from the `nm` tool demonstrates how log strings are clustered by severity in the final ELF file. It shows the addresses of log messages and the delimiter symbols (`_defmt_warn`, `_defmt_info`), which are crucial for determining log levels at runtime. ```console $ arm-none-eabi-nm -CSn elf-file 00000000 00000001 N Bye 00000001 00000001 N Good 00000002 00000000 N _defmt_warn 00000002 00000001 N Hi 00000003 00000001 N Hello 00000003 00000000 N _defmt_info (..) ``` -------------------------------- ### Logging a String Literal with defmt Source: https://github.com/knurling-rs/defmt/blob/main/book/src/ser-istr.md Use `defmt::info!` to log a simple string literal. This string will be interned, converting it into a `usize` index for efficient serialization. ```rust # extern crate defmt; defmt::info!("Hello, world!"); ```