141 lines
3.6 KiB
Rust
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;
|
|
}
|
|
}
|
|
}
|