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
Vendored
+115
@@ -0,0 +1,115 @@
|
||||
use serde::de;
|
||||
use serde::ser;
|
||||
|
||||
use crate::map::Map;
|
||||
use crate::Value;
|
||||
|
||||
/// Type representing a TOML table, payload of the `Value::Table` variant.
|
||||
///
|
||||
/// By default it entries are stored in
|
||||
/// [lexicographic order](https://doc.rust-lang.org/std/primitive.str.html#impl-Ord-for-str)
|
||||
/// of the keys. Enable the `preserve_order` feature to store entries in the order they appear in
|
||||
/// the source file.
|
||||
pub type Table = Map<String, Value>;
|
||||
|
||||
impl Table {
|
||||
/// Convert a `T` into `toml::Table`.
|
||||
///
|
||||
/// This conversion can fail if `T`'s implementation of `Serialize` decides to
|
||||
/// fail, or if `T` contains a map with non-string keys.
|
||||
pub fn try_from<T>(value: T) -> Result<Self, crate::ser::Error>
|
||||
where
|
||||
T: ser::Serialize,
|
||||
{
|
||||
value.serialize(crate::value::TableSerializer)
|
||||
}
|
||||
|
||||
/// Interpret a `toml::Table` as an instance of type `T`.
|
||||
///
|
||||
/// This conversion can fail if the structure of the `Table` does not match the structure
|
||||
/// expected by `T`, for example if `T` is a bool which can't be mapped to a `Table`. It can
|
||||
/// also fail if the structure is correct but `T`'s implementation of `Deserialize` decides
|
||||
/// that something is wrong with the data, for example required struct fields are missing from
|
||||
/// the TOML map or some number is too big to fit in the expected primitive type.
|
||||
pub fn try_into<'de, T>(self) -> Result<T, crate::de::Error>
|
||||
where
|
||||
T: de::Deserialize<'de>,
|
||||
{
|
||||
de::Deserialize::deserialize(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "display")]
|
||||
impl std::fmt::Display for Table {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
crate::ser::to_string(self)
|
||||
.expect("Unable to represent value as string")
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parse")]
|
||||
impl std::str::FromStr for Table {
|
||||
type Err = crate::de::Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
crate::from_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> de::Deserializer<'de> for Table {
|
||||
type Error = crate::de::Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, crate::de::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
Value::Table(self).deserialize_any(visitor)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, crate::de::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
Value::Table(self).deserialize_enum(name, variants, visitor)
|
||||
}
|
||||
|
||||
// `None` is interpreted as a missing field so be sure to implement `Some`
|
||||
// as a present field.
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, crate::de::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
Value::Table(self).deserialize_option(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, crate::de::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
Value::Table(self).deserialize_newtype_struct(name, visitor)
|
||||
}
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
|
||||
bytes byte_buf map unit_struct tuple_struct struct
|
||||
tuple ignored_any identifier
|
||||
}
|
||||
}
|
||||
|
||||
impl de::IntoDeserializer<'_, crate::de::Error> for Table {
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user