//! Bare bones state with pubsub access. //! For more ergonomic access it might be nice to allow clients to subscribe to only the parts they //! are interested in instead of the whole thing. use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pubsub::PubSubChannel}; use crate::{ leds::Matrix, patterns::{PATTERNS, PATTERN_COUNT}, }; pub struct State { pattern_idx: usize, patterns: [Matrix; PATTERN_COUNT], } impl Default for State { fn default() -> Self { Self { pattern_idx: Default::default(), patterns: PATTERNS, } } } impl State { /// Switch to the next pattern on the left. /// Wrap around to the last if it is already the first one. pub fn pattern_left(&mut self) { self.pattern_idx = if self.pattern_idx == 0 { self.patterns.len() - 1 } else { self.pattern_idx - 1 }; } /// Switch to the next pattern on the right. /// Wrap around to the first if it is already the last one. pub fn pattern_right(&mut self) { self.pattern_idx = if self.pattern_idx == self.patterns.len() - 1 { 0 } else { self.pattern_idx + 1 }; } /// Return the active patern. pub fn pattern(&self) -> Matrix { self.patterns[self.pattern_idx] } } #[derive(Clone, Copy)] pub enum StateChange { /// Switch to the paatternon the left of the active one. PatternLeft, /// Switch to the paatternon the right of the active one. PatternRight, /// Publish a new active pattern. Pattern(Matrix), } /// PubSub channel to listen to state changes and publish them as well. pub static STATE: PubSubChannel = PubSubChannel::new(); /// Subscribe to state change messages and update the state accordingly. /// Publish when a new pattern is active. #[embassy_executor::task] pub async fn task() { let mut state = State::default(); let state_pub = STATE.publisher().unwrap(); let mut state_sub = STATE.subscriber().unwrap(); loop { let old_pattern = state.pattern(); match state_sub.next_message_pure().await { StateChange::PatternLeft => state.pattern_left(), StateChange::PatternRight => state.pattern_right(), _ => (), } if old_pattern != state.pattern() { state_pub.publish_immediate(StateChange::Pattern(state.pattern())); } } }