cmdr-joystick/rp2040/src/status_led.rs

141 lines
3.6 KiB
Rust

//! Project: CMtec CMDR joystick 24
//! Date: 2023-08-01
//! Author: Christoffer Martinsson
//! Email: cm@cmtec.se
//! License: Please refer to LICENSE in root directory
use rp2040_hal::{
gpio::{Function, FunctionConfig, Pin, PinId, ValidPinMode},
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,
Activity = 2,
Other = 3,
Warning = 4,
Error = 5,
Bootloader = 6,
}
#[warn(dead_code)]
/// Status LED driver
/// 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<P, SM, I>
where
I: PinId,
P: PIOExt + FunctionConfig,
Function<P>: ValidPinMode<I>,
SM: StateMachineIndex,
{
ws2812_direct: Ws2812Direct<P, SM, I>,
state: bool,
mode: StatusMode,
}
impl<P, SM, I> Ws2812StatusLed<P, SM, I>
where
I: PinId,
P: PIOExt + FunctionConfig,
Function<P>: ValidPinMode<I>,
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: Pin<I, Function<P>>,
pio: &mut PIO<P>,
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
pub fn get_mode(&self) -> StatusMode {
self.mode
}
/// Update status LED
/// Depending on the mode, the LED will be set to a different colour
///
/// * OFF = off
/// * NORMAL = green
/// * ACTIVITY = blue
/// * OTHER = orange
/// * 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; 7] = [
(0, 0, 0).into(), // Off
(10, 7, 0).into(), // Green
(10, 4, 10).into(), // Blue
(5, 10, 0).into(), // Orange
(2, 20, 0).into(), // Red
(2, 20, 0).into(), // Red
(0, 10, 10).into(), // Purple
];
self.mode = mode;
if mode == StatusMode::Warning && !self.state {
self.ws2812_direct
.write([colors[mode as usize]].iter().copied())
.unwrap();
self.state = true;
} else if mode == StatusMode::Warning || 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;
}
}
}