use esp_hal::dma::DmaChannelFor;
use esp_hal::dma::DmaDescriptor;
use esp_hal::dma::DmaError;
use esp_hal::dma::DmaTxBuf;
use esp_hal::gpio::AnyPin;
use esp_hal::gpio::NoPin;
use esp_hal::i2s::parallel::I2sParallel;
use esp_hal::i2s::parallel::I2sParallelTransfer;
use esp_hal::i2s::parallel::TxEightBits;
use esp_hal::i2s::parallel::TxPins;
use esp_hal::i2s::parallel::TxSixteenBits;
use esp_hal::i2s::AnyI2s;
#[cfg(feature = "iram")]
use esp_hal::ram;
use esp_hal::time::Rate;
use crate::framebuffer::FrameBuffer;
use crate::Hub75Error;
use crate::Hub75Pins;
use crate::Hub75Pins16;
use crate::Hub75Pins8;
pub struct Hub75<'d, DM: esp_hal::DriverMode> {
i2s: I2sParallel<'d, DM>,
tx_descriptors: &'static mut [DmaDescriptor],
}
impl<'d> Hub75<'d, esp_hal::Blocking> {
pub fn new<T: TxPins<'d>>(
i2s: AnyI2s<'d>,
hub75_pins: impl Hub75Pins<'d, T>,
channel: impl DmaChannelFor<AnyI2s<'d>>,
tx_descriptors: &'static mut [DmaDescriptor],
frequency: Rate,
) -> Result<Self, Hub75Error> {
let (pins, clock) = hub75_pins.convert_pins();
#[cfg(not(feature = "invert-clock"))]
let clock = clock.into_output_signal().with_output_inverter(true);
let i2s = I2sParallel::new(i2s, channel, frequency, pins, clock);
Ok(Self {
i2s,
tx_descriptors,
})
}
pub fn into_async(self) -> Hub75<'d, esp_hal::Async> {
Hub75 {
i2s: self.i2s.into_async(),
tx_descriptors: self.tx_descriptors,
}
}
}
impl<'d, DM: esp_hal::DriverMode> Hub75<'d, DM> {
#[cfg_attr(feature = "iram", ram)]
pub fn render<
const ROWS: usize,
const COLS: usize,
const NROWS: usize,
const BITS: u8,
const FRAME_COUNT: usize,
>(
self,
fb: &impl FrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>,
) -> Result<Hub75Transfer<'d, DM>, (Hub75Error, Self)> {
let i2s = self.i2s;
let tx_descriptors = self.tx_descriptors;
let tx_buffer = unsafe {
let (ptr, len) = fb.read_buffer();
core::slice::from_raw_parts_mut(ptr as *mut u8, len)
};
let tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).expect("DmaTxBuf::new failed");
let xfer = i2s.send(tx_buf).map_err(|(e, i2s, buf)| {
let (tx_descriptors, _) = buf.split();
(
e.into(),
Self {
i2s,
tx_descriptors,
},
)
})?;
Ok(Hub75Transfer { xfer })
}
}
pub struct Hub75Transfer<'d, DM: esp_hal::DriverMode> {
xfer: I2sParallelTransfer<'d, DmaTxBuf, DM>,
}
impl<'d, DM: esp_hal::DriverMode> Hub75Transfer<'d, DM> {
#[cfg_attr(feature = "iram", ram)]
pub fn is_done(&self) -> bool {
self.xfer.is_done()
}
#[cfg_attr(feature = "iram", ram)]
pub fn wait(self) -> (Result<(), DmaError>, Hub75<'d, DM>) {
let (i2s, tx_buf) = self.xfer.wait();
let (tx_descriptors, _) = tx_buf.split();
(
Ok(()),
Hub75 {
i2s,
tx_descriptors,
},
)
}
}
impl Hub75Transfer<'_, esp_hal::Async> {
#[cfg_attr(feature = "iram", ram)]
pub async fn wait_for_done(&mut self) -> Result<(), DmaError> {
self.xfer.wait_for_done().await
}
}
impl<'d> crate::Hub75Pins<'d, TxSixteenBits<'d>> for Hub75Pins16<'d> {
fn convert_pins(self) -> (TxSixteenBits<'d>, AnyPin<'d>) {
let (_, blank) = unsafe { self.blank.split() };
let pins = TxSixteenBits::new(
self.addr0,
self.addr1,
self.addr2,
self.addr3,
self.addr4,
self.latch,
NoPin,
NoPin,
blank.with_output_inverter(true),
self.red1,
self.grn1,
self.blu1,
self.red2,
self.grn2,
self.blu2,
NoPin,
);
(pins, self.clock)
}
}
impl<'d> crate::Hub75Pins<'d, TxEightBits<'d>> for Hub75Pins8<'d> {
fn convert_pins(self) -> (TxEightBits<'d>, AnyPin<'d>) {
let (_, blank) = unsafe { self.blank.split() };
let pins = TxEightBits::new(
self.red1,
self.grn1,
self.blu1,
self.red2,
self.grn2,
self.blu2,
self.latch,
#[cfg(feature = "invert-blank")]
blank.with_output_inverter(true),
#[cfg(not(feature = "invert-blank"))]
blank,
);
(pins, self.clock)
}
}