//! Project: CMtec CMDR Keyboard 51 //! Date: 2025-03-09 //! Author: Christoffer Martinsson //! Email: cm@cmtec.se //! License: Please refer to LICENSE in root directory use rp2040_hal::{ gpio::AnyPin, pio::{PIOExt, StateMachineIndex, UninitStateMachine, PIO}, }; use smart_leds::{SmartLedsWrite, RGB8}; use ws2812_pio::Ws2812Direct; /// Status LED modes /// /// * OFF = Syatem offline /// * NORMAL = All system Ok /// * ACTIVITY = System activity /// * OTHER = Other activity /// * WARNING = Warning /// * ERROR = Error /// * BOOTLOADER = Bootloader active #[allow(dead_code)] #[derive(PartialEq, Eq, Copy, Clone)] pub enum StatusMode { Off = 0, Normal = 1, NormalFlash = 2, Activity = 3, ActivityFlash = 4, Other = 5, OtherFlash = 6, Warning = 7, Error = 8, Bootloader = 9, } #[warn(dead_code)] /// This driver uses the PIO state machine to drive a WS2812 LED /// /// # Example /// /// ``` /// let mut status_led = Ws2812StatusLed::new( /// pins.neopixel.into_mode(), /// &mut pio, /// sm0, /// clocks.peripheral_clock.freq(), /// ); /// ``` pub struct Ws2812StatusLed where I: AnyPin, P: PIOExt, SM: StateMachineIndex, { ws2812_direct: Ws2812Direct, state: bool, mode: StatusMode, } impl Ws2812StatusLed where I: AnyPin, P: PIOExt, SM: StateMachineIndex, { /// Creates a new instance of this driver. /// /// # Arguments /// /// * `pin` - PIO pin /// * `pio` - PIO instance /// * `sm` - PIO state machine /// * `clock_freq` - PIO clock frequency pub fn new( pin: I, pio: &mut PIO

, sm: UninitStateMachine<(P, SM)>, clock_freq: fugit::HertzU32, ) -> Self { // prepare the PIO program let ws2812_direct = Ws2812Direct::new(pin, pio, sm, clock_freq); let state = false; let mode = StatusMode::Off; Self { ws2812_direct, state, mode, } } /// Get current status mode #[allow(dead_code)] pub fn get_mode(&self) -> StatusMode { self.mode } #[warn(dead_code)] /// Update status LED /// Depending on the mode, the LED will be set to a different colour /// /// * OFF = off /// * NORMAL = green /// * NORMALFLASH = green (flashing) /// * ACTIVITY = blue /// * ACTIVITYFLASH = blue (flashing) /// * OTHER = orange /// * OTHERFLASH = orange (flashing) /// * WARNING = red (flashing) /// * ERROR = red /// * BOOTLOADER = purple /// /// Make sure to call this function regularly to keep the LED flashing pub fn update(&mut self, mode: StatusMode) { let colors: [RGB8; 10] = [ (0, 0, 0).into(), // Off (10, 7, 0).into(), // Green (10, 7, 0).into(), // Green (10, 4, 10).into(), // Blue (10, 4, 10).into(), // Blue (5, 10, 0).into(), // Orange (5, 10, 0).into(), // Orange (2, 20, 0).into(), // Red (2, 20, 0).into(), // Red (0, 10, 10).into(), // Purple ]; if mode == StatusMode::Warning || mode == StatusMode::NormalFlash || mode == StatusMode::ActivityFlash || mode == StatusMode::OtherFlash || mode != self.mode { self.mode = mode; } else { return; } if (mode == StatusMode::Warning || mode == StatusMode::NormalFlash || mode == StatusMode::ActivityFlash || mode == StatusMode::OtherFlash) && !self.state { self.ws2812_direct .write([colors[mode as usize]].iter().copied()) .unwrap(); self.state = true; } else if mode == StatusMode::Warning || mode == StatusMode::NormalFlash || mode == StatusMode::ActivityFlash || mode == StatusMode::OtherFlash || mode == StatusMode::Off { self.ws2812_direct .write([colors[0]].iter().copied()) .unwrap(); self.state = false; } else { self.ws2812_direct .write([colors[mode as usize]].iter().copied()) .unwrap(); self.state = true; } } }