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::parl_io::BitPackOrder;
use esp_hal::parl_io::ClkOutPin;
use esp_hal::parl_io::ConfigurePins;
use esp_hal::parl_io::ParlIo;
use esp_hal::parl_io::ParlIoTx;
use esp_hal::parl_io::ParlIoTxTransfer;
use esp_hal::parl_io::SampleEdge;
use esp_hal::parl_io::TxConfig;
use esp_hal::parl_io::TxEightBits;
use esp_hal::parl_io::TxPins;
use esp_hal::parl_io::TxSixteenBits;
use esp_hal::peripherals::PARL_IO;
#[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> {
parl_io: ParlIoTx<'d, DM>,
tx_descriptors: &'static mut [DmaDescriptor],
}
impl<'d> Hub75<'d, esp_hal::Async> {
pub fn new_async<T: TxPins + ConfigurePins + 'd>(
parl_io: PARL_IO<'d>,
hub75_pins: impl Hub75Pins<'d, T>,
channel: impl DmaChannelFor<PARL_IO<'d>>,
tx_descriptors: &'static mut [DmaDescriptor],
frequency: Rate,
) -> Result<Self, Hub75Error> {
let (parl_io, pins, clk_pin, config) =
Self::new_internal(parl_io, hub75_pins, channel, frequency)?;
let parl_io = parl_io.into_async().tx.with_config(pins, clk_pin, config)?;
Ok(Self {
parl_io,
tx_descriptors,
})
}
}
impl<'d> Hub75<'d, esp_hal::Blocking> {
pub fn new<T: TxPins + ConfigurePins + 'd>(
parl_io: PARL_IO<'d>,
hub75_pins: impl Hub75Pins<'d, T>,
channel: impl DmaChannelFor<PARL_IO<'d>>,
tx_descriptors: &'static mut [DmaDescriptor],
frequency: Rate,
) -> Result<Self, Hub75Error> {
let (parl_io, pins, clk_pin, config) =
Self::new_internal(parl_io, hub75_pins, channel, frequency)?;
let parl_io = parl_io.tx.with_config(pins, clk_pin, config)?;
Ok(Self {
parl_io,
tx_descriptors,
})
}
}
impl<'d, DM: esp_hal::DriverMode> Hub75<'d, DM> {
fn new_internal<T: TxPins + ConfigurePins + 'd>(
parl_io: PARL_IO<'d>,
hub75_pins: impl Hub75Pins<'d, T>,
channel: impl DmaChannelFor<PARL_IO<'d>>,
frequency: Rate,
) -> Result<(ParlIo<'d, esp_hal::Blocking>, T, ClkOutPin<'d>, TxConfig), esp_hal::parl_io::Error>
{
let (pins, clock_pin) = hub75_pins.convert_pins();
let parl_io = ParlIo::new(parl_io, channel)?;
#[cfg(feature = "invert-clock")]
let sample_edge = SampleEdge::Normal;
#[cfg(not(feature = "invert-clock"))]
let sample_edge = SampleEdge::Invert;
let config = TxConfig::default()
.with_frequency(frequency)
.with_idle_value(0)
.with_sample_edge(sample_edge)
.with_bit_order(BitPackOrder::Msb);
let clock_pin = ClkOutPin::new(clock_pin);
Ok((parl_io, pins, clock_pin, config))
}
#[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 parl_io = self.parl_io;
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("failed to create DmaTxBuf!");
let xfer = parl_io
.write(tx_buf.len(), tx_buf)
.map_err(|(e, parl_io, buf)| {
let (tx_descriptors, _) = buf.split();
(
e.into(),
Self {
parl_io,
tx_descriptors,
},
)
})?;
Ok(Hub75Transfer { xfer })
}
}
pub struct Hub75Transfer<'d, DM: esp_hal::DriverMode> {
xfer: ParlIoTxTransfer<'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 (result, parl_io, tx_buf) = self.xfer.wait();
let (tx_descriptors, _) = tx_buf.split();
match result {
Ok(()) => (
Ok(()),
Hub75 {
parl_io,
tx_descriptors,
},
),
Err(e) => (
Err(e),
Hub75 {
parl_io,
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;
Ok(())
}
}
impl<'d> 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> 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)
}
}