Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
1d7848119e |
12
Cargo.toml
12
Cargo.toml
@ -11,11 +11,13 @@ name = "renderbug"
|
||||
harness = false # do not use the built in cargo test harness -> resolve rust-analyzer errors
|
||||
|
||||
[profile.release]
|
||||
opt-level = "s"
|
||||
opt-level = 3
|
||||
lto = "on"
|
||||
|
||||
[profile.dev]
|
||||
debug = true # Symbols are nice and they don't increase the size on Flash
|
||||
opt-level = "z"
|
||||
opt-level = "s"
|
||||
lto = "on"
|
||||
|
||||
[features]
|
||||
default = ["std", "esp-idf-svc/native", "rmt", "smart-leds"]
|
||||
@ -32,6 +34,8 @@ alloc = ["esp-idf-svc/alloc"]
|
||||
[dependencies]
|
||||
log = { version = "0.4", default-features = false }
|
||||
esp-idf-svc = { version = "0.49", default-features = false }
|
||||
hsv = "0.1.1"
|
||||
palette = { version = "0.7.6" }
|
||||
running-average = "0.1.0"
|
||||
rgb = "0.8.50"
|
||||
|
||||
@ -43,10 +47,12 @@ smart-leds-trait = { version = "0.3.0", optional = true }
|
||||
smart-leds = { version = "0.4.0", optional = true }
|
||||
|
||||
embedded-graphics = { version = "0.8.1", optional = true, features = ["fixed_point", "defmt"] }
|
||||
ansi_term = "0.12.1"
|
||||
num = "0.4.3"
|
||||
chrono = "0.4.38"
|
||||
serde_json = "1.0.133"
|
||||
paste = "1.0.15"
|
||||
ssd1306 = "0.9.0"
|
||||
embedded-hal = "1.0.0"
|
||||
|
||||
[build-dependencies]
|
||||
embuild = "0.32.0"
|
||||
|
@ -1,7 +1,8 @@
|
||||
pub mod test;
|
||||
|
||||
use palette::Hsv;
|
||||
|
||||
use rgb::RGB8;
|
||||
use crate::lib8::Hsv;
|
||||
|
||||
use crate::events::EventBus;
|
||||
use crate::geometry::*;
|
||||
@ -21,7 +22,7 @@ struct SolidShader {}
|
||||
|
||||
impl Shader for SolidShader {
|
||||
fn draw(&self, _coords: &VirtualCoordinates, frame: usize) -> RGB8 {
|
||||
Hsv::new((frame % 255) as u8, 255, sin8((frame % 64) as u8)).into_rgb8()
|
||||
Hsv::new_srgb((frame % 255) as u8, 255, sin8((frame % 64) as u8)).into_rgb8()
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +31,7 @@ struct ShimmerShader {}
|
||||
|
||||
impl Shader for ShimmerShader {
|
||||
fn draw(&self, coords: &VirtualCoordinates, frame: usize) -> RGB8 {
|
||||
Hsv::new(((coords.x as usize).wrapping_add(frame / 3) % 255) as u8, coords.y, sin8(frame).max(75).min(64)).into_rgb8()
|
||||
Hsv::new_srgb(((coords.x as usize).wrapping_add(frame / 3) % 255) as u8, coords.y, sin8(frame).max(75).min(64)).into_rgb8()
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +48,7 @@ impl Shader for ThinkingShader {
|
||||
let noise_y = offset_y / 2;
|
||||
//let noise_x = coords.x.wrapping_add(offset_x);
|
||||
//let noise_y = coords.y.wrapping_add(offset_y);
|
||||
Hsv::new(
|
||||
Hsv::new_srgb(
|
||||
inoise8(offset_x as i16, offset_y as i16),
|
||||
128_u8.saturating_add(inoise8(noise_y as i16, noise_x as i16)),
|
||||
255
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::lib8::Hsv;
|
||||
use palette::Hsv;
|
||||
use rgb::RGB8;
|
||||
|
||||
use crate::{events::{Event, EventBus}, lib8::{interpolate::scale8, trig::{cos8, sin8}, IntoRgb8}, render::{Shader, Surface}, task::Task, time::Periodically};
|
||||
use crate::{events::{Event, EventBus, Namespace}, lib8::{interpolate::scale8, trig::{cos8, sin8}, IntoRgb8}, render::{Shader, Surface}, task::Task, time::Periodically};
|
||||
|
||||
use super::{Coordinates, Rectangle, VirtualCoordinates};
|
||||
|
||||
@ -48,7 +48,7 @@ impl Shader for TestShader {
|
||||
Self::Blue => RGB8::new(0, 0, 255),
|
||||
Self::White => RGB8::new(255, 255, 255),
|
||||
Self::RGB => RGB8::new(coords.x, coords.y, 255 - (coords.x / 2 + coords.y / 2)),
|
||||
Self::HSV => Hsv::new(coords.x, coords.y, 255).into_rgb8(),
|
||||
Self::HSV => Hsv::new_srgb(coords.x, coords.y, 255).into_rgb8(),
|
||||
Self::Outline => match (coords.x, coords.y) {
|
||||
(0, 0) => RGB8::new(255, 255, 255),
|
||||
(0, _) => RGB8::new(255, 0, 0),
|
||||
|
260
src/events.rs
260
src/events.rs
@ -1,7 +1,57 @@
|
||||
use core::fmt::Debug;
|
||||
use std::{collections::VecDeque, fmt::{Display, Result}, sync::{Arc, Mutex}};
|
||||
|
||||
use crate::{properties::{Properties, PropertyID, Variant}, property_namespace};
|
||||
use rgb::Rgb;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Variant {
|
||||
SignedByte(i8),
|
||||
Byte(u8),
|
||||
UInt(u32),
|
||||
Int(i32),
|
||||
BigUInt(u64),
|
||||
BigInt(i64),
|
||||
Boolean(bool),
|
||||
String(String),
|
||||
RGB(Rgb<u8>),
|
||||
Vec(Vec<Variant>)
|
||||
}
|
||||
|
||||
macro_rules! impl_variant_type {
|
||||
($type:ty, $var_type:tt) => {
|
||||
impl From<$type> for Variant {
|
||||
fn from(value: $type) -> Self {
|
||||
Variant::$var_type(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<$type> for Variant {
|
||||
fn into(self) -> $type {
|
||||
match self {
|
||||
Variant::$var_type(value) => value,
|
||||
_ => panic!(concat!("Expected Variant::", stringify!($var_type), "but got {:?}"), self)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_variant_type!(u8, Byte);
|
||||
impl_variant_type!(i8, SignedByte);
|
||||
impl_variant_type!(u32, UInt);
|
||||
impl_variant_type!(i32, Int);
|
||||
impl_variant_type!(i64, BigInt);
|
||||
impl_variant_type!(u64, BigUInt);
|
||||
impl_variant_type!(bool, Boolean);
|
||||
impl_variant_type!(String, String);
|
||||
impl_variant_type!(Rgb<u8>, RGB);
|
||||
impl_variant_type!(Vec<Variant>, Vec);
|
||||
|
||||
impl<'a> From<&'a str> for Variant {
|
||||
fn from(value: &'a str) -> Self {
|
||||
Variant::String(value.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Event {
|
||||
@ -46,6 +96,214 @@ impl Event {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Property {
|
||||
key: PropertyKey,
|
||||
value: Variant
|
||||
}
|
||||
|
||||
impl Property {
|
||||
pub const fn new(key: PropertyKey, value: Variant) -> Self {
|
||||
Property {
|
||||
key,
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct NamespaceKey(pub &'static str);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct PropertyKey(pub &'static str);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct PropertyID {
|
||||
pub namespace: NamespaceKey,
|
||||
pub key: PropertyKey
|
||||
}
|
||||
|
||||
impl Display for PropertyID {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result {
|
||||
write!(f, "{}::{}", self.namespace.0, self.key.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Namespace {
|
||||
fn nskey() -> NamespaceKey;
|
||||
fn properties() -> Vec<Property>;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! prop_id {
|
||||
($name:ident, $prop_name:ident) => {
|
||||
$crate::PropertyID {
|
||||
namespace: $crate::NamespaceKey(stringify!($name)),
|
||||
key: $crate::PropertyKey(stringify!($prop_name))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! property_namespace {
|
||||
($name:ident, $($prop_name:ident => $value:expr),*) => {
|
||||
pub enum $name {
|
||||
$($prop_name),*
|
||||
}
|
||||
|
||||
impl $crate::Namespace for $name {
|
||||
fn nskey() -> $crate::NamespaceKey {
|
||||
$crate::NamespaceKey(stringify!($name))
|
||||
}
|
||||
|
||||
fn properties() -> Vec<$crate::Property> {
|
||||
vec![
|
||||
$($crate::Property::new(Self::$prop_name.key(), $crate::Variant::from($value))),*
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
pub const fn key(&self) -> $crate::PropertyKey {
|
||||
match self {
|
||||
$(Self::$prop_name => $crate::PropertyKey(stringify!($prop_name))),*
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn id(&self) -> $crate::PropertyID {
|
||||
$crate::PropertyID { namespace: $crate::NamespaceKey(stringify!($name)), key: self.key() }
|
||||
}
|
||||
|
||||
pub fn new_property_change<V>(&self, value: V) -> $crate::Event where $crate::Variant: From<V> {
|
||||
$crate::Event::PropertyChange(self.id(), $crate::Variant::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<$crate::PropertyID> for $name {
|
||||
fn into(self) -> $crate::PropertyID {
|
||||
self.id()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NamespaceProps {
|
||||
props: Vec<Property>,
|
||||
key: NamespaceKey
|
||||
}
|
||||
|
||||
impl NamespaceProps {
|
||||
fn new<NS: Namespace>() -> Self {
|
||||
NamespaceProps {
|
||||
props: NS::properties(),
|
||||
key: NS::nskey()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_key(&self, key: &PropertyKey) -> Option<&Property> {
|
||||
for next in self.props.iter() {
|
||||
if next.key == *key {
|
||||
return Some(next);
|
||||
}
|
||||
}
|
||||
|
||||
log::warn!("Unknown key {:?}", key);
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
fn get_key_mut(&mut self, key: &PropertyKey) -> Option<&mut Property> {
|
||||
for next in self.props.iter_mut() {
|
||||
if next.key == *key {
|
||||
return Some(next);
|
||||
}
|
||||
}
|
||||
|
||||
log::warn!("Unknown key {:?}", key);
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Properties {
|
||||
contents: Vec<NamespaceProps>
|
||||
}
|
||||
|
||||
impl Display for Properties {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for ns in self.contents.iter() {
|
||||
write!(f, "{}\n", ns.key.0).unwrap();
|
||||
for prop in ns.props.iter() {
|
||||
write!(f, "\t{} = {:?}\n", prop.key.0, prop.value).unwrap();
|
||||
}
|
||||
}
|
||||
Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Properties {
|
||||
fn new() -> Self {
|
||||
Properties {
|
||||
contents: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_namespace<T: Namespace>(&mut self) {
|
||||
self.contents.push(NamespaceProps::new::<T>());
|
||||
}
|
||||
|
||||
fn get_namespace(&self, ns: &NamespaceKey) -> Option<&NamespaceProps> {
|
||||
for nsprops in self.contents.iter() {
|
||||
if nsprops.key == *ns {
|
||||
return Some(nsprops)
|
||||
}
|
||||
}
|
||||
|
||||
log::warn!("Unknown namespace {:?}", ns);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn get_namespace_mut(&mut self, ns: &NamespaceKey) -> Option<&mut NamespaceProps> {
|
||||
for nsprops in self.contents.iter_mut() {
|
||||
if nsprops.key == *ns {
|
||||
return Some(nsprops)
|
||||
}
|
||||
}
|
||||
|
||||
log::warn!("Unknown namespace {:?}", ns);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get<T: Into<PropertyID>>(&self, key: T) -> Option<Variant> {
|
||||
let as_id = key.into();
|
||||
match self.get_namespace(&as_id.namespace).unwrap().get_key(&as_id.key) {
|
||||
None => None,
|
||||
Some(v) => Some(v.value.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set<V, T: Into<PropertyID>>(&mut self, key: T, value: V) -> bool where Variant: From<V> {
|
||||
let as_id = key.into();
|
||||
let as_variant: Variant = value.into();
|
||||
match self.get_namespace_mut(&as_id.namespace).unwrap().get_key_mut(&as_id.key) {
|
||||
None => (),
|
||||
Some(found_key) => {
|
||||
if found_key.value != as_variant {
|
||||
found_key.value = as_variant;
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EventBus {
|
||||
pending: Arc<Mutex<VecDeque<Event>>>,
|
||||
|
@ -1,8 +1,6 @@
|
||||
use chrono::{DateTime, Timelike, Utc};
|
||||
|
||||
use crate::{events::{Event, EventBus}, lib8::interpolate::lerp8by8, prop_id, properties::{PropertyID, Variant}, render::props::Output as OutputNS, task::Task, time::Periodically};
|
||||
use crate::events::System as SystemNS;
|
||||
use paste::paste;
|
||||
use crate::{events::{Event, EventBus, Namespace, Variant}, lib8::interpolate::lerp8by8, prop_id, render::props::Output as OutputNS, task::Task, time::Periodically, PropertyID};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct ScheduleEntry {
|
||||
@ -37,7 +35,7 @@ impl CircadianRhythm {
|
||||
fn update_brightness(&self, bus: &mut EventBus) {
|
||||
let now: DateTime<Utc> = std::time::SystemTime::now().into();
|
||||
let next_brightness = self.brightness_for_time(now.hour() as u8, now.minute() as u8);
|
||||
bus.set_property(OutputNS::Brightness, next_brightness);
|
||||
bus.push(OutputNS::Brightness.new_property_change(next_brightness));
|
||||
}
|
||||
|
||||
fn brightness_for_time(&self, hour: u8, minute: u8) -> u8 {
|
||||
@ -79,7 +77,7 @@ fn map_range(x: u16, in_min: u16, in_max: u16, out_min: u16, out_max: u16) -> u1
|
||||
}
|
||||
let rise = out_max - out_min;
|
||||
let delta = x - in_min;
|
||||
return (delta.wrapping_mul(rise)) / run + out_min;
|
||||
return (delta * rise) / run + out_min;
|
||||
}
|
||||
|
||||
|
||||
@ -90,7 +88,7 @@ impl Task for CircadianRhythm {
|
||||
|
||||
fn on_property_change(&mut self, key: PropertyID, value: &Variant, bus: &mut EventBus) {
|
||||
match (key, value) {
|
||||
(prop_id!(SystemNS::TimeSync), Variant::Boolean(true)) => self.update_brightness(bus),
|
||||
(prop_id!(System, TimeSync), Variant::Boolean(true)) => self.update_brightness(bus),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ pub mod interpolate;
|
||||
pub mod noise;
|
||||
pub mod trig;
|
||||
|
||||
use palette::encoding::srgb::Srgb;
|
||||
|
||||
use rgb::Rgb;
|
||||
|
||||
use crate::lib8::interpolate::scale8;
|
||||
@ -16,23 +18,7 @@ impl IntoRgb8 for Rgb<u8> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Hsv {
|
||||
pub hue: u8,
|
||||
pub saturation: u8,
|
||||
pub value: u8
|
||||
}
|
||||
|
||||
impl Hsv {
|
||||
pub fn new(hue: u8, saturation: u8, value: u8) -> Self {
|
||||
Hsv {
|
||||
hue,
|
||||
saturation,
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRgb8 for Hsv {
|
||||
impl IntoRgb8 for palette::Hsv<Srgb, u8> {
|
||||
//TODO: Borrowed from FastLED
|
||||
fn into_rgb8(self) -> Rgb<u8> {
|
||||
const HSV_SECTION_3: u8 = 0x40;
|
||||
@ -41,7 +27,7 @@ impl IntoRgb8 for Hsv {
|
||||
return Rgb::new(self.value, self.value, self.value)
|
||||
}
|
||||
|
||||
let mock_hue = scale8(191, self.hue);
|
||||
let mock_hue = scale8(191, self.hue.into_inner());
|
||||
let value: u8 = self.value;
|
||||
let saturation: u8 = self.saturation;
|
||||
let invsat: u8 = 255 - saturation;
|
||||
@ -66,4 +52,4 @@ impl IntoRgb8 for Hsv {
|
||||
_ => Rgb::new(rampup_adj_with_floor, brightness_floor, rampdown_adj_with_floor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,9 @@ mod mappings;
|
||||
mod buffers;
|
||||
mod scenes;
|
||||
mod inputs;
|
||||
|
||||
#[macro_use]
|
||||
mod events;
|
||||
mod properties;
|
||||
|
||||
use events::*;
|
||||
use inputs::circadian::CircadianRhythm;
|
||||
|
@ -171,14 +171,7 @@ impl<const STRIDE_NUM: usize> StrideMapping<STRIDE_NUM> {
|
||||
|
||||
pub fn new_albus() -> Self {
|
||||
Self::from_json(&[
|
||||
(0, 0, 29, false),
|
||||
(1, 0, 20, false),
|
||||
(2, 0, 22, false),
|
||||
(3, 0, 19, false),
|
||||
(4, 0, 12, false),
|
||||
(5, 0, 14, false),
|
||||
(6, 0, 16, false),
|
||||
(7, 0, 19, false),
|
||||
(0, 0, 50 * 3, false)
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,8 @@ use std::{collections::LinkedList, thread::JoinHandle};
|
||||
use esp_idf_svc::mqtt::client::{EspMqttClient, MqttClientConfiguration};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::{events::{Event, EventBus, System as SystemNS}, prop_id, properties::{PropertyID, Variant}, render::props::Output as OutputNS, scenes::props::Scenes as SceneNS, task::Task};
|
||||
use crate::{events::{Event, EventBus, Namespace, Property, System as SystemNS, Variant}, prop_id, render::props::Output as OutputNS, scenes::props::Scenes as SceneNS, task::Task, PropertyID};
|
||||
use crate::platform::props::Board as BoardNS;
|
||||
use paste::paste;
|
||||
|
||||
struct HADevice {
|
||||
prefix: String,
|
||||
@ -118,7 +117,8 @@ impl MqttTask {
|
||||
|
||||
impl Task for MqttTask {
|
||||
fn start(&mut self, bus: &mut EventBus) {
|
||||
bus.set_property(props::MQTT::Online, false);
|
||||
bus.push(props::MQTT::Online.new_property_change(false));
|
||||
|
||||
|
||||
let chip_id = bus.properties().get(BoardNS::ChipID).unwrap().into();
|
||||
self.fps_sensor = Some(HADevice::new("sensor", chip_id, "fps"));
|
||||
@ -126,7 +126,7 @@ impl Task for MqttTask {
|
||||
|
||||
fn on_property_change(&mut self, key: PropertyID, value: &Variant, bus: &mut EventBus) {
|
||||
match (key, value) {
|
||||
(prop_id!(SystemNS::NetworkOnline), Variant::Boolean(true)) => {
|
||||
(prop_id!(System, Online), Variant::Boolean(true)) => {
|
||||
log::info!("Registering with MQTT");
|
||||
|
||||
let chip_id = bus.properties().get(BoardNS::ChipID).unwrap().into();
|
||||
@ -156,10 +156,10 @@ impl Task for MqttTask {
|
||||
}
|
||||
log::info!("MQTT should be online!");
|
||||
|
||||
bus.set_property(props::MQTT::Online, true);
|
||||
bus.push(props::MQTT::Online.new_property_change(true));
|
||||
}
|
||||
},
|
||||
(prop_id!(OutputNS::FPS), Variant::UInt(fps)) => {
|
||||
(prop_id!(Output, FPS), Variant::UInt(fps)) => {
|
||||
if let Some(ref mut client) = self.client {
|
||||
if let Some(ref sensor) = self.fps_sensor {
|
||||
client.enqueue(
|
||||
|
@ -1,6 +1,6 @@
|
||||
use esp_idf_svc::{eventloop::{EspSubscription, EspSystemEventLoop, System}, hal::modem::Modem, netif::IpEvent, nvs::{EspNvsPartition, NvsDefault}, sntp::{EspSntp, SyncStatus}, wifi::{AuthMethod, ClientConfiguration, Configuration, EspWifi, WifiEvent}};
|
||||
|
||||
use crate::{events::{EventBus, System as SystemNS}, properties::Variant, task::Task, time::Periodically};
|
||||
use crate::{events::{EventBus, Variant, System as SystemNS}, task::Task, time::Periodically};
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
@ -66,7 +66,7 @@ impl Task for WifiTask {
|
||||
let mut wifi_bus = bus.clone();
|
||||
self.wifi_sub = Some(self.sys_loop.subscribe::<WifiEvent, _>( move |evt| {
|
||||
log::debug!("wifi event {:?}", evt);
|
||||
wifi_bus.set_property(SystemNS::NetworkOnline,false);
|
||||
wifi_bus.push(SystemNS::NetworkOnline.new_property_change(false));
|
||||
}).unwrap());
|
||||
let mut ip_bus = bus.clone();
|
||||
self.ip_sub = Some(self.sys_loop.subscribe::<IpEvent, _>(move |evt| {
|
||||
@ -99,6 +99,6 @@ impl Task for WifiTask {
|
||||
self.wifi_sub.take().unwrap();
|
||||
self.ip_sub.take().unwrap();
|
||||
self.disconnect();
|
||||
bus.set_property(SystemNS::NetworkOnline, false);
|
||||
bus.push(SystemNS::NetworkOnline.new_property_change(false));
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
use smart_leds_trait::SmartLedsWrite;
|
||||
|
||||
use crate::buffers::Pixbuf;
|
||||
use crate::properties::Variant;
|
||||
use crate::events::Variant;
|
||||
use crate::render::{HardwarePixel, Output, PixelView, Sample, props::Output as OutputNS};
|
||||
use crate::power::brightness_for_mw;
|
||||
use crate::{geometry::*, prop_id};
|
||||
use crate::mappings::*;
|
||||
use paste::paste;
|
||||
|
||||
use core::fmt::Debug;
|
||||
|
||||
@ -58,7 +57,7 @@ impl<P: Pixbuf<Pixel=T::Color>, T: FastWrite> Output for StrideOutput<P, T> {
|
||||
|
||||
fn on_event(&mut self, event: &crate::events::Event) {
|
||||
match event {
|
||||
crate::events::Event::PropertyChange(prop_id!(OutputNS::Brightness), Variant::Byte(new_brightness)) => self.brightness = *new_brightness,
|
||||
crate::events::Event::PropertyChange(prop_id!(Output, Brightness), Variant::Byte(new_brightness)) => self.brightness = *new_brightness,
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
@ -1,270 +0,0 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use rgb::Rgb;
|
||||
pub use paste::paste;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Variant {
|
||||
SignedByte(i8),
|
||||
Byte(u8),
|
||||
UInt(u32),
|
||||
Int(i32),
|
||||
BigUInt(u64),
|
||||
BigInt(i64),
|
||||
Boolean(bool),
|
||||
String(String),
|
||||
RGB(Rgb<u8>),
|
||||
Vec(Vec<Variant>)
|
||||
}
|
||||
|
||||
macro_rules! impl_variant_type {
|
||||
($type:ty, $var_type:tt) => {
|
||||
impl From<$type> for Variant {
|
||||
fn from(value: $type) -> Self {
|
||||
Variant::$var_type(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<$type> for Variant {
|
||||
fn into(self) -> $type {
|
||||
match self {
|
||||
Variant::$var_type(value) => value,
|
||||
_ => panic!(concat!("Expected Variant::", stringify!($var_type), "but got {:?}"), self)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_variant_type!(u8, Byte);
|
||||
impl_variant_type!(i8, SignedByte);
|
||||
impl_variant_type!(u32, UInt);
|
||||
impl_variant_type!(i32, Int);
|
||||
impl_variant_type!(i64, BigInt);
|
||||
impl_variant_type!(u64, BigUInt);
|
||||
impl_variant_type!(bool, Boolean);
|
||||
impl_variant_type!(String, String);
|
||||
impl_variant_type!(Rgb<u8>, RGB);
|
||||
impl_variant_type!(Vec<Variant>, Vec);
|
||||
|
||||
impl<'a> From<&'a str> for Variant {
|
||||
fn from(value: &'a str) -> Self {
|
||||
Variant::String(value.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Property {
|
||||
key: PropertyKey,
|
||||
value: Variant
|
||||
}
|
||||
|
||||
impl Property {
|
||||
pub const fn new(key: PropertyKey, value: Variant) -> Self {
|
||||
Property {
|
||||
key,
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct NamespaceKey(pub &'static str);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct PropertyKey(pub &'static str);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct PropertyID {
|
||||
pub namespace: NamespaceKey,
|
||||
pub key: PropertyKey
|
||||
}
|
||||
|
||||
impl Display for PropertyID {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}::{}", self.namespace.0, self.key.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Namespace {
|
||||
fn nskey() -> NamespaceKey;
|
||||
fn properties() -> Vec<Property>;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! prop_id {
|
||||
($head:ident $(:: $tail:tt)+) => {
|
||||
prop_id!( $head :: ; $($tail),* )
|
||||
};
|
||||
($($namespace:ident ::)+ ; $key:ident ) => {
|
||||
$crate::properties::PropertyID {
|
||||
namespace: $($namespace ::)+ NAMESPACE_KEY,
|
||||
key: paste! { $($namespace ::)+ [<KEY_ $key>] }
|
||||
}
|
||||
};
|
||||
($($namespace:ident ::)+ ; $head:ident , $($tail:ident),+) => {
|
||||
prop_id!( $($namespace ::)* $head :: ; $($tail),* )
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! property_namespace {
|
||||
($name:ident, $($prop_name:ident => $value:expr),*) => {
|
||||
pub enum $name {
|
||||
$($prop_name),*
|
||||
}
|
||||
|
||||
use paste::paste;
|
||||
|
||||
impl crate::properties::Namespace for $name {
|
||||
fn nskey() -> $crate::properties::NamespaceKey {
|
||||
Self::NAMESPACE_KEY
|
||||
}
|
||||
|
||||
fn properties() -> Vec<$crate::properties::Property> {
|
||||
vec![
|
||||
$($crate::properties::Property::new(paste! {Self::[<KEY_ $prop_name>]}, $crate::properties::Variant::from($value)),)*
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
pub const NAMESPACE_KEY: $crate::properties::NamespaceKey = $crate::properties::NamespaceKey(stringify!($name));
|
||||
|
||||
$(paste! { pub const [<KEY_ $prop_name>]: crate::properties::PropertyKey = $crate::properties::PropertyKey(stringify!($prop_name)); })*
|
||||
|
||||
pub const fn key(&self) -> $crate::properties::PropertyKey {
|
||||
match self {
|
||||
$(Self::$prop_name => $crate::properties::PropertyKey(stringify!($prop_name))),*
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn id(&self) -> $crate::properties::PropertyID {
|
||||
$crate::properties::PropertyID { namespace: Self::NAMESPACE_KEY, key: self.key() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<$crate::properties::PropertyID> for $name {
|
||||
fn into(self) -> $crate::properties::PropertyID {
|
||||
self.id()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NamespaceProps {
|
||||
props: Vec<Property>,
|
||||
key: NamespaceKey
|
||||
}
|
||||
|
||||
impl NamespaceProps {
|
||||
fn new<NS: Namespace>() -> Self {
|
||||
NamespaceProps {
|
||||
props: NS::properties(),
|
||||
key: NS::nskey()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_key(&self, key: &PropertyKey) -> Option<&Property> {
|
||||
for next in self.props.iter() {
|
||||
if next.key == *key {
|
||||
return Some(next);
|
||||
}
|
||||
}
|
||||
|
||||
log::warn!("Unknown key {:?}", key);
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
fn get_key_mut(&mut self, key: &PropertyKey) -> Option<&mut Property> {
|
||||
for next in self.props.iter_mut() {
|
||||
if next.key == *key {
|
||||
return Some(next);
|
||||
}
|
||||
}
|
||||
|
||||
log::warn!("Unknown key {:?}", key);
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Properties {
|
||||
contents: Vec<NamespaceProps>
|
||||
}
|
||||
|
||||
impl Display for Properties {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for ns in self.contents.iter() {
|
||||
write!(f, "{}\n", ns.key.0).unwrap();
|
||||
for prop in ns.props.iter() {
|
||||
write!(f, "\t{} = {:?}\n", prop.key.0, prop.value).unwrap();
|
||||
}
|
||||
}
|
||||
Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Properties {
|
||||
pub fn new() -> Self {
|
||||
Properties {
|
||||
contents: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_namespace<T: Namespace>(&mut self) {
|
||||
self.contents.push(NamespaceProps::new::<T>());
|
||||
}
|
||||
|
||||
fn get_namespace(&self, ns: &NamespaceKey) -> Option<&NamespaceProps> {
|
||||
for nsprops in self.contents.iter() {
|
||||
if nsprops.key == *ns {
|
||||
return Some(nsprops)
|
||||
}
|
||||
}
|
||||
|
||||
log::warn!("Unknown namespace {:?}", ns);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn get_namespace_mut(&mut self, ns: &NamespaceKey) -> Option<&mut NamespaceProps> {
|
||||
for nsprops in self.contents.iter_mut() {
|
||||
if nsprops.key == *ns {
|
||||
return Some(nsprops)
|
||||
}
|
||||
}
|
||||
|
||||
log::warn!("Unknown namespace {:?}", ns);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get<T: Into<PropertyID>>(&self, key: T) -> Option<Variant> {
|
||||
let as_id = key.into();
|
||||
match self.get_namespace(&as_id.namespace).unwrap().get_key(&as_id.key) {
|
||||
None => None,
|
||||
Some(v) => Some(v.value.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set<V, T: Into<PropertyID>>(&mut self, key: T, value: V) -> bool where Variant: From<V> {
|
||||
let as_id = key.into();
|
||||
let as_variant: Variant = value.into();
|
||||
match self.get_namespace_mut(&as_id.namespace).unwrap().get_key_mut(&as_id.key) {
|
||||
None => (),
|
||||
Some(found_key) => {
|
||||
if found_key.value != as_variant {
|
||||
found_key.value = as_variant;
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
use rgb::Rgb;
|
||||
use crate::events::*;
|
||||
use crate::properties::*;
|
||||
use crate::geometry::*;
|
||||
use crate::{geometry::*, PropertyID};
|
||||
use crate::lib8::interpolate::Fract8Ops;
|
||||
use crate::power::AsMilliwatts;
|
||||
use crate::task::Task;
|
||||
use crate::time::Periodically;
|
||||
use running_average::RealTimeRunningAverage;
|
||||
use core::fmt::Debug;
|
||||
use std::collections::LinkedList;
|
||||
|
||||
pub trait HardwarePixel: Send + Sync + Copy + AsMilliwatts + Default + From<Rgb<u8>> + Fract8Ops {}
|
||||
impl<T> HardwarePixel for T where T: Send + Sync + Copy + AsMilliwatts + Default + From<Rgb<u8>> + Fract8Ops {}
|
||||
@ -74,7 +74,7 @@ impl<T: Output, S: Surfaces> Renderer<T, S> {
|
||||
impl<T: Output, S: Surfaces> Task for Renderer<T, S> {
|
||||
fn name(&self) -> &'static str { "Renderer" }
|
||||
|
||||
fn on_property_change(&mut self, key: PropertyID, value: &Variant, _bus: &mut EventBus) {
|
||||
fn on_property_change(&mut self, key: PropertyID, value: &crate::events::Variant, _bus: &mut EventBus) {
|
||||
self.output.on_event(&Event::new_property_change(key, value.clone()));
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ impl<T: Output, S: Surfaces> Task for Renderer<T, S> {
|
||||
self.fps.insert((self.frame - self.frame_count) as u32);
|
||||
self.frame_count = self.frame;
|
||||
let fps = self.fps.measurement();
|
||||
bus.set_property(crate::render::props::Output::FPS, fps.rate() as u32);
|
||||
bus.push(crate::render::props::Output::FPS.new_property_change(fps.rate() as u32));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
use crate::task::Task;
|
||||
use crate::events::*;
|
||||
use crate::properties::*;
|
||||
use paste::paste;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
struct Scene {
|
||||
@ -13,7 +11,7 @@ struct Scene {
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
enum Trigger {
|
||||
Startup,
|
||||
PropertyEquals(PropertyID, Variant)
|
||||
PropertyEquals(&'static str, Variant)
|
||||
}
|
||||
|
||||
pub struct Sequencer {
|
||||
@ -34,7 +32,7 @@ impl Sequencer {
|
||||
Scene {
|
||||
name: "Online",
|
||||
patterns: vec!["Idle"],
|
||||
trigger: Trigger::PropertyEquals(prop_id!(System::NetworkOnline), Variant::Boolean(true))
|
||||
trigger: Trigger::PropertyEquals("system.network.online", Variant::Boolean(true))
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -95,18 +93,18 @@ impl Task for Sequencer {
|
||||
log::info!("Starting sequencer!!!");
|
||||
|
||||
let startup_scene = self.scenes.iter().filter(|i| { i.trigger == Trigger::Startup }).next().unwrap();
|
||||
bus.set_property(Scenes::Current, startup_scene.name);
|
||||
bus.push(Scenes::Current.new_property_change(startup_scene.name));
|
||||
let mut scene_list = Vec::new();
|
||||
for scene in self.scenes.iter() {
|
||||
scene_list.push(Variant::String(scene.name.to_string()));
|
||||
}
|
||||
|
||||
bus.set_property(Scenes::All, scene_list);
|
||||
bus.push(Scenes::All.new_property_change(scene_list));
|
||||
}
|
||||
|
||||
fn on_property_change(&mut self, key: PropertyID, value: &Variant, bus: &mut EventBus) {
|
||||
match (key, value) {
|
||||
(prop_id!(Scenes::Current), Variant::String(ref scene_name)) => {
|
||||
(prop_id!(Scenes, Current), Variant::String(ref scene_name)) => {
|
||||
log::info!("Applying scene");
|
||||
self.apply_scene(scene_name, bus);
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
use core::fmt;
|
||||
use std::collections::LinkedList;
|
||||
|
||||
use crate::{events::{Event, EventBus}, properties::{Variant, PropertyID}};
|
||||
use crate::{events::{Event, EventBus, Namespace, Property, Variant}, PropertyID};
|
||||
|
||||
pub trait Task: Send {
|
||||
fn on_ready(&mut self, bus: &mut EventBus) {}
|
||||
@ -12,6 +13,8 @@ pub trait Task: Send {
|
||||
fn name(&self) -> &'static str {
|
||||
core::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn properties(&self) -> LinkedList<Property> { LinkedList::new() }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -141,7 +144,6 @@ impl<const TASK_COUNT: usize> Scheduler for FixedSizeScheduler<TASK_COUNT> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user