use core::marker::PhantomData;
use heapless::Vec;
#[cfg(feature = "async")]
use crate::driver::DriverAsync;
use crate::{
color::{ColorCorrection, FromColor, LedChannels, LedColor, LinearSrgb},
driver::Driver,
time::Nanoseconds,
util::component::Component,
};
mod delay;
pub use self::delay::*;
pub trait ClocklessLed {
type Word: Component;
const T_0H: Nanoseconds;
const T_0L: Nanoseconds;
const T_1H: Nanoseconds;
const T_1L: Nanoseconds;
const T_RESET: Nanoseconds;
const LED_CHANNELS: LedChannels;
fn t_cycle() -> Nanoseconds {
(Self::T_0H + Self::T_0L).max(Self::T_1H + Self::T_1L)
}
fn encode<const PIXEL_COUNT: usize, const BUFFER_SIZE: usize, I, C>(
pixels: I,
brightness: f32,
correction: ColorCorrection,
) -> Vec<Self::Word, BUFFER_SIZE>
where
I: IntoIterator<Item = C>,
LinearSrgb: FromColor<C>,
{
Vec::from_iter(pixels.into_iter().flat_map(|pixel| {
let linear_srgb = LinearSrgb::from_color(pixel);
let data: LedColor<Self::Word> =
linear_srgb.to_led(Self::LED_CHANNELS, brightness, correction);
data.into_iter()
}))
}
}
pub trait ClocklessWriter<Led: ClocklessLed> {
type Error;
fn write<const FRAME_BUFFER_SIZE: usize>(
&mut self,
frame: Vec<Led::Word, FRAME_BUFFER_SIZE>,
) -> Result<(), Self::Error>;
}
#[cfg(feature = "async")]
pub trait ClocklessWriterAsync<Led: ClocklessLed> {
type Error;
#[allow(async_fn_in_trait)]
async fn write<const FRAME_BUFFER_SIZE: usize>(
&mut self,
frame: Vec<Led::Word, FRAME_BUFFER_SIZE>,
) -> Result<(), Self::Error>;
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ClocklessDriver<Led, Writer> {
led: PhantomData<Led>,
writer: Writer,
}
impl Default for ClocklessDriver<(), ()> {
fn default() -> Self {
ClocklessDriver {
led: PhantomData,
writer: (),
}
}
}
impl<Writer> ClocklessDriver<(), Writer> {
pub fn with_led<Led>(self) -> ClocklessDriver<Led, Writer> {
ClocklessDriver {
led: PhantomData,
writer: self.writer,
}
}
}
impl<Led> ClocklessDriver<Led, ()> {
pub fn with_writer<Writer>(self, writer: Writer) -> ClocklessDriver<Led, Writer> {
ClocklessDriver {
led: self.led,
writer,
}
}
}
impl<Led, Writer> Driver for ClocklessDriver<Led, Writer>
where
Led: ClocklessLed,
Writer: ClocklessWriter<Led>,
{
type Error = Writer::Error;
type Color = LinearSrgb;
type Word = Led::Word;
fn encode<const PIXEL_COUNT: usize, const FRAME_BUFFER_SIZE: usize, I, C>(
&mut self,
pixels: I,
brightness: f32,
correction: ColorCorrection,
) -> Vec<Self::Word, FRAME_BUFFER_SIZE>
where
I: IntoIterator<Item = C>,
Self::Color: FromColor<C>,
{
Led::encode::<PIXEL_COUNT, FRAME_BUFFER_SIZE, _, _>(pixels, brightness, correction)
}
fn write<const FRAME_BUFFER_SIZE: usize>(
&mut self,
frame: Vec<Self::Word, FRAME_BUFFER_SIZE>,
_brightness: f32,
_correction: ColorCorrection,
) -> Result<(), Self::Error> {
self.writer.write(frame)
}
}
#[cfg(feature = "async")]
impl<Led, Writer> DriverAsync for ClocklessDriver<Led, Writer>
where
Led: ClocklessLed,
Writer: ClocklessWriterAsync<Led>,
{
type Error = Writer::Error;
type Color = LinearSrgb;
type Word = Led::Word;
fn encode<const PIXEL_COUNT: usize, const FRAME_BUFFER_SIZE: usize, I, C>(
&mut self,
pixels: I,
brightness: f32,
correction: ColorCorrection,
) -> Vec<Self::Word, FRAME_BUFFER_SIZE>
where
I: IntoIterator<Item = C>,
Self::Color: FromColor<C>,
{
Led::encode::<PIXEL_COUNT, FRAME_BUFFER_SIZE, _, _>(pixels, brightness, correction)
}
async fn write<const FRAME_BUFFER_SIZE: usize>(
&mut self,
frame: Vec<Self::Word, FRAME_BUFFER_SIZE>,
) -> Result<(), Self::Error> {
self.writer.write(frame).await
}
}