owb_core/utils/controllers/leds.rs
1//! LED control module for the Omni-Wheel Bot.
2//!
3//! Manages an addressable LED strip via `SmartLedsWrite` and dispatches commands
4//! received over `LED_CHANNEL`.
5
6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use serde::{Deserialize, Serialize};
8use smart_leds_trait::{SmartLedsWrite, RGB8};
9
10/// Channel used to receive LED commands (`LEDCommand` messages).
11pub static LED_CHANNEL: embassy_sync::channel::Channel<CriticalSectionRawMutex, LEDCommand, 16> =
12 embassy_sync::channel::Channel::new();
13
14/// Number of LEDs in the attached chain.
15const LED_COUNT: usize = 2;
16
17/// LED command variants for switching on/off or setting a color.
18///
19/// Serialized as JSON with tag `"lc"`.
20#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
21#[serde(tag = "lc", rename_all = "snake_case")]
22pub enum LEDCommand {
23 /// Turn the LEDs on (last color or white).
24 On,
25 /// Turn all LEDs off (set to black).
26 Off,
27 /// Set the LED strip to the given RGB color.
28 SC { r: u8, g: u8, b: u8 },
29}
30
31/// High-level LED controller that drives a strip of addressable LEDs.
32///
33/// Maintains the on/off state and last selected color.
34pub struct LedModule<Driver> {
35 driver: Driver,
36 is_on: bool,
37 last_color: Option<RGB8>,
38}
39
40impl<Driver, E> LedModule<Driver>
41where
42 Driver: SmartLedsWrite<Color = RGB8, Error = E>,
43{
44 /// Create a new `LedModule` over the given LED driver.
45 ///
46 /// The strip is initially off with no last color.
47 pub fn new(driver: Driver) -> Self {
48 Self {
49 driver,
50 is_on: false,
51 last_color: None,
52 }
53 }
54
55 /// Execute an incoming `LEDCommand`, updating internal state and LED strip.
56 ///
57 /// - `On`: enable LEDs with the last color or white.
58 /// - `Off`: disable LEDs (all black).
59 /// - `SC {r,g,b}`: set a new color, applied immediately if strip is on.
60 pub fn ex_command(
61 &mut self,
62 cmd: LEDCommand,
63 ) -> Result<(), E> {
64 match cmd {
65 LEDCommand::On => {
66 self.is_on = true;
67 let color = self.last_color.unwrap_or(RGB8 {
68 r: 255,
69 g: 255,
70 b: 255,
71 });
72 self.set_all(color)?;
73 }
74 LEDCommand::Off => {
75 self.is_on = false;
76 self.set_all(RGB8 { r: 0, g: 0, b: 0 })?;
77 }
78 LEDCommand::SC { r, g, b } => {
79 let new_color = RGB8 { r, g, b };
80 self.last_color = Some(new_color);
81 if self.is_on {
82 self.set_all(new_color)?;
83 }
84 }
85 }
86 Ok(())
87 }
88
89 /// Set all LEDs in the strip to the specified color.
90 fn set_all(
91 &mut self,
92 color: RGB8,
93 ) -> Result<(), E> {
94 let data = core::iter::repeat(color).take(LED_COUNT);
95 self.driver.write(data)
96 }
97}