use core::marker::PhantomData;
use embedded_hal::{delay::DelayNs, digital::OutputPin};
#[cfg(feature = "async")]
use embedded_hal_async::delay::DelayNs as DelayNsAsync;
use super::ClocklessLed;
#[cfg(feature = "async")]
use crate::driver::DriverAsync;
use crate::{
color::{ColorCorrection, FromColor, LinearSrgb},
driver::Driver,
util::bits::{u8_to_bits, BitOrder},
};
pub struct ClocklessDelayDriver<Led: ClocklessLed, Pin: OutputPin, Delay> {
led: PhantomData<Led>,
pin: Pin,
delay: Delay,
}
impl<Led, Pin, Delay> ClocklessDelayDriver<Led, Pin, Delay>
where
Led: ClocklessLed,
Pin: OutputPin,
{
pub fn new(mut pin: Pin, delay: Delay) -> Result<Self, Pin::Error> {
pin.set_low()?;
Ok(Self {
led: PhantomData,
delay,
pin,
})
}
}
impl<Led, Pin, Delay> ClocklessDelayDriver<Led, Pin, Delay>
where
Led: ClocklessLed,
Pin: OutputPin,
Delay: DelayNs,
{
fn write_buffer(&mut self, buffer: &[u8]) -> Result<(), Pin::Error> {
for byte in buffer {
for bit in u8_to_bits(byte, BitOrder::MostSignificantBit) {
if !bit {
self.pin.set_high()?;
self.delay.delay_ns(Led::T_0H.to_nanos());
self.pin.set_low()?;
self.delay.delay_ns(Led::T_0L.to_nanos());
} else {
self.pin.set_high()?;
self.delay.delay_ns(Led::T_1H.to_nanos());
self.pin.set_low()?;
self.delay.delay_ns(Led::T_1L.to_nanos());
}
}
}
Ok(())
}
fn delay_for_reset(&mut self) {
self.delay.delay_ns(Led::T_RESET.to_nanos())
}
}
#[cfg(feature = "async")]
impl<Led, Pin, Delay> ClocklessDelayDriver<Led, Pin, Delay>
where
Led: ClocklessLed,
Pin: OutputPin,
Delay: DelayNsAsync,
{
async fn write_buffer_async(&mut self, buffer: &[u8]) -> Result<(), Pin::Error> {
for byte in buffer {
for bit in u8_to_bits(byte, BitOrder::MostSignificantBit) {
if !bit {
self.pin.set_high()?;
self.delay.delay_ns(Led::T_0H.to_nanos()).await;
self.pin.set_low()?;
self.delay.delay_ns(Led::T_0L.to_nanos()).await;
} else {
self.pin.set_high()?;
self.delay.delay_ns(Led::T_1H.to_nanos()).await;
self.pin.set_low()?;
self.delay.delay_ns(Led::T_1L.to_nanos()).await;
}
}
}
Ok(())
}
async fn delay_for_reset_async(&mut self) {
self.delay.delay_ns(Led::T_RESET.to_nanos()).await
}
}
impl<Led, Pin, Delay> Driver for ClocklessDelayDriver<Led, Pin, Delay>
where
Led: ClocklessLed,
Pin: OutputPin,
Delay: DelayNs,
{
type Error = Pin::Error;
type Color = LinearSrgb;
fn write<I, C>(
&mut self,
pixels: I,
brightness: f32,
correction: ColorCorrection,
) -> Result<(), Self::Error>
where
I: IntoIterator<Item = C>,
Self::Color: FromColor<C>,
{
for color in pixels {
let linear_srgb = LinearSrgb::from_color(color);
let data = linear_srgb.to_led(Led::LED_CHANNELS, brightness, correction);
self.write_buffer(data.as_ref())?;
}
self.delay_for_reset();
Ok(())
}
}
#[cfg(feature = "async")]
impl<Led, Pin, Delay> DriverAsync for ClocklessDelayDriver<Led, Pin, Delay>
where
Led: ClocklessLed,
Pin: OutputPin,
Delay: DelayNsAsync,
{
type Error = Pin::Error;
type Color = LinearSrgb;
async fn write<I, C>(
&mut self,
pixels: I,
brightness: f32,
correction: ColorCorrection,
) -> Result<(), Self::Error>
where
I: IntoIterator<Item = C>,
Self::Color: FromColor<C>,
{
for color in pixels {
let linear_srgb = LinearSrgb::from_color(color);
let data = linear_srgb.to_led(Led::LED_CHANNELS, brightness, correction);
self.write_buffer_async(data.as_ref()).await?;
}
self.delay_for_reset_async().await;
Ok(())
}
}