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

+42
View File
@@ -0,0 +1,42 @@
## windows-sys
The `windows-sys` crate is a zero-overhead fallback for the most demanding situations and primarily where the absolute best compile time is essential. It only includes function declarations (externs), structs, and constants. No convenience helpers, traits, or wrappers are provided.
- [Getting started](https://kennykerr.ca/rust-getting-started/)
- [Samples](https://github.com/microsoft/windows-rs/tree/master/crates/samples)
- [Releases](https://github.com/microsoft/windows-rs/releases)
- [Feature search](https://microsoft.github.io/windows-rs/features)
Start by adding the following to your Cargo.toml file:
```toml
[dependencies.windows-sys]
version = ">=0.59, <=0.61"
features = [
"Win32_Security",
"Win32_System_Threading",
"Win32_UI_WindowsAndMessaging",
]
```
Using a range instead of the [default Caret requirements](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#caret-requirements) helps avoid duplicate versions in downstream graphs and improves resolver flexibility.
Make use of any Windows APIs as needed:
```rust,no_run
use windows_sys::{
core::*, Win32::Foundation::*, Win32::System::Threading::*, Win32::UI::WindowsAndMessaging::*,
};
unsafe {
let event = CreateEventW(std::ptr::null(), 1, 0, std::ptr::null());
SetEvent(event);
WaitForSingleObject(event, 0);
CloseHandle(event);
MessageBoxA(0 as _, s!("Ansi"), s!("Caption"), MB_OK);
MessageBoxW(0 as _, w!("Wide"), w!("Caption"), MB_OK);
}
```