micro-rust/src/state.rs

88 lines
2.5 KiB
Rust
Raw Normal View History

2024-10-17 10:02:00 +00:00
//! 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<CriticalSectionRawMutex, StateChange, 4, 4, 4> =
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()));
}
}
}