#![no_std]
use embedded_hal::digital::OutputPin;
#[cfg(feature = "async")]
use embedded_hal_async::digital::Wait;
#[cfg(not(feature = "spinloop_delay"))]
use embedded_hal::delay::DelayNs;
#[cfg(feature = "own_delay")]
pub struct WS2812<'a, LED, D> {
led: LED,
delay: &'a mut D,
}
#[cfg(feature = "manual_delay")]
pub struct WS2812<LED> {
led: LED,
}
#[cfg(feature = "spinloop_delay")]
pub struct WS2812<LED> {
led: LED,
cpu_freq: u64,
}
#[cfg(feature = "own_delay")]
impl<'a, LED, D: DelayNs> WS2812<'a, LED, D> {
pub fn new(led: LED, delay: &'a mut D) -> Self {
Self { led, delay }
}
pub fn destroy(self) -> LED {
self.led
}
}
#[cfg(feature = "manual_delay")]
impl<LED> WS2812<LED> {
pub fn new(led: LED) -> Self {
Self { led }
}
pub fn destroy(self) -> LED {
self.led
}
}
#[cfg(feature = "spinloop_delay")]
impl<LED> WS2812<LED> {
pub fn new(led: LED, cpu_freq: u64) -> Self {
Self { led, cpu_freq }
}
pub fn destroy(self) -> LED {
self.led
}
}
pub trait TransferTiming {
fn t0h() -> u32;
fn t1h() -> u32;
fn t0l() -> u32;
fn t1l() -> u32;
fn reset() -> u32;
}
pub trait AsyncGlowColor: TransferTiming {
#[cfg(not(feature = "manual_delay"))]
fn delay_ns(&mut self, ns: u32) -> impl core::future::Future<Output = ()>;
fn wait_for_low(&mut self) -> impl core::future::Future<Output = ()>;
fn wait_for_high(&mut self) -> impl core::future::Future<Output = ()>;
#[cfg(not(feature = "manual_delay"))]
fn async_send_color<const N: usize>(
&mut self,
color: [Color; N],
) -> impl core::future::Future<Output = ()> {
async move {
for each_color in color {
for byte in each_color.0 {
for bit in (0..8).rev() {
if (byte & (1 << bit)) != 0 {
self.wait_for_high().await;
self.delay_ns(Self::t1h()).await;
self.wait_for_low().await;
self.delay_ns(Self::t1l()).await;
} else {
self.wait_for_high().await;
self.delay_ns(Self::t0h()).await;
self.wait_for_low().await;
self.delay_ns(Self::t0l()).await;
}
}
}
}
self.wait_for_low().await;
self.delay_ns(Self::reset()).await
}
}
#[cfg(feature = "manual_delay")]
fn async_send_color<const N: usize, D: DelayNs>(
&mut self,
color: [Color; N],
delay: &mut D,
) -> impl core::future::Future<Output = ()> {
async move {
for each_color in color {
for byte in each_color.0 {
for bit in (0..8).rev() {
if (byte & (1 << bit)) != 0 {
self.wait_for_high().await;
delay.delay_ns(Self::t1h());
self.wait_for_low().await;
delay.delay_ns(Self::t1l());
} else {
self.wait_for_high().await;
delay.delay_ns(Self::t0h());
self.wait_for_low().await;
delay.delay_ns(Self::t0l());
}
}
}
}
self.wait_for_low().await;
delay.delay_ns(Self::reset())
}
}
}
pub trait GlowColor: TransferTiming {
#[cfg(not(feature = "manual_delay"))]
fn delay_ns(&mut self, ns: u32);
fn led_low(&mut self);
fn led_high(&mut self);
#[cfg(not(feature = "manual_delay"))]
fn send_color<const N: usize>(&mut self, color: [Color; N]) {
for each_color in color {
for byte in each_color.0 {
for bit in (0..8).rev() {
if (byte & (1 << bit)) != 0 {
self.led_high();
self.delay_ns(Self::t1h());
self.led_low();
self.delay_ns(Self::t1l());
} else {
self.led_high();
self.delay_ns(Self::t0h());
self.led_low();
self.delay_ns(Self::t0l());
}
}
}
}
self.led_low();
self.delay_ns(Self::reset())
}
#[cfg(feature = "manual_delay")]
fn send_color<const N: usize, D: DelayNs>(&mut self, color: [Color; N], delay: &mut D) {
for each_color in color {
for byte in each_color.0 {
for bit in (0..8).rev() {
if (byte & (1 << bit)) != 0 {
self.led_high();
delay.delay_ns(Self::t1h());
self.led_low();
delay.delay_ns(Self::t1l());
} else {
self.led_high();
delay.delay_ns(Self::t0h());
self.led_low();
delay.delay_ns(Self::t0l());
}
}
}
}
self.led_low();
delay.delay_ns(Self::reset())
}
#[cfg(feature = "async")]
#[cfg(not(feature = "manual_delay"))]
fn send_color_w_embassy<const N: usize>(
&mut self,
color: [Color; N],
) -> impl Future<Output = ()> {
async move {
for each_color in color {
for byte in each_color.0 {
for bit in (0..8).rev() {
if (byte & (1 << bit)) != 0 {
self.led_high();
embassy_time::Timer::after_nanos(Self::t1h() as u64).await;
self.led_low();
embassy_time::Timer::after_nanos(Self::t1l() as u64).await;
} else {
self.led_high();
embassy_time::Timer::after_nanos(Self::t0h() as u64).await;
self.led_low();
embassy_time::Timer::after_nanos(Self::t0l() as u64).await;
}
}
}
self.led_low();
embassy_time::Timer::after_nanos(Self::reset() as u64).await;
}
}
}
}
#[derive(Default, Clone)]
pub struct Color(pub [u8; 3]);
impl Color {
pub const fn red() -> Self {
Self([255, 0, 0])
}
pub const fn green() -> Self {
Self([0, 255, 0]) }
pub const fn blue() -> Self {
Self([0, 0, 255]) }
pub const fn cyan() -> Self {
Self([0, 255, 255]) }
pub const fn magenta() -> Self {
Self([255, 0, 255]) }
pub const fn yellow() -> Self {
Self([255, 255, 0]) }
pub const fn white() -> Self {
Self([255, 255, 255]) }
pub const fn orange() -> Self {
Self([255, 165, 0]) }
pub const fn purple() -> Self {
Self([128, 0, 128]) }
pub const fn pink() -> Self {
Self([255, 192, 203]) }
pub const fn brown() -> Self {
Self([165, 42, 42]) }
}
#[cfg(feature = "own_delay")]
impl<'a, LED, D> TransferTiming for WS2812<'a, LED, D> {
fn t0h() -> u32 {
350
}
fn t1h() -> u32 {
700
}
fn t0l() -> u32 {
800
}
fn t1l() -> u32 {
600
}
fn reset() -> u32 {
50
}
}
#[cfg(feature = "own_delay")]
impl<'a, LED: OutputPin, D: DelayNs> GlowColor for WS2812<'a, LED, D> {
fn led_low(&mut self) {
self.led.set_low().ok();
}
fn delay_ns(&mut self, ns: u32) {
self.delay.delay_ns(ns);
}
fn led_high(&mut self) {
self.led.set_high().ok();
}
}
#[cfg(feature = "async")]
#[cfg(feature = "own_delay")]
impl<'a, LED: Wait, D> AsyncGlowColor for WS2812<'a, LED, D> {
async fn wait_for_high(&mut self) {
self.led.wait_for_high().await.ok();
}
async fn delay_ns(&mut self, ns: u32) {
embassy_time::Timer::after_nanos(ns as u64).await
}
async fn wait_for_low(&mut self) {
self.led.wait_for_low().await.ok();
}
}
#[cfg(feature = "spinloop_delay")]
impl<'a, LED> TransferTiming for WS2812<LED> {
fn t0h() -> u32 {
350
}
fn t1h() -> u32 {
700
}
fn t0l() -> u32 {
800
}
fn t1l() -> u32 {
600
}
fn reset() -> u32 {
50
}
}
#[cfg(feature = "spinloop_delay")]
impl<LED: OutputPin> GlowColor for WS2812<LED> {
fn led_low(&mut self) {
self.led.set_low().ok();
}
fn delay_ns(&mut self, ns: u32) {
let cycle = (self.cpu_freq * ns as u64) / 1_000_000_000;
for _ in 0..cycle as u32 {
core::hint::spin_loop();
}
}
fn led_high(&mut self) {
self.led.set_high().ok();
}
}
#[cfg(feature = "async")]
#[cfg(feature = "spinloop_delay")]
impl<LED: Wait> AsyncGlowColor for WS2812<LED> {
async fn wait_for_high(&mut self) {
self.led.wait_for_high().await.ok();
}
async fn delay_ns(&mut self, ns: u32) {
embassy_time::Timer::after_nanos(ns as u64).await
}
async fn wait_for_low(&mut self) {
self.led.wait_for_low().await.ok();
}
}
#[cfg(feature = "manual_delay")]
impl<'a, LED> TransferTiming for WS2812<LED> {
fn t0h() -> u32 {
350
}
fn t1h() -> u32 {
700
}
fn t0l() -> u32 {
800
}
fn t1l() -> u32 {
600
}
fn reset() -> u32 {
50
}
}
#[cfg(feature = "manual_delay")]
impl<LED: OutputPin> GlowColor for WS2812<LED> {
fn led_low(&mut self) {
self.led.set_low().ok();
}
fn led_high(&mut self) {
self.led.set_high().ok();
}
}
#[cfg(feature = "async")]
#[cfg(feature = "manual_delay")]
impl<LED: Wait> AsyncGlowColor for WS2812<LED> {
async fn wait_for_high(&mut self) {
self.led.wait_for_high().await.ok();
}
async fn wait_for_low(&mut self) {
self.led.wait_for_low().await.ok();
}
}