lilkaoxide 0.1.0

Rust support library for Lilka console
use esp_hal::{
    dma_buffers,
    gpio::interconnect::PeripheralOutput,
    i2s::master::{Config, I2s},
    peripherals::{DMA_CH0, I2S0},
};
#[cfg(feature = "blocking")]
type DriveMode = esp_hal::Blocking;
#[cfg(feature = "async")]
type DriveMode = esp_hal::Async;

pub type I2sTx<'d> = esp_hal::i2s::master::I2sTx<'d, DriveMode>;
pub const DEFAULT_DMA_TX_BUF_SIZE: usize = 4 * 4096;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum I2sInitError {
    PeripheralInitFailed,
}

impl I2sInitError {
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::PeripheralInitFailed => "I2S init failed",
        }
    }
}

pub enum TDMStandart {
    Phillips,
    MSB,
    PCM,
    PCM_Long,
}

macro_rules! tdm_config {
    ($standard:expr, $cfg:ident => $($method:tt)*) => {
        match $standard {
            TDMStandart::Phillips => Config::new_tdm_philips()$($method)*,
            TDMStandart::MSB      => Config::new_tdm_msb()$($method)*,
            TDMStandart::PCM      => Config::new_tdm_pcm_short()$($method)*,
            TDMStandart::PCM_Long => Config::new_tdm_pcm_long()$($method)*,
        }
    };
}

pub struct I2sTxConfig {
    pub sample_rate: esp_hal::time::Rate,
    pub channels: esp_hal::i2s::master::Channels,
    pub data_format: esp_hal::i2s::master::DataFormat,
    pub tdm_standard: TDMStandart,
}

impl Default for I2sTxConfig {
    fn default() -> Self {
        Self {
            sample_rate: esp_hal::time::Rate::from_hz(44100),
            channels: esp_hal::i2s::master::Channels::STEREO,
            data_format: esp_hal::i2s::master::DataFormat::Data16Channel16,
            tdm_standard: TDMStandart::Phillips,
        }
    }
}

pub fn init_i2s_tx<'d>(
    config: I2sTxConfig,
    bclk: impl PeripheralOutput<'d>,
    dout: impl PeripheralOutput<'d>,
    lrck: impl PeripheralOutput<'d>,
    i2s0: I2S0<'d>,
    dma_channel: DMA_CH0<'d>,
) -> Result<I2sTx<'d>, I2sInitError> {
    let i2s = I2s::new(
        i2s0,
        dma_channel,
        tdm_config!(config.tdm_standard, cfg => .with_sample_rate(config.sample_rate).with_channels(config.channels).with_data_format(config.data_format))
    )
    .map_err(|_| I2sInitError::PeripheralInitFailed)?;
    let (_, _, _tx_buf, tx_desc) = dma_buffers!(0, DEFAULT_DMA_TX_BUF_SIZE);

    #[cfg(feature = "async")]
    let i2s = i2s.into_async();
    let i2stx = i2s
        .i2s_tx
        .with_bclk(bclk)
        .with_ws(lrck)
        .with_dout(dout)
        .build(tx_desc);
    Ok(i2stx)
}