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 Self::new_with_ws2812_driver(driver)
119 }
120
121 pub fn new_with_rmt_driver(tx: TxRmtDriver<'d>) -> Result<Self, Ws2812Esp32RmtDriverError> {
142 let driver = Ws2812Esp32RmtDriver::<'d>::new_with_rmt_driver(tx)?;
143 Self::new_with_ws2812_driver(driver)
144 }
145
146 pub fn new_with_ws2812_driver(
147 driver: Ws2812Esp32RmtDriver<'d>,
148 ) -> Result<Self, Ws2812Esp32RmtDriverError> {
149 let data = core::iter::repeat(0)
150 .take(S::pixel_len() * CDev::BPP)
151 .collect::<Data>();
152 Ok(Self {
153 driver,
154 data,
155 brightness: u8::MAX,
156 changed: true,
157 _phantom: Default::default(),
158 })
159 }
160
161 #[inline]
164 pub fn set_brightness(&mut self, brightness: u8) {
165 self.brightness = brightness;
166 self.changed = true;
167 }
168
169 #[inline]
171 pub fn brightness(&self) -> u8 {
172 self.brightness
173 }
174
175 pub fn clear_with_black(&mut self) -> Result<(), Ws2812Esp32RmtDriverError> {
178 self.data.fill(0);
179 self.changed = true;
180 Ok(())
181 }
182
183 pub fn flush(&mut self) -> Result<(), Ws2812Esp32RmtDriverError> {
185 if self.changed {
186 self.driver.write_blocking(self.data.iter().copied())?;
187 self.changed = false;
188 }
189 Ok(())
190 }
191}
192
193impl<'d, CDraw, CDev, S, Data> OriginDimensions for LedPixelDrawTarget<'d, CDraw, CDev, S, Data>
194where
195 CDraw: RgbColor,
196 CDev: LedPixelColor + From<CDraw>,
197 S: LedPixelShape,
198 Data: DerefMut<Target = [u8]> + FromIterator<u8> + IntoIterator<Item = u8>,
199{
200 #[inline]
201 fn size(&self) -> Size {
202 S::size()
203 }
204}
205
206impl<'d, CDraw, CDev, S, Data> DrawTarget for LedPixelDrawTarget<'d, CDraw, CDev, S, Data>
207where
208 CDraw: RgbColor,
209 CDev: LedPixelColor + From<CDraw>,
210 S: LedPixelShape,
211 Data: DerefMut<Target = [u8]> + FromIterator<u8> + IntoIterator<Item = u8>,
212{
213 type Color = CDraw;
214 type Error = Ws2812Esp32RmtDriverError;
215
216 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
217 where
218 I: IntoIterator<Item = Pixel<Self::Color>>,
219 {
220 for Pixel(point, color) in pixels {
221 if let Some(pixel_index) = S::pixel_index(point) {
222 let index = pixel_index * CDev::BPP;
223 let color_device = CDev::from(color).brightness(self.brightness);
224 for (offset, v) in color_device.as_ref().iter().enumerate() {
225 self.data[index + offset] = *v;
226 }
227 self.changed = true;
228 }
229 }
230 Ok(())
231 }
232
233 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
234 let c = CDev::from(color).brightness(self.brightness);
235 for (index, v) in self.data.iter_mut().enumerate() {
236 *v = c.as_ref()[index % CDev::BPP];
237 }
238 self.changed = true;
239 Ok(())
240 }
241}
242
243impl<
244 const N: usize,
245 const R_ORDER: usize,
246 const G_ORDER: usize,
247 const B_ORDER: usize,
248 const W_ORDER: usize,
249 > From<Rgb888> for LedPixelColorImpl<N, R_ORDER, G_ORDER, B_ORDER, W_ORDER>
250{
251 fn from(x: Rgb888) -> Self {
252 Self::new_with_rgb(x.r(), x.g(), x.b())
253 }
254}
255
256pub type LedPixelStrip<const L: usize> = LedPixelMatrix<L, 1>;
258
259pub type Ws2812DrawTarget<'d, S, Data = LedPixelDrawTargetData> =
297 LedPixelDrawTarget<'d, Rgb888, LedPixelColorGrb24, S, Data>;
298
299#[cfg(test)]
300mod test {
301 use super::*;
302 use crate::mock::esp_idf_hal::peripherals::Peripherals;
303
304 #[test]
305 fn test_led_pixel_matrix() {
306 assert_eq!(LedPixelMatrix::<10, 5>::PIXEL_LEN, 50);
307 assert_eq!(LedPixelMatrix::<10, 5>::SIZE, Size::new(10, 5));
308 assert_eq!(LedPixelMatrix::<10, 5>::pixel_len(), 50);
309 assert_eq!(LedPixelMatrix::<10, 5>::size(), Size::new(10, 5));
310 assert_eq!(
311 LedPixelMatrix::<10, 5>::pixel_index(Point::new(0, 0)),
312 Some(0)
313 );
314 assert_eq!(
315 LedPixelMatrix::<10, 5>::pixel_index(Point::new(9, 4)),
316 Some(49)
317 );
318 assert_eq!(
319 LedPixelMatrix::<10, 5>::pixel_index(Point::new(-1, 0)),
320 None
321 );
322 assert_eq!(
323 LedPixelMatrix::<10, 5>::pixel_index(Point::new(0, -1)),
324 None
325 );
326 assert_eq!(
327 LedPixelMatrix::<10, 5>::pixel_index(Point::new(10, 4)),
328 None
329 );
330 assert_eq!(LedPixelMatrix::<10, 5>::pixel_index(Point::new(9, 5)), None);
331 }
332
333 #[test]
334 fn test_led_pixel_strip() {
335 assert_eq!(LedPixelStrip::<10>::PIXEL_LEN, 10);
336 assert_eq!(LedPixelStrip::<10>::SIZE, Size::new(10, 1));
337 assert_eq!(LedPixelStrip::<10>::pixel_len(), 10);
338 assert_eq!(LedPixelStrip::<10>::size(), Size::new(10, 1));
339 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(0, 0)), Some(0));
340 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(9, 0)), Some(9));
341 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(-1, 0)), None);
342 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(0, -1)), None);
343 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(10, 0)), None);
344 assert_eq!(LedPixelStrip::<10>::pixel_index(Point::new(9, 1)), None);
345 }
346
347 #[test]
348 fn test_ws2812draw_target_new() {
349 let peripherals = Peripherals::take().unwrap();
350 let led_pin = peripherals.pins.gpio0;
351 let channel = peripherals.rmt.channel0;
352
353 let draw = Ws2812DrawTarget::<LedPixelMatrix<10, 5>>::new(channel, led_pin).unwrap();
354 assert_eq!(draw.changed, true);
355 assert_eq!(
356 draw.data,
357 core::iter::repeat(0).take(150).collect::<Vec<_>>()
358 );
359 }
360
361 #[test]
362 fn test_ws2812draw_target_new_with_custom_data_struct() {
363 const VEC_CAPACITY: usize = LedPixelMatrix::<10, 5>::PIXEL_LEN * LedPixelColorGrb24::BPP;
364
365 let peripherals = Peripherals::take().unwrap();
366 let led_pin = peripherals.pins.gpio0;
367 let channel = peripherals.rmt.channel0;
368
369 let draw = Ws2812DrawTarget::<LedPixelMatrix<10, 5>, heapless::Vec<u8, VEC_CAPACITY>>::new(
370 channel, led_pin,
371 )
372 .unwrap();
373 assert_eq!(draw.changed, true);
374 assert_eq!(
375 draw.data,
376 core::iter::repeat(0)
377 .take(150)
378 .collect::<heapless::Vec<_, VEC_CAPACITY>>()
379 );
380 }
381
382 #[test]
383 fn test_ws2812draw_target_draw() {
384 let peripherals = Peripherals::take().unwrap();
385 let led_pin = peripherals.pins.gpio1;
386 let channel = peripherals.rmt.channel1;
387
388 let mut draw = Ws2812DrawTarget::<LedPixelMatrix<10, 5>>::new(channel, led_pin).unwrap();
389
390 draw.draw_iter(
391 [
392 Pixel(Point::new(0, 0), Rgb888::new(0x01, 0x02, 0x03)),
393 Pixel(Point::new(9, 4), Rgb888::new(0x04, 0x05, 0x06)),
394 Pixel(Point::new(10, 5), Rgb888::new(0xFF, 0xFF, 0xFF)), ]
396 .iter()
397 .cloned(),
398 )
399 .unwrap();
400 assert_eq!(draw.changed, true);
401 assert_eq!(draw.data[0..3], [0x02, 0x01, 0x03]);
402 assert_eq!(draw.data[3..147], [0x00; 144]);
403 assert_eq!(draw.data[147..150], [0x05, 0x04, 0x06]);
404 draw.changed = false;
405
406 draw.clear(Rgb888::new(0x07, 0x08, 0x0A)).unwrap();
407 assert_eq!(draw.changed, true);
408 assert_eq!(
409 draw.data,
410 core::iter::repeat([0x08, 0x07, 0x0A])
411 .take(50)
412 .flatten()
413 .collect::<Vec<_>>()
414 );
415 draw.changed = false;
416
417 draw.clear_with_black().unwrap();
418 assert_eq!(draw.changed, true);
419 assert_eq!(draw.data, [0x00; 150]);
420 draw.changed = false;
421 }
422
423 #[test]
424 fn test_ws2812draw_target_flush() {
425 let peripherals = Peripherals::take().unwrap();
426 let led_pin = peripherals.pins.gpio2;
427 let channel = peripherals.rmt.channel2;
428
429 let mut draw = Ws2812DrawTarget::<LedPixelMatrix<10, 5>>::new(channel, led_pin).unwrap();
430
431 draw.changed = true;
432 draw.data.fill(0x01);
433 draw.driver.pixel_data = None;
434 draw.flush().unwrap();
435 assert_eq!(draw.driver.pixel_data.unwrap(), draw.data);
436 assert_eq!(draw.changed, false);
437
438 draw.driver.pixel_data = None;
439 draw.flush().unwrap();
440 assert_eq!(draw.driver.pixel_data, None);
441 assert_eq!(draw.changed, false);
442 }
443}