ws2812_esp32_rmt_driver/
lib_smart_leds.rs

1//! smart-leds driver wrapper API.
2
3use crate::driver::color::{LedPixelColor, LedPixelColorGrb24, LedPixelColorImpl};
4use crate::driver::{Ws2812Esp32RmtDriver, Ws2812Esp32RmtDriverError};
5#[cfg(all(not(feature = "std"), feature = "alloc"))]
6use alloc::vec::Vec;
7use esp_idf_hal::rmt::TxRmtDriver;
8use core::marker::PhantomData;
9#[cfg(feature = "alloc")]
10use smart_leds_trait::SmartLedsWrite;
11use smart_leds_trait::{RGB8, RGBW};
12
13#[cfg(not(target_vendor = "espressif"))]
14use crate::mock::esp_idf_hal;
15use esp_idf_hal::{gpio::OutputPin, peripheral::Peripheral, rmt::RmtChannel};
16
17/// 8-bit RGBW (RGB + white)
18pub type RGBW8 = RGBW<u8, u8>;
19
20impl<
21        const N: usize,
22        const R_ORDER: usize,
23        const G_ORDER: usize,
24        const B_ORDER: usize,
25        const W_ORDER: usize,
26    > From<RGB8> for LedPixelColorImpl<N, R_ORDER, G_ORDER, B_ORDER, W_ORDER>
27{
28    fn from(x: RGB8) -> Self {
29        Self::new_with_rgb(x.r, x.g, x.b)
30    }
31}
32
33impl<
34        const N: usize,
35        const R_ORDER: usize,
36        const G_ORDER: usize,
37        const B_ORDER: usize,
38        const W_ORDER: usize,
39    > From<RGBW8> for LedPixelColorImpl<N, R_ORDER, G_ORDER, B_ORDER, W_ORDER>
40{
41    fn from(x: RGBW8) -> Self {
42        Self::new_with_rgbw(x.r, x.g, x.b, x.a.0)
43    }
44}
45
46/// ws2812-like smart led driver wrapper providing smart-leds API
47///
48/// This is a generalization to handle variants such as SK6812-RGBW 4-color LED.
49/// Use [`Ws2812Esp32Rmt`] for typical RGB LED (WS2812B/SK6812) consisting of 8-bit GRB (total 24-bit pixel).
50///
51/// # Examples
52///
53/// ```
54/// #[cfg(not(target_vendor = "espressif"))]
55/// use ws2812_esp32_rmt_driver::mock::esp_idf_hal;
56///
57/// use esp_idf_hal::peripherals::Peripherals;
58/// use smart_leds::{SmartLedsWrite, White};
59/// use ws2812_esp32_rmt_driver::{LedPixelEsp32Rmt, RGBW8};
60/// use ws2812_esp32_rmt_driver::driver::color::LedPixelColorGrbw32;
61///
62/// let peripherals = Peripherals::take().unwrap();
63/// let led_pin = peripherals.pins.gpio26;
64/// let channel = peripherals.rmt.channel0;
65/// let mut ws2812 = LedPixelEsp32Rmt::<RGBW8, LedPixelColorGrbw32>::new(channel, led_pin).unwrap();
66///
67/// let pixels = std::iter::repeat(RGBW8 {r: 0, g: 0, b: 0, a: White(30)}).take(25);
68/// ws2812.write(pixels).unwrap();
69/// ```
70pub struct LedPixelEsp32Rmt<'d, CSmart, CDev>
71where
72    CDev: LedPixelColor + From<CSmart>,
73{
74    driver: Ws2812Esp32RmtDriver<'d>,
75    phantom: PhantomData<(CSmart, CDev)>,
76}
77
78impl<'d, CSmart, CDev> LedPixelEsp32Rmt<'d, CSmart, CDev>
79where
80    CDev: LedPixelColor + From<CSmart>,
81{
82    /// Create a new driver wrapper.
83    ///
84    /// `channel` shall be different between different `pin`.
85    pub fn new<C: RmtChannel>(
86        channel: impl Peripheral<P = C> + 'd,
87        pin: impl Peripheral<P = impl OutputPin> + 'd,
88    ) -> Result<Self, Ws2812Esp32RmtDriverError> {
89        let driver = Ws2812Esp32RmtDriver::<'d>::new(channel, pin)?;
90        Ok(Self {
91            driver,
92            phantom: Default::default(),
93        })
94    }
95
96    /// Create a new driver wrapper.
97    pub fn new_with_rmt_driver(
98        tx: TxRmtDriver<'d>,
99    ) -> Result<Self, Ws2812Esp32RmtDriverError> {
100        let driver = Ws2812Esp32RmtDriver::<'d>::new_with_rmt_driver(tx)?;
101        Ok(Self {
102            driver,
103            phantom: Default::default(),
104        })
105    }
106}
107
108impl<
109        'd,
110        CSmart,
111        const N: usize,
112        const R_ORDER: usize,
113        const G_ORDER: usize,
114        const B_ORDER: usize,
115        const W_ORDER: usize,
116    > LedPixelEsp32Rmt<'d, CSmart, LedPixelColorImpl<N, R_ORDER, G_ORDER, B_ORDER, W_ORDER>>
117where
118    LedPixelColorImpl<N, R_ORDER, G_ORDER, B_ORDER, W_ORDER>: From<CSmart>,
119{
120    /// Writes pixel data from a color sequence to the driver without data copy
121    ///
122    /// # Errors
123    ///
124    /// Returns an error if an RMT driver error occurred.
125    pub fn write_nocopy<T, I>(&mut self, iterator: T) -> Result<(), Ws2812Esp32RmtDriverError>
126    where
127        T: IntoIterator<Item = I>,
128        I: Into<CSmart>,
129        <T as IntoIterator>::IntoIter: Send,
130    {
131        self.driver
132            .write_blocking(iterator.into_iter().flat_map(|color| {
133                let c =
134                    LedPixelColorImpl::<N, R_ORDER, G_ORDER, B_ORDER, W_ORDER>::from(color.into());
135                c.0
136            }))?;
137        Ok(())
138    }
139}
140
141#[cfg(feature = "alloc")]
142impl<'d, CSmart, CDev> SmartLedsWrite for LedPixelEsp32Rmt<'d, CSmart, CDev>
143where
144    CDev: LedPixelColor + From<CSmart>,
145{
146    type Error = Ws2812Esp32RmtDriverError;
147    type Color = CSmart;
148
149    /// Writes pixel data from a color sequence to the driver
150    ///
151    /// # Errors
152    ///
153    /// Returns an error if an RMT driver error occurred.
154    fn write<T, I>(&mut self, iterator: T) -> Result<(), Self::Error>
155    where
156        T: IntoIterator<Item = I>,
157        I: Into<Self::Color>,
158    {
159        let pixel_data = iterator.into_iter().fold(Vec::new(), |mut vec, color| {
160            vec.extend_from_slice(CDev::from(color.into()).as_ref());
161            vec
162        });
163        self.driver.write_blocking(pixel_data.into_iter())?;
164        Ok(())
165    }
166}
167
168/// 8-bit GRB (total 24-bit pixel) LED driver wrapper providing smart-leds API,
169/// Typical RGB LED (WS2812B/SK6812) driver wrapper providing smart-leds API
170///
171/// # Examples
172///
173/// ```
174/// #[cfg(not(target_vendor = "espressif"))]
175/// use ws2812_esp32_rmt_driver::mock::esp_idf_hal;
176///
177/// use esp_idf_hal::peripherals::Peripherals;
178/// use smart_leds::{RGB8, SmartLedsWrite};
179/// use ws2812_esp32_rmt_driver::Ws2812Esp32Rmt;
180///
181/// let peripherals = Peripherals::take().unwrap();
182/// let led_pin = peripherals.pins.gpio27;
183/// let channel = peripherals.rmt.channel0;
184/// let mut ws2812 = Ws2812Esp32Rmt::new(channel, led_pin).unwrap();
185///
186/// let pixels = std::iter::repeat(RGB8::new(30, 0, 0)).take(25);
187/// ws2812.write(pixels).unwrap();
188/// ```
189pub type Ws2812Esp32Rmt<'d> = LedPixelEsp32Rmt<'d, RGB8, LedPixelColorGrb24>;
190
191#[cfg(test)]
192mod test {
193    use super::*;
194    use crate::mock::esp_idf_hal::peripherals::Peripherals;
195
196    #[test]
197    fn test_ws2812_esp32_rmt_smart_leds() {
198        let sample_data = [RGB8::new(0x00, 0x01, 0x02), RGB8::new(0x03, 0x04, 0x05)];
199        let expected_values: [u8; 6] = [0x01, 0x00, 0x02, 0x04, 0x03, 0x05];
200
201        let peripherals = Peripherals::take().unwrap();
202        let led_pin = peripherals.pins.gpio0;
203        let channel = peripherals.rmt.channel0;
204
205        let mut ws2812 = Ws2812Esp32Rmt::new(channel, led_pin).unwrap();
206        ws2812.write(sample_data.iter().cloned()).unwrap();
207        assert_eq!(ws2812.driver.pixel_data.unwrap(), &expected_values);
208    }
209}