ws2812_uart/
lib.rs

1//! # Use ws2812 leds via UART
2//!
3//! - For usage with `smart-leds`
4//! - Implements the `SmartLedsWrite` trait
5//!
6//! The UART Tx pin has to be inverted (either in software or
7//! in hardware). The UART itself should be pretty fast.
8//! Recommended speed is 3_750_000 baud, 8-N-1.
9
10#![no_std]
11
12use core::marker::PhantomData;
13use smart_leds_trait::{RGB8, RGBW};
14
15pub mod device {
16    pub struct Ws2812;
17    pub struct Sk6812w;
18
19    pub trait Ws2812Like {
20        type Color: super::EncodeColor;
21    }
22
23    impl Ws2812Like for Ws2812 {
24        type Color = super::RGB8;
25    }
26
27    impl Ws2812Like for Sk6812w {
28        type Color = super::RGBW<u8>;
29    }
30}
31
32pub trait EncodeColor {
33    type Bytes: IntoIterator<Item = u8>;
34    fn encode(self) -> Self::Bytes;
35}
36
37impl EncodeColor for RGB8 {
38    type Bytes = [u8; 3];
39    fn encode(self) -> Self::Bytes {
40        [self.g, self.r, self.b]
41    }
42}
43
44impl EncodeColor for RGBW<u8> {
45    type Bytes = [u8; 4];
46    fn encode(self) -> Self::Bytes {
47        [self.g, self.r, self.b, self.a.0]
48    }
49}
50
51pub struct Ws2812<UART, DEV = device::Ws2812> {
52    uart: UART,
53    _device: PhantomData<DEV>,
54}
55
56/// Encode byte as four bytes.
57fn encode_byte(mut byte: u8) -> [u8; 4] {
58    let mut res = [0; 4];
59    for i in 0..4 {
60        res[i] = !(0b_0001_0000
61            | if (byte & 0b_10_00_0000) != 0 {
62                0b_0000_0011
63            } else {
64                0
65            }
66            | if (byte & 0b_01_00_0000) != 0 {
67                0b_0110_0000
68            } else {
69                0
70            });
71        byte <<= 2;
72    }
73    res
74}
75
76impl<UART, DEV> Ws2812<UART, DEV> {
77    /// Construct smart LED output from an UART instance.
78    pub fn new(uart: UART) -> Self {
79        Self {
80            uart,
81            _device: PhantomData,
82        }
83    }
84}
85
86#[cfg(feature = "blocking")]
87mod blocking {
88    use super::{device, encode_byte, EncodeColor, Ws2812};
89    use embedded_io::{ErrorType as BlockingErrorType, Write as BlockingWrite};
90    use smart_leds_trait::SmartLedsWrite;
91
92    impl<UART, DEV> Ws2812<UART, DEV>
93    where
94        UART: BlockingWrite,
95    {
96        fn send_byte(&mut self, byte: u8) -> Result<(), <UART as BlockingErrorType>::Error> {
97            let bytes = encode_byte(byte);
98            self.uart.write_all(&bytes)
99        }
100    }
101
102    impl<UART, DEV> SmartLedsWrite for Ws2812<UART, DEV>
103    where
104        UART: BlockingWrite,
105        DEV: device::Ws2812Like,
106    {
107        type Error = <UART as BlockingErrorType>::Error;
108        type Color = DEV::Color;
109
110        fn write<T, I>(&mut self, iterator: T) -> Result<(), Self::Error>
111        where
112            T: IntoIterator<Item = I>,
113            I: Into<Self::Color>,
114        {
115            for item in iterator {
116                let color = item.into();
117                for byte in color.encode() {
118                    self.send_byte(byte)?;
119                }
120            }
121            Ok(())
122        }
123    }
124}
125
126#[cfg(feature = "async")]
127mod asyncs {
128    use super::{device, encode_byte, EncodeColor, Ws2812};
129    use embedded_io_async::{ErrorType as AsyncErrorType, Write as AsyncWrite};
130    use smart_leds_trait::SmartLedsWriteAsync;
131
132    impl<UART, DEV> Ws2812<UART, DEV>
133    where
134        UART: AsyncWrite,
135    {
136        async fn send_byte_async(
137            &mut self,
138            byte: u8,
139        ) -> Result<(), <UART as AsyncErrorType>::Error> {
140            let bytes = encode_byte(byte);
141            self.uart.write_all(&bytes).await
142        }
143    }
144
145    impl<UART, DEV> SmartLedsWriteAsync for Ws2812<UART, DEV>
146    where
147        UART: AsyncWrite,
148        DEV: device::Ws2812Like,
149    {
150        type Error = <UART as AsyncErrorType>::Error;
151        type Color = DEV::Color;
152
153        async fn write<T, I>(&mut self, iterator: T) -> Result<(), Self::Error>
154        where
155            T: IntoIterator<Item = I>,
156            I: Into<Self::Color>,
157        {
158            for item in iterator {
159                let color = item.into();
160                for byte in color.encode() {
161                    self.send_byte_async(byte).await?;
162                }
163            }
164            Ok(())
165        }
166    }
167}