1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
use anyhow::Result;
use esp_idf_hal::rmt::{FixedLengthSignal, PinState, Pulse, TxRmtDriver};
use std::time::Duration;
use crate::{
color::{Rgb, BLACK},
infra::{State, Switch},
};
/// Sends an RGB color value to a `NeoPixel` LED using the RMT peripheral.
///
/// # Arguments
///
/// * `rgb` - An `Rgb` struct containing the red, green, and blue color values.
/// * `tx` - A mutable reference to a `TxRmtDriver` used to transmit the signal.
///
/// # Returns
///
/// * `Result<()>` - Returns `Ok(())` if the operation was successful, or an `anyhow::Error` if an error occurred.
///
/// # Errors
///
/// This function will return an error if:
///
/// * There is an issue with the RMT driver, such as failing to retrieve the counter clock frequency.
/// * There is an issue creating the pulses with the specified durations.
/// * There is an issue setting the signal pulses.
/// * There is an issue starting the transmission.
fn neopixel(rgb: &Rgb, tx: &mut TxRmtDriver) -> Result<()> {
let color: u32 = rgb.into();
let ticks_hz = tx.counter_clock()?;
let (t0_high, t0_low, t1_high, t1_low) = (
Pulse::new_with_duration(
ticks_hz,
PinState::High,
&Duration::from_nanos(350),
)?,
Pulse::new_with_duration(
ticks_hz,
PinState::Low,
&Duration::from_nanos(800),
)?,
Pulse::new_with_duration(
ticks_hz,
PinState::High,
&Duration::from_nanos(700),
)?,
Pulse::new_with_duration(
ticks_hz,
PinState::Low,
&Duration::from_nanos(600),
)?,
);
let mut signal = FixedLengthSignal::<24>::new();
for i in (0..24).rev() {
let p = 2_u32.pow(i);
let bit: bool = p & color != 0;
let (high_pulse, low_pulse) = if bit {
(t1_high, t1_low)
} else {
(t0_high, t0_low)
};
signal.set(23 - i as usize, &(high_pulse, low_pulse))?;
}
tx.start_blocking(&signal)?;
Ok(())
}
/// Represents an LED with color and state control.
///
/// # Type Parameters
/// * `'a` - Lifetime of the LED.
pub struct Led<'a> {
color: Rgb,
state: State,
tx_rmt: TxRmtDriver<'a>,
}
impl<'a> Led<'a> {
/// Creates a new `Led` instance.
///
/// # Arguments
/// * `tx_rmt` - A `TxRmtDriver` for controlling the LED.
///
/// # Returns
/// A new `Led` initialized to off with black color.
///
/// # Errors
/// Returns an error if the LED cannot be initialized.
pub fn new(tx_rmt: TxRmtDriver<'a>) -> Result<Self> {
let mut ret = Self {
tx_rmt,
color: BLACK,
state: State::off(),
};
ret.apply()?;
Ok(ret)
}
/// Applies the current state and color to the LED.
///
/// # Errors
/// Returns an error if the LED state or color cannot be applied.
fn apply(&mut self) -> Result<()> {
match self.state {
State::On(_) => neopixel(&self.color, &mut self.tx_rmt),
State::Off => neopixel(&BLACK, &mut self.tx_rmt),
}
}
/// Sets the color of the LED.
///
/// # Arguments
/// * `color` - The new color for the LED.
///
/// # Returns
/// `Ok(())` on success.
///
/// # Errors
/// Returns an error if the color cannot be applied.
pub fn set_color(&mut self, color: Rgb) -> Result<()> {
self.color = color;
self.apply()
}
/// Turns on the LED.
///
/// # Returns
/// `Ok(())` on success.
///
/// # Errors
/// Returns an error if the LED cannot be turned on.
pub fn on(&mut self) -> Result<()> {
self.state = State::on();
self.apply()
}
/// Turns off the LED.
///
/// # Returns
/// `Ok(())` on success.
///
/// # Errors
/// Returns an error if the LED cannot be turned off.
pub fn off(&mut self) -> Result<()> {
self.state = State::off();
self.apply()
}
}
impl Switch for Led<'_> {
/// Toggles the state of the LED.
///
/// # Returns
/// `Ok(())` on success.
///
/// # Errors
/// Returns an error if the LED state cannot be toggled.
fn toggle(&mut self) -> Result<()> {
match self.state {
State::On(_) => self.off(),
State::Off => self.on(),
}
}
}