ws2812_async/
lib.rs

1#![no_std]
2use core::marker::PhantomData;
3
4use embedded_hal_async::spi::{ErrorType, SpiBus};
5use smart_leds_trait::{SmartLedsWriteAsync, RGB8};
6
7const PATTERNS: [u8; 4] = [0b1000_1000, 0b1000_1110, 0b1110_1000, 0b1110_1110];
8
9/// Trait for color order reordering
10pub trait OrderedColors {
11    fn order(color: RGB8) -> [u8; 3];
12}
13
14/// Marker struct for RGB order
15pub struct Rgb;
16
17/// Marker struct for GRB order
18pub struct Grb;
19
20impl OrderedColors for Rgb {
21    fn order(color: RGB8) -> [u8; 3] {
22        [color.r, color.g, color.b]
23    }
24}
25
26impl OrderedColors for Grb {
27    fn order(color: RGB8) -> [u8; 3] {
28        [color.g, color.r, color.b]
29    }
30}
31
32/// N = 12 * NUM_LEDS
33pub struct Ws2812<SPI: SpiBus<u8>, C: OrderedColors, const N: usize> {
34    spi: SPI,
35    data: [u8; N],
36    _color_order: PhantomData<C>,
37}
38
39impl<SPI: SpiBus<u8>, C: OrderedColors, const N: usize> Ws2812<SPI, C, N> {
40    /// Create a new WS2812 driver, with the given SPI bus
41    /// Colors default to RGB order
42    pub fn new(spi: SPI) -> Self {
43        Self {
44            spi,
45            data: [0; N],
46            _color_order: PhantomData,
47        }
48    }
49}
50
51impl<SPI, E, C: OrderedColors, const N: usize> SmartLedsWriteAsync for Ws2812<SPI, C, N>
52where
53    SPI: SpiBus<u8, Error = E>,
54{
55    type Error = E;
56    type Color = RGB8;
57
58    async fn write<T, I>(&mut self, iter: T) -> Result<(), <SPI as ErrorType>::Error>
59    where
60        T: IntoIterator<Item = I>,
61        I: Into<Self::Color>,
62    {
63        for (led_bytes, rgb8) in self.data.chunks_mut(12).zip(iter) {
64            let colors = C::order(rgb8.into());
65            for (i, mut color) in colors.into_iter().enumerate() {
66                for ii in 0..4 {
67                    led_bytes[i * 4 + ii] = PATTERNS[((color & 0b1100_0000) >> 6) as usize];
68                    color <<= 2;
69                }
70            }
71        }
72        self.spi.write(&self.data).await?;
73        let blank = [0_u8; 140];
74        self.spi.write(&blank).await
75    }
76}