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:
17624 files changed
+4564928
-38
No files matched your search
@@ -0,0 +1,64 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[maybe_async_cfg::maybe(send="Send", sync(feature = "is_sync"), async(not(feature = "is_sync"), async_trait::async_trait))]
|
||||
trait Trait {
|
||||
fn sync_fn() {}
|
||||
|
||||
async fn declare_async(&self);
|
||||
|
||||
async fn async_fn(&self) {
|
||||
self.declare_async().await
|
||||
}
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(send="?Send", sync(feature = "is_sync"), async(not(feature = "is_sync"), async_trait::async_trait))]
|
||||
pub trait PubTrait {
|
||||
fn sync_fn() {}
|
||||
|
||||
async fn declare_async(&self);
|
||||
|
||||
async fn async_fn(&self) {
|
||||
self.declare_async().await
|
||||
}
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, sync(feature = "is_sync"), async(not(feature = "is_sync")))]
|
||||
async fn async_fn() {}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, sync(feature = "is_sync"), async(not(feature = "is_sync")))]
|
||||
pub async fn pub_async_fn() {
|
||||
}
|
||||
|
||||
struct Struct;
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, idents(Trait), sync(feature = "is_sync"), async(not(feature = "is_sync"), async_trait::async_trait))]
|
||||
impl Trait for Struct {
|
||||
fn sync_fn() {}
|
||||
|
||||
async fn declare_async(&self) {}
|
||||
|
||||
async fn async_fn(&self) {
|
||||
async { self.declare_async().await }.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "is_sync")]
|
||||
fn main() -> std::result::Result<(), ()> {
|
||||
let s = Struct;
|
||||
s.declare_async();
|
||||
s.async_fn();
|
||||
async_fn();
|
||||
pub_async_fn();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[cfg(not(feature = "is_sync"))]
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let s = Struct;
|
||||
s.declare_async().await;
|
||||
s.async_fn().await;
|
||||
async_fn().await;
|
||||
pub_async_fn().await;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[maybe_async_cfg::maybe(send="Send", async(not(feature = "is_sync"), async_trait::async_trait))]
|
||||
trait Trait {
|
||||
fn sync_fn() {}
|
||||
|
||||
async fn declare_async(&self);
|
||||
|
||||
async fn async_fn(&self) {
|
||||
self.declare_async().await
|
||||
}
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(send="?Send", async(not(feature = "is_sync"), async_trait::async_trait))]
|
||||
trait NotSendTrait {
|
||||
async fn declare_async_not_send(&self);
|
||||
|
||||
async fn async_fn_not_send(&self) {
|
||||
self.declare_async_not_send().await
|
||||
}
|
||||
}
|
||||
#[maybe_async_cfg::maybe(send="Send", async(not(feature = "is_sync"), async_trait::async_trait))]
|
||||
pub trait PubTrait {
|
||||
fn sync_fn() {}
|
||||
|
||||
async fn declare_async(&self);
|
||||
|
||||
async fn async_fn(&self) {
|
||||
self.declare_async().await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, async(not(feature = "is_sync")))]
|
||||
async fn async_fn() {}
|
||||
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, async(not(feature = "is_sync")))]
|
||||
pub async fn pub_async_fn() {}
|
||||
|
||||
struct Struct;
|
||||
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, idents(Trait), async(not(feature = "is_sync"), async_trait::async_trait))]
|
||||
impl Trait for Struct {
|
||||
fn sync_fn() {}
|
||||
|
||||
async fn declare_async(&self) {}
|
||||
|
||||
async fn async_fn(&self) {
|
||||
async { self.declare_async().await }.await
|
||||
}
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, idents(NotSendTrait), send="?Send", async(not(feature = "is_sync"), async_trait::async_trait))]
|
||||
impl NotSendTrait for Struct {
|
||||
async fn declare_async_not_send(&self) {}
|
||||
|
||||
async fn async_fn_not_send(&self) {
|
||||
async { self.declare_async_not_send().await }.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "is_sync")]
|
||||
fn main() {}
|
||||
|
||||
|
||||
#[cfg(not(feature = "is_sync"))]
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let s = Struct;
|
||||
s.declare_async().await;
|
||||
s.async_fn().await;
|
||||
async_fn().await;
|
||||
pub_async_fn().await;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[maybe_async_cfg::maybe(sync(feature = "is_sync"))]
|
||||
trait Trait {
|
||||
fn sync_fn() {}
|
||||
|
||||
async fn declare_async(&self);
|
||||
|
||||
async fn async_fn(&self) {
|
||||
self.declare_async().await
|
||||
}
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(sync(feature = "is_sync"))]
|
||||
pub trait PubTrait {
|
||||
fn sync_fn() {}
|
||||
|
||||
async fn declare_async(&self);
|
||||
|
||||
async fn async_fn(&self) {
|
||||
self.declare_async().await
|
||||
}
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, sync(feature = "is_sync"))]
|
||||
async fn async_fn() {}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, sync(feature = "is_sync"))]
|
||||
pub async fn pub_async_fn() {}
|
||||
|
||||
struct Struct;
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, idents(Trait), sync(feature = "is_sync"))]
|
||||
impl Trait for Struct {
|
||||
fn sync_fn() {}
|
||||
|
||||
async fn declare_async(&self) {}
|
||||
|
||||
async fn async_fn(&self) {
|
||||
async { self.declare_async().await }.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "is_sync")]
|
||||
fn main() -> std::result::Result<(), ()> {
|
||||
let s = Struct;
|
||||
s.declare_async();
|
||||
s.async_fn();
|
||||
async_fn();
|
||||
pub_async_fn();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[cfg(not(feature = "is_sync"))]
|
||||
#[async_std::main]
|
||||
async fn main() {}
|
||||
@@ -0,0 +1,37 @@
|
||||
#[maybe_async_cfg::maybe(sync(feature = "is_sync"), async(not(feature = "is_sync")))]
|
||||
async fn async_fn() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(
|
||||
idents(async_fn),
|
||||
sync(feature = "is_sync", test),
|
||||
async(all(not(feature="is_sync"), feature = "async_std"), async_std::test),
|
||||
async(all(not(feature="is_sync"), feature = "tokio"), tokio::test)
|
||||
)]
|
||||
async fn test_async_fn() {
|
||||
let res = async_fn().await;
|
||||
assert_eq!(res, true);
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(sync(feature = "is_sync", test), async(not(feature = "is_sync"), async_std::test))]
|
||||
async fn test_async_fn2() {
|
||||
let res = async_fn().await;
|
||||
assert_eq!(res, true);
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(sync(feature = "is_sync", test), async(not(feature = "is_sync"), async_std::test))]
|
||||
async fn test_async_fn3() {
|
||||
let res = async_fn().await;
|
||||
assert_eq!(res, true);
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(sync(feature = "is_sync", test), async(not(feature = "is_sync"), async_std::test))]
|
||||
async fn test_async_fn4() {
|
||||
let res = async_fn().await;
|
||||
assert_eq!(res, true);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#![allow(unused_imports)]
|
||||
use std::future::Future;
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, sync(feature = "is_sync"), async(not(feature = "is_sync")))]
|
||||
pub async fn with_fn<T, F: Sync + std::future::Future<Output = Result<(), ()>>>(
|
||||
test: T,
|
||||
) -> Result<(), ()>
|
||||
where
|
||||
T: FnOnce() -> F,
|
||||
{
|
||||
test().await
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, sync(feature = "is_sync"), async(not(feature = "is_sync")))]
|
||||
pub async fn with_fn_where<T, F>(test: T) -> Result<(), ()>
|
||||
where
|
||||
T: FnOnce() -> F,
|
||||
F: Sync + Future<Output = Result<(), ()>>,
|
||||
{
|
||||
test().await
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, sync(feature = "is_sync"))]
|
||||
fn main() {
|
||||
with_fn(|| Ok(())).unwrap();
|
||||
with_fn_where(|| Ok(())).unwrap();
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, async(not(feature = "is_sync")))]
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
with_fn(|| async { Ok(()) }).await.unwrap();
|
||||
with_fn_where(|| async { Ok(()) }).await.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
/// InnerClient differ a lot between sync and async.
|
||||
#[maybe_async_cfg::maybe(sync(feature = "is_sync"), async(not(feature = "is_sync"), async_trait::async_trait))]
|
||||
trait Trait {
|
||||
async fn maybe_async_fn();
|
||||
}
|
||||
|
||||
/// The higher level API for end user.
|
||||
pub struct Struct;
|
||||
|
||||
/// Synchronous implementation, only compiles when `is_sync` feature is off.
|
||||
/// Else the compiler will complain that *request is defined multiple times* and
|
||||
/// blabla.
|
||||
#[maybe_async_cfg::maybe(keep_self, idents(Trait), sync(feature = "is_sync"), async(not(feature = "is_sync")))]
|
||||
#[maybe_async::only_if(key="sync")]
|
||||
impl Trait for Struct {
|
||||
fn maybe_async_fn() { }
|
||||
}
|
||||
|
||||
/// Asynchronous implementation, only compiles when `is_sync` feature is off.
|
||||
#[maybe_async_cfg::maybe(keep_self, idents(Trait), sync(feature = "is_sync"), async(not(feature = "is_sync"), async_trait::async_trait))]
|
||||
#[maybe_async::only_if(key="async")]
|
||||
impl Trait for Struct {
|
||||
async fn maybe_async_fn() { }
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, idents(Trait, another_maybe_async_fn(fn)), sync(feature = "is_sync"), async(not(feature = "is_sync")))]
|
||||
impl Struct {
|
||||
async fn another_maybe_async_fn() {
|
||||
<Self as Trait>::maybe_async_fn().await
|
||||
// When `is_sync` is toggle on, this block will compiles to:
|
||||
// Self::maybe_async_fn()
|
||||
}
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, idents(another_maybe_async_fn(fn)), sync(feature = "is_sync"), async(not(feature = "is_sync")))]
|
||||
#[maybe_async::only_if(key="sync")]
|
||||
fn main() {
|
||||
let _ = Struct::another_maybe_async_fn();
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(keep_self, idents(another_maybe_async_fn(fn)), sync(feature = "is_sync"), async(not(feature = "is_sync")))]
|
||||
#[maybe_async::only_if(key="async")]
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let _ = Struct::another_maybe_async_fn().await;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#[maybe_async_cfg::maybe(
|
||||
sync(feature = "is_sync"),
|
||||
)]
|
||||
async fn async_fn() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(
|
||||
idents(async_fn(fn)),
|
||||
sync(feature = "is_sync"),
|
||||
async(not(feature = "is_sync")),
|
||||
)]
|
||||
async fn test_async_fn() {
|
||||
let res = async_fn().await;
|
||||
assert_eq!(res, true);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
error[E0425]: cannot find function `async_fn_async` in this scope
|
||||
--> tests/ui/test_fail/01-empty-test.rs:14:15
|
||||
|
|
||||
14 | let res = async_fn().await;
|
||||
| ^^^^^^^^ not found in this scope
|
||||
@@ -0,0 +1,21 @@
|
||||
#[maybe_async_cfg::maybe(
|
||||
sync(feature = "is_sync"),
|
||||
unknown(not(feature = "is_sync")),
|
||||
)]
|
||||
async fn async_fn() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[maybe_async_cfg::maybe(
|
||||
idents(async_fn(fn)),
|
||||
sync(feature = "is_sync"),
|
||||
async(not(feature = "is_sync")),
|
||||
)]
|
||||
async fn test_async_fn() {
|
||||
let res = async_fn().await;
|
||||
assert_eq!(res, true);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
error[E0425]: cannot find function `async_fn_async` in this scope
|
||||
--> tests/ui/test_fail/02-unknown-path.rs:15:15
|
||||
|
|
||||
15 | let res = async_fn().await;
|
||||
| ^^^^^^^^ not found in this scope
|
||||
@@ -0,0 +1,23 @@
|
||||
#[maybe_async_cfg::maybe(
|
||||
sync(feature = "is_sync"),
|
||||
async(not(feature = "is_sync")),
|
||||
)]
|
||||
async fn async_fn() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
//#[maybe_async::test(feature="is_sync", async(feature="async", async_std::test, added))]
|
||||
#[maybe_async_cfg::maybe(
|
||||
idents(async_fn(fn)),
|
||||
sync(feature = "is_sync"),
|
||||
async(not(feature = "is_sync")),
|
||||
async(not(feature = "is_sync")),
|
||||
)]
|
||||
async fn test_async_fn() {
|
||||
let res = async_fn().await;
|
||||
assert_eq!(res, true);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
error[E0428]: the name `test_async_fn_async` is defined multiple times
|
||||
--> tests/ui/test_fail/03-async-gt2.rs:16:1
|
||||
|
|
||||
16 | async fn test_async_fn() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| `test_async_fn_async` redefined here
|
||||
| previous definition of the value `test_async_fn_async` here
|
||||
|
|
||||
= note: `test_async_fn_async` must be defined only once in the value namespace of this module
|
||||
@@ -0,0 +1,23 @@
|
||||
#[maybe_async_cfg::maybe(
|
||||
sync(feature = "is_sync"),
|
||||
async(not(feature = "is_sync")),
|
||||
)]
|
||||
async fn async_fn() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
// bad sync condition
|
||||
//#[maybe_async::test(unknown(feature="async", async_std::test))]
|
||||
#[maybe_async_cfg::maybe(
|
||||
idents(async_fn(fn)),
|
||||
sync(unknown = "is_sync"),
|
||||
async(not(feature = "is_sync")),
|
||||
)]
|
||||
async fn test_async_fn() {
|
||||
let res = async_fn().await;
|
||||
assert_eq!(res, true);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: Wrong name for name-value pair: unknown
|
||||
--> tests/ui/test_fail/04-bad-sync-cond.rs:13:10
|
||||
|
|
||||
13 | sync(unknown = "is_sync"),
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
Reference in new issue
Block a user