feat: add display UI with splash screen, dashboard, and RSSI sparkline

Implement full SSD1306 OLED display support:
- Splash screen on boot (1.5s) with project name, version, board
- Dashboard showing radio state, config, counters, RSSI/SNR
- RSSI history sparkline (64-sample ring buffer, 2px-wide bars)
- DisplayOn/DisplayOff host commands routed via dedicated channel
- Pure render functions against generic DrawTarget (no hardware coupling)
- Display on/off control bypasses radio task entirely

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
swaitsandClaude Opus 4.6 committed 2026-03-29 20:42:54 -06:00
1 parent 7064110293
commit 3102fc747a
17624 files changed
+4564928 -38

No files matched your search

+1
View File
@@ -0,0 +1 @@
{"files":{".cargo_vcs_info.json":"52958cfe708221b05e570d1ec210648cda1ff43896ca0e2db590ab05c2f5a274","Cargo.lock":"8818a65aea2506c7069182f452385413cfbc97b01274b3da39c1e0be2325603e","Cargo.toml":"c5af9fdb95fb235ad451d4d1ccb1303e7c68d458dc1d93804b6da256c3e65aff","Cargo.toml.orig":"262decc394bb6b333d261d75108c3f4cc779a2c764e2ebc90bc08da117462428","README.md":"17297ac96124513227d7f6cef9a936b27b57ce7a2a48b44cd8792eddb59040df","src/lib.rs":"ca245dc548ced4687aaadccb2faaa29a236b4c5aeadc653898121c0e6e694e79"},"package":"f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad"}
+6
View File
@@ -0,0 +1,6 @@
{
"git": {
"sha1": "f6decae6e09d1216aff052aa0733a6b5e632a100"
},
"path_in_vcs": "defmt-03"
}
+125
View File
@@ -0,0 +1,125 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "defmt"
version = "0.3.100"
dependencies = [
"defmt 1.0.0",
]
[[package]]
name = "defmt"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b834fbddebd69852b7742f3b1fdd9df277c8f36a028c03b7002f7f513bac65fe"
dependencies = [
"bitflags",
"defmt-macros",
]
[[package]]
name = "defmt-macros"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6e0f20557738ff14dad3e698b57da89f04d708433024c6f931dde286051b94a"
dependencies = [
"defmt-parser",
"proc-macro-error2",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "defmt-parser"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
dependencies = [
"thiserror",
]
[[package]]
name = "proc-macro-error-attr2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "proc-macro-error2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+64
View File
@@ -0,0 +1,64 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
name = "defmt"
version = "0.3.100"
authors = ["The Knurling-rs developers"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "A highly efficient logging framework that targets resource-constrained devices, like microcontrollers"
homepage = "https://knurling.ferrous-systems.com/"
readme = "README.md"
keywords = [
"knurling",
"logging",
"logger",
"formatting",
"formatter",
]
categories = [
"embedded",
"no-std",
"development-tools::debugging",
"value-formatting",
]
license = "MIT OR Apache-2.0"
repository = "https://github.com/knurling-rs/defmt"
[package.metadata.docs.rs]
features = ["alloc"]
rustdoc-args = ["--cfg=docsrs"]
targets = [
"thumbv6m-none-eabi",
"thumbv7em-none-eabihf",
]
[features]
alloc = ["defmt10/alloc"]
avoid-default-panic = ["defmt10/avoid-default-panic"]
encoding-raw = ["defmt10/encoding-raw"]
encoding-rzcobs = ["defmt10/encoding-rzcobs"]
ip_in_core = ["defmt10/ip_in_core"]
unstable-test = ["defmt10/unstable-test"]
[lib]
name = "defmt"
path = "src/lib.rs"
[dependencies.defmt10]
version = "1"
package = "defmt"
+54
View File
@@ -0,0 +1,54 @@
# `defmt`
`defmt` ("de format", short for "deferred formatting") is a highly efficient logging framework that targets resource-constrained devices, like microcontrollers.
For more details about the framework check the book at <https://defmt.ferrous-systems.com>.
This release is a semver-trick compatibility shim that allows packages using `defmt = "0.3"` to inter-operate with packages using `defmt = "1.0"`.
## Setup
### New project
The fastest way to get started with `defmt` is to use our [app-template] to set up a new Cortex-M embedded project.
[app-template]: https://github.com/knurling-rs/app-template
### Existing project
To include `defmt` in your existing project, follow our [Application Setup guide].
[Application Setup guide]: https://defmt.ferrous-systems.com/setup.html
## MSRV
The minimum supported Rust version is 1.76 (or Ferrocene 24.05). `defmt` is tested against the latest stable Rust version and the MSRV.
## Support
`defmt` 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
http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
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
+336
View File
@@ -0,0 +1,336 @@
//! A highly efficient logging framework that targets resource-constrained
//! devices, like microcontrollers.
//!
//! Check out the defmt book at <https://defmt.ferrous-systems.com> for more
//! information about how to use it.
//!
//! # Compatibility
//!
//! This is a defmt-0.3 compatbility crate. It depends upon `defmt-1.0` and
//! re-exports the items that were available in `defmt-0.3`. This allows you to
//! mix defmt-0.3 and defmt-1.0 within the same compilation.
//!
//! The `defmt` wire format might change between minor versions. Attempting to
//! read a defmt stream with an incompatible version will result in an error,
//! and any tool used to process that stream should first check for a symbol
//! named like `_defmt_version_ = X`, where X indicates the wire format version
//! in use.
//!
//! Updating your version of defmt might mean you also have to update your
//! version of `defmt-print` or `defmt-decoder`.
#![no_std]
/// Just like the [`core::assert!`] macro but `defmt` is used to log the panic message
///
/// [`core::assert!`]: https://doc.rust-lang.org/core/macro.assert.html
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::assert;
/// Just like the [`core::assert_eq!`] macro but `defmt` is used to log the panic message
///
/// [`core::assert_eq!`]: https://doc.rust-lang.org/core/macro.assert_eq.html
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::assert_eq;
/// Just like the [`core::assert_ne!`] macro but `defmt` is used to log the panic message
///
/// [`core::assert_ne!`]: https://doc.rust-lang.org/core/macro.assert_ne.html
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::assert_ne;
/// Just like the [`core::debug_assert!`] macro but `defmt` is used to log the panic message
///
/// [`core::debug_assert!`]: https://doc.rust-lang.org/core/macro.debug_assert.html
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::debug_assert;
/// Just like the [`core::debug_assert_eq!`] macro but `defmt` is used to log the panic message
///
/// [`core::debug_assert_eq!`]: https://doc.rust-lang.org/core/macro.debug_assert_eq.html
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::debug_assert_eq;
/// Just like the [`core::debug_assert_ne!`] macro but `defmt` is used to log the panic message
///
/// [`core::debug_assert_ne!`]: https://doc.rust-lang.org/core/macro.debug_assert_ne.html
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::debug_assert_ne;
/// Just like the [`core::unreachable!`] macro but `defmt` is used to log the panic message
///
/// [`core::unreachable!`]: https://doc.rust-lang.org/core/macro.unreachable.html
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::unreachable;
/// Just like the [`core::todo!`] macro but `defmt` is used to log the panic message
///
/// [`core::todo!`]: https://doc.rust-lang.org/core/macro.todo.html
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::todo;
/// Just like the [`core::unimplemented!`] macro but `defmt` is used to log the panic message
///
/// [`core::unimplemented!`]: https://doc.rust-lang.org/core/macro.unimplemented.html
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::todo as unimplemented;
/// Just like the [`core::panic!`] macro but `defmt` is used to log the panic message
///
/// [`core::panic!`]: https://doc.rust-lang.org/core/macro.panic.html
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::panic;
/// Unwraps an `Option` or `Result`, panicking if it is `None` or `Err`.
///
/// This macro is roughly equivalent to `{Option,Result}::{expect,unwrap}` but invocation looks
/// a bit different because this is a macro and not a method. The other difference is that
/// `unwrap!`-ing a `Result<T, E>` value requires that the error type `E` implements the `Format`
/// trait
///
/// The following snippet shows the differences between core's unwrap method and defmt's unwrap
/// macro:
///
/// ```
/// use defmt::unwrap;
///
/// # let option = Some(());
/// let x = option.unwrap();
/// let x = unwrap!(option);
///
/// # let result = Ok::<(), ()>(());
/// let x = result.unwrap();
/// let x = unwrap!(result);
///
/// let x = result.expect("text");
/// let x = unwrap!(result, "text");
///
/// # let arg = ();
/// let x = result.expect(&format!("text {:?}", arg));
/// let x = unwrap!(result, "text {:?}", arg); // arg must be implement `Format`
/// ```
///
/// If used, the format string must follow the defmt syntax (documented in [the manual])
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::unwrap;
/// This is an alias for defmt's [`unwrap`] macro which supports messages like std's except.
/// ```
/// use defmt::expect;
///
/// # let result = Ok::<(), ()>(());
/// # let arg = ();
/// let x = result.expect(&format!("text {:?}", arg));
/// let x = expect!(result, "text {:?}", arg); // arg must be implement `Format`
/// ```
///
/// For the complete documentation see that of defmt's *unwrap* macro.
// note: Linking to unwrap is broken as of 2024-10-09, it links back to expect
pub use defmt10::unwrap as expect;
/// Overrides the panicking behavior of `defmt::panic!`
///
/// By default, `defmt::panic!` calls `core::panic!` after logging the panic message using `defmt`.
/// This can result in the panic message being printed twice in some cases. To avoid that issue use
/// this macro. See [the manual] for details.
///
/// [the manual]: https://defmt.ferrous-systems.com/panic.html
///
/// # Inter-operation with built-in attributes
///
/// This attribute cannot be used together with the `export_name` or `no_mangle` attributes
pub use defmt10::panic_handler;
/// Creates an interned string ([`Str`]) from a string literal.
///
/// This must be called on a string literal, and will allocate the literal in the object file. At
/// runtime, only a small string index is required to refer to the string, represented as the
/// [`Str`] type.
///
/// # Example
///
/// ```
/// let interned = defmt::intern!("long string literal taking up little space");
/// ```
///
/// [`Str`]: struct.Str.html
pub use defmt10::intern;
/// Always logs data irrespective of log level.
///
/// Please refer to [the manual] for documentation on the syntax.
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::println;
/// Logs data at *debug* level.
///
/// Please refer to [the manual] for documentation on the syntax.
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::debug;
/// Logs data at *error* level.
///
/// Please refer to [the manual] for documentation on the syntax.
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::error;
/// Logs data at *info* level.
///
/// Please refer to [the manual] for documentation on the syntax.
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::info;
/// Logs data at *trace* level.
///
/// Please refer to [the manual] for documentation on the syntax.
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::trace;
/// Logs data at *warn* level.
///
/// Please refer to [the manual] for documentation on the syntax.
///
/// [the manual]: https://defmt.ferrous-systems.com/macros.html
pub use defmt10::warn;
/// Just like the [`std::dbg!`] macro but `defmt` is used to log the message at `TRACE` level.
///
/// [`std::dbg!`]: https://doc.rust-lang.org/std/macro.dbg.html
pub use defmt10::dbg;
/// Writes formatted data to a [`Formatter`].
///
/// [`Formatter`]: struct.Formatter.html
pub use defmt10::write;
/// Defines the global defmt logger.
///
/// `#[global_logger]` needs to be put on a unit struct type declaration. This struct has to
/// implement the [`Logger`] trait.
///
/// # Example
///
/// ```
/// use defmt::{Logger, global_logger};
///
/// #[global_logger]
/// struct MyLogger;
///
/// unsafe impl Logger for MyLogger {
/// fn acquire() {
/// # todo!()
/// // ...
/// }
/// unsafe fn flush() {
/// # todo!()
/// // ...
/// }
/// unsafe fn release() {
/// # todo!()
/// // ...
/// }
/// unsafe fn write(bytes: &[u8]) {
/// # todo!()
/// // ...
/// }
/// }
/// ```
///
/// [`Logger`]: trait.Logger.html
pub use defmt10::global_logger;
/// Defines the global timestamp provider for defmt.
///
/// This macro can be used to attach a timestamp or other data to every defmt message. Its syntax
/// works exactly like the logging macros, except that no local variables can be accessed and the
/// macro should be placed in a module instead of a function.
///
/// `timestamp!` must only be used once across the crate graph.
///
/// If no crate defines a timestamp, no timestamp will be included in the logged messages.
///
/// # Examples
///
/// ```
/// # use core::sync::atomic::{AtomicU32, Ordering};
///
/// static COUNT: AtomicU32 = AtomicU32::new(0);
/// defmt::timestamp!("{=u32:us}", COUNT.fetch_add(1, Ordering::Relaxed));
/// ```
pub use defmt10::timestamp;
/// Generates a bitflags structure that can be formatted with defmt.
///
/// This macro is a wrapper around the [`bitflags!`] crate, and provides an (almost) identical
/// interface. Refer to [its documentation] for an explanation of the syntax.
///
/// [its documentation]: https://docs.rs/bitflags/1/bitflags/
///
/// # Limitations
///
/// This macro only supports bitflags structs represented as one of Rust's built-in unsigned integer
/// types (`u8`, `u16`, `u32`, `u64`, or `u128`). Custom types are not supported. This restriction
/// is necessary to support defmt's efficient encoding.
///
/// # Examples
///
/// The example from the bitflags crate works as-is:
///
/// ```
/// defmt::bitflags! {
/// struct Flags: u32 {
/// const A = 0b00000001;
/// const B = 0b00000010;
/// const C = 0b00000100;
/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
/// }
/// }
///
/// defmt::info!("Flags::ABC: {}", Flags::ABC);
/// defmt::info!("Flags::empty(): {}", Flags::empty());
/// ```
pub use defmt10::bitflags;
#[doc(inline)]
pub use defmt10::{Debug2Format, Display2Format, Encoder, Formatter, Str};
#[doc(inline)]
pub use defmt10::{Format, Logger};
#[doc(hidden)]
pub use defmt10::export;
#[doc(inline)]
pub use defmt10::flush;