//! 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 ,
state: bool,
mode: StatusMode,
}
impl Ws2812StatusLed
where
I: AnyPin ,
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;
}
}
}