1use crate::driver::color::{LedPixelColor, LedPixelColorGrb24, LedPixelColorImpl};
4use crate::driver::{Ws2812Esp32RmtDriver, Ws2812Esp32RmtDriverError};
5use core::marker::PhantomData;
6use core::ops::DerefMut;
7use embedded_graphics_core::draw_target::DrawTarget;
8use embedded_graphics_core::geometry::{OriginDimensions, Point, Size};
9use embedded_graphics_core::pixelcolor::{Rgb888, RgbColor};
10use embedded_graphics_core::Pixel;
11use esp_idf_hal::rmt::TxRmtDriver;
12
13#[cfg(not(target_vendor = "espressif"))]
14use crate::mock::esp_idf_hal;
15use esp_idf_hal::{gpio::OutputPin, peripheral::Peripheral, rmt::RmtChannel};
16
17pub trait LedPixelShape {
19 fn pixel_len() -> usize {
21 let size = Self::size();
22 (size.width * size.height) as usize
23 }
24 fn size() -> Size;
26 fn pixel_index(point: Point) -> Option<usize>;
29}
30
31pub struct LedPixelMatrix<const W: usize, const H: usize> {}
33
34impl<const W: usize, const H: usize> LedPixelMatrix<W, H> {
35 pub const SIZE: Size = Size::new(W as u32, H as u32);
37 pub const PIXEL_LEN: usize = W * H;
39}
40
41impl<const W: usize, const H: usize> LedPixelShape for LedPixelMatrix<W, H> {
42 #[inline]
43 fn size() -> Size {
44 Self::SIZE
45 }
46 #[inline]
47 fn pixel_len() -> usize {
48 Self::PIXEL_LEN
49 }
50
51 fn pixel_index(point: Point) -> Option<usize> {
52 if (0..W as i32).contains(&point.x) && (0..H as i32).contains(&point.y) {
53 Some((point.x + point.y * W as i32) as usize)
54 } else {
55 None
56 }
57 }
58}
59
60#[cfg(feature = "std")]
62type LedPixelDrawTargetData = Vec<u8>;
63
64#[cfg(all(not(feature = "std"), feature = "alloc"))]
66type LedPixelDrawTargetData = alloc::vec::Vec<u8>;
67
68#[cfg(all(not(feature = "std"), not(feature = "alloc")))]
71type LedPixelDrawTargetData = heapless::Vec<u8, 256>;
72
73pub struct LedPixelDrawTarget<'d, CDraw, CDev, S, Data = LedPixelDrawTargetData>
90where
91 CDraw: RgbColor,
92 CDev: LedPixelColor + From<CDraw>,
93 S: LedPixelShape,
94 Data: DerefMut<Target = [u8]> + FromIterator<u8> + IntoIterator<Item = u8>,
95{
96 driver: Ws2812Esp32RmtDriver<'d>,
97 data: Data,
98 brightness: u8,
99 changed: bool,
100 _phantom: PhantomData<(CDraw, CDev, S, Data)>,
101}
102
103impl<'d, CDraw, CDev, S, Data> LedPixelDrawTarget<'d, CDraw, CDev, S, Data>
104where
105 CDraw: RgbColor,
106 CDev: LedPixelColor + From<CDraw>,
107 S: LedPixelShape,
108 Data: DerefMut<Target = [u8]> + FromIterator<u8> + IntoIterator<Item = u8>,
109{
110 pub fn new<C: RmtChannel>(
114 channel: impl Peripheral<P = C> + 'd,
115 pin: impl Peripheral<P = impl OutputPin> + 'd,
116 ) -> Result<Self, Ws2812Esp32RmtDriverError> {
117 let driver = Ws2812Esp32RmtDriver::<'d>::new(channel, pin)?;
118 let data = core::iter::repeat(0)
119 .take(S::pixel_len() * CDev::BPP)
120 .collect::<Data>();
121 Ok(Self {
122 driver,
123 data,
124 brightness: u8::MAX,
125 changed: true,
126 _phantom: Default::default(),
127 })
128 }
129
130 pub fn new_with_rmt_driver(
132 tx: TxRmtDriver<'d>,
133 ) -> Result<Self, Ws2812Esp32RmtDriverError> {
134 let driver = Ws2812Esp32RmtDriver::<'d>::new_with_rmt_driver(tx)?;
135 let data = core::iter::repeat(0)
136 .take(S::pixel_len() * CDev::BPP)
137 .collect::<Data>();
138 Ok(Self {
139 driver,
140 data,
141 brightness: u8::MAX,
142 changed: true,
143 _phantom: Default::default(),
144 })
145 }
146
147 #[inline]
150 pub fn set_brightness(&mut self, brightness: u8) {
151 self.brightness = brightness;
152 self.changed = true;
153 }
154
155 #[inline]
157 pub fn brightness(&self) -> u8 {
158 self.brightness
159 }
160
161 pub fn clear_with_black(&mut self) -> Result<(), Ws2812Esp32RmtDriverError> {
164 self.data.fill(0);
165 self.changed = true;
166 Ok(())
167 }
168
169 pub fn flush(&mut self) -> Result<(), Ws2812Esp32RmtDriverError> {
171 if self.changed {
172 self.driver.write_blocking(self.data.iter().copied())?;
173 self.changed = false;
174 }
175 Ok(())
176 }
177}
178
179impl<'d, CDraw, CDev, S, Data> OriginDimensions for LedPixelDrawTarget<'d, CDraw, CDev, S, Data>
180where
181 CDraw: RgbColor,
182 CDev: LedPixelColor + From<CDraw>,
183 S: LedPixelShape,
184 Data: DerefMut<Target = [u8]> + FromIterator<u8> + IntoIterator<Item = u8>,
185{
186 #[inline]
187 fn size(&self) -> Size {
188 S::size()
189 }
190}
191
192impl<'d, CDraw, CDev, S, Data> DrawTarget for LedPixelDrawTarget<'d, CDraw, CDev, S, Data>
193where
194 CDraw: RgbColor,
195 CDev: LedPixelColor + From<CDraw>,
196 S: LedPixelShape,
197 Data: DerefMut<Target = [u8]> + FromIterator<u8> + IntoIterator<Item = u8>,
198{
199 type Color = CDraw;
200 type Error = Ws2812Esp32RmtDriverError;
201
202 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
203 where
204 I: IntoIterator<Item = Pixel<Self::Color>>,
205 {
206 for Pixel(point, color) in pixels {
207 if let Some(pixel_index) = S::pixel_index(point) {
208 let index = pixel_index * CDev::BPP;
209 let color_device = CDev::from(color).brightness(self.brightness);
210 for (offset, v) in color_device.as_ref().iter().enumerate() {
211 self.data[index + offset] = *v;
212 }
213 self.changed = true;
214 }
215 }
216 Ok(())
217 }
218
219 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
220 let c = CDev::from(color).brightness(self.brightness);
221 for (index, v) in self.data.iter_mut().enumerate() {
222 *v = c.as_ref()[index % CDev::BPP];
223 }
224 self.changed = true;
225 Ok(())
226 }
227}
228
229impl<
230 const N: usize,
231 const R_ORDER: usize,
232 const G_ORDER: usize,
233 const B_ORDER: usize,
234 const W_ORDER: usize,
235 > From<Rgb888> for LedPixelColorImpl<N, R_ORDER, G_ORDER, B_ORDER, W_ORDER>
236{
237 fn from(x: Rgb888) -> Self {
238 Self::new_with_rgb(x.r(), x.g(), x.b())
239 }
240}
241
242pub type LedPixelStrip<const L: usize> = LedPixelMatrix<L, 1>;
244
245pub type Ws2812DrawTarget<'d, S, Data = LedPixelDrawTargetData> =
283 LedPixelDrawTarget<'d, Rgb888, LedPixelColorGrb24, S, Data>;
284
285#[cfg(test)]
286mod test {
287 use super::*;
288 use crate::mock::esp_idf_hal::peripherals::Peripherals;
289
290 #[test]
291 fn test_led_pixel_matrix() {
292 assert_eq!(LedPixelMatrix::<10, 5>::PIXEL_LEN, 50);
293 assert_eq!(LedPixelMatrix::<10, 5>::SIZE, Size::new(10, 5));
294 assert_eq!(LedPixelMatrix::<10, 5>::pixel_len(), 50);
295 assert_eq!(LedPixelMatrix::<10, 5>::size(), Size::new(10, 5));
296 assert_eq!(
297 LedPixelMatrix::<10, 5>::pixel_index(Point::new(0, 0)),
298 Some(0)
299 );
300 assert_eq!(
301 LedPixelMatrix::<10, 5>::pixel_index(Point::new(9, 4)),
302 Some(49)
303 );
304 assert_eq!(
305 LedPixelMatrix::<10, 5>::pixel_index(Point::new(-1, 0)),
306 None
307 );
308 assert_eq!(
309 LedPixelMatrix::<10, 5>::pixel_index(Point::new(0, -1)),
310 None
311 );
312 assert_eq!(
313 LedPixelMatrix::<10, 5>::pixel_index(Point::new(10, 4)),
314 None
315 );
316 assert_eq!(LedPixelMatrix::<10, 5>::pixel_index(Point::new(9, 5)), None);
317 }
318
319 #[test]
320 fn test_led_pixel_strip() {
321 assert_eq!(LedPixelStrip::<10>::PIXEL_LEN, 10);
322 assert_eq!(LedPixelStrip::<10>::SIZE, Size::new(10, 1));
323 assert_eq!(LedPixelStrip::<10>::pixel_len(), 10);
324 assert_eq!(LedPixelStrip::<10>::size(), Size::new(10, 1));
325 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(0, 0)), Some(0));
326 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(9, 0)), Some(9));
327 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(-1, 0)), None);
328 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(0, -1)), None);
329 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(10, 0)), None);
330 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(9, 1)), None);
331 }
332
333 #[test]
334 fn test_ws2812draw_target_new() {
335 let peripherals = Peripherals::take().unwrap();
336 let led_pin = peripherals.pins.gpio0;
337 let channel = peripherals.rmt.channel0;
338
339 let draw = Ws2812DrawTarget::<LedPixelMatrix<10, 5>>::new(channel, led_pin).unwrap();
340 assert_eq!(draw.changed, true);
341 assert_eq!(
342 draw.data,
343 core::iter::repeat(0).take(150).collect::<Vec<_>>()
344 );
345 }
346
347 #[test]
348 fn test_ws2812draw_target_new_with_custom_data_struct() {
349 const VEC_CAPACITY: usize = LedPixelMatrix::<10, 5>::PIXEL_LEN * LedPixelColorGrb24::BPP;
350
351 let peripherals = Peripherals::take().unwrap();
352 let led_pin = peripherals.pins.gpio0;
353 let channel = peripherals.rmt.channel0;
354
355 let draw = Ws2812DrawTarget::<LedPixelMatrix<10, 5>, heapless::Vec<u8, VEC_CAPACITY>>::new(
356 channel, led_pin,
357 )
358 .unwrap();
359 assert_eq!(draw.changed, true);
360 assert_eq!(
361 draw.data,
362 core::iter::repeat(0)
363 .take(150)
364 .collect::<heapless::Vec<_, VEC_CAPACITY>>()
365 );
366 }
367
368 #[test]
369 fn test_ws2812draw_target_draw() {
370 let peripherals = Peripherals::take().unwrap();
371 let led_pin = peripherals.pins.gpio1;
372 let channel = peripherals.rmt.channel1;
373
374 let mut draw = Ws2812DrawTarget::<LedPixelMatrix<10, 5>>::new(channel, led_pin).unwrap();
375
376 draw.draw_iter(
377 [
378 Pixel(Point::new(0, 0), Rgb888::new(0x01, 0x02, 0x03)),
379 Pixel(Point::new(9, 4), Rgb888::new(0x04, 0x05, 0x06)),
380 Pixel(Point::new(10, 5), Rgb888::new(0xFF, 0xFF, 0xFF)), ]
382 .iter()
383 .cloned(),
384 )
385 .unwrap();
386 assert_eq!(draw.changed, true);
387 assert_eq!(draw.data[0..3], [0x02, 0x01, 0x03]);
388 assert_eq!(draw.data[3..147], [0x00; 144]);
389 assert_eq!(draw.data[147..150], [0x05, 0x04, 0x06]);
390 draw.changed = false;
391
392 draw.clear(Rgb888::new(0x07, 0x08, 0x0A)).unwrap();
393 assert_eq!(draw.changed, true);
394 assert_eq!(
395 draw.data,
396 core::iter::repeat([0x08, 0x07, 0x0A])
397 .take(50)
398 .flatten()
399 .collect::<Vec<_>>()
400 );
401 draw.changed = false;
402
403 draw.clear_with_black().unwrap();
404 assert_eq!(draw.changed, true);
405 assert_eq!(draw.data, [0x00; 150]);
406 draw.changed = false;
407 }
408
409 #[test]
410 fn test_ws2812draw_target_flush() {
411 let peripherals = Peripherals::take().unwrap();
412 let led_pin = peripherals.pins.gpio2;
413 let channel = peripherals.rmt.channel2;
414
415 let mut draw = Ws2812DrawTarget::<LedPixelMatrix<10, 5>>::new(channel, led_pin).unwrap();
416
417 draw.changed = true;
418 draw.data.fill(0x01);
419 draw.driver.pixel_data = None;
420 draw.flush().unwrap();
421 assert_eq!(draw.driver.pixel_data.unwrap(), draw.data);
422 assert_eq!(draw.changed, false);
423
424 draw.driver.pixel_data = None;
425 draw.flush().unwrap();
426 assert_eq!(draw.driver.pixel_data, None);
427 assert_eq!(draw.changed, false);
428 }
429}