use crate::sealed::Sealed;
use core::convert::Infallible;
use core::marker::PhantomData;
use nb::Error::WouldBlock;
use crate::driver::ClockPolarity;
use crate::driver::I2sDriver as Driver;
use crate::driver::I2sDriverConfig as DriverConfig;
use crate::{I2sPeripheral, WsPin};
pub use crate::marker::{self, *};
#[doc(hidden)]
pub trait FrameFormat: Sealed {
type RawFrame: Default + Copy + Sync + Send + AsRef<[u16]> + AsMut<[u16]>;
}
type RawFrame<STD, FMT> = <(STD, FMT) as FrameFormat>::RawFrame;
macro_rules! impl_frame_format{
($(([$($std:ident),*],$fmt:ident,$raw_frame:ty)),*) => {
$(
$(
impl FrameFormat for ($std,$fmt) {
type RawFrame = $raw_frame;
}
)*
)*
};
}
impl<T: Sealed, U: Sealed> Sealed for (T, U) {}
impl_frame_format!(
([Philips, Msb, Lsb], Data16Channel16, [u16; 2]),
([Philips, Msb, Lsb], Data16Channel32, [u16; 2]),
([Philips, Msb, Lsb], Data32Channel32, [u16; 4]),
([PcmShortSync, PcmLongSync], Data16Channel16, [u16; 1]),
([PcmShortSync, PcmLongSync], Data16Channel32, [u16; 1]),
([PcmShortSync, PcmLongSync], Data32Channel32, [u16; 2])
);
pub trait ToRawFrame<STD, FMT>
where
(STD, FMT): FrameFormat,
{
fn to_raw(&self) -> RawFrame<STD, FMT>;
}
macro_rules! impl_to_raw_frame{
($(($type:ty,[$($std:ident),*],$fmt:ident),$func:item),*) => {
$(
$(
impl ToRawFrame<$std, $fmt> for $type {
$func
}
)*
)*
};
}
impl_to_raw_frame!(
((i16, i16), [Philips, Msb, Lsb], Data16Channel16),
fn to_raw(&self) -> [u16; 2] {
[self.0 as u16, self.1 as u16]
},
((i16, i16), [Philips, Msb, Lsb], Data16Channel32),
fn to_raw(&self) -> [u16; 2] {
[self.0 as u16, self.1 as u16]
},
((i32, i32), [Philips, Msb, Lsb], Data32Channel32),
fn to_raw(&self) -> [u16; 4] {
[
(self.0 as u32 >> 16) as u16,
(self.0 as u32 & 0xFFFF) as u16,
(self.1 as u32 >> 16) as u16,
(self.1 as u32 & 0xFFFF) as u16,
]
},
(i16, [PcmShortSync, PcmLongSync], Data16Channel16),
fn to_raw(&self) -> [u16; 1] {
[*self as u16]
},
(i16, [PcmShortSync, PcmLongSync], Data16Channel32),
fn to_raw(&self) -> [u16; 1] {
[*self as u16]
},
(i32, [PcmShortSync, PcmLongSync], Data32Channel32),
fn to_raw(&self) -> [u16; 2] {
[(*self as u32 >> 16) as u16, (*self as u32 & 0xFFFF) as u16]
}
);
pub trait FromRawFrame<STD, FMT>
where
(STD, FMT): FrameFormat,
{
fn from_raw(raw: RawFrame<STD, FMT>) -> Self;
}
macro_rules! impl_from_raw_frame{
($(($type:ty,[$($std:ident),*],$fmt:ident),$func:item),*) => {
$(
$(
impl FromRawFrame<$std, $fmt> for $type {
$func
}
)*
)*
};
}
impl_from_raw_frame!(
((i16, i16), [Philips, Msb, Lsb], Data16Channel16),
fn from_raw(raw: [u16; 2]) -> Self {
(raw[0] as i16, raw[1] as i16)
},
((i16, i16), [Philips, Msb, Lsb], Data16Channel32),
fn from_raw(raw: [u16; 2]) -> Self {
(raw[0] as i16, raw[1] as i16)
},
((i32, i32), [Philips, Msb, Lsb], Data32Channel32),
fn from_raw(raw: [u16; 4]) -> Self {
let l = (raw[0] as i32) << 16 | raw[1] as i32;
let r = (raw[2] as i32) << 16 | raw[3] as i32;
(l, r)
},
(i16, [PcmShortSync, PcmLongSync], Data16Channel16),
fn from_raw(raw: [u16; 1]) -> Self {
raw[0] as i16
},
(i16, [PcmShortSync, PcmLongSync], Data16Channel32),
fn from_raw(raw: [u16; 1]) -> Self {
raw[0] as i16
},
(i32, [PcmShortSync, PcmLongSync], Data32Channel32),
fn from_raw(raw: [u16; 2]) -> Self {
(raw[0] as i32) << 16 | raw[1] as i32
}
);
#[non_exhaustive]
pub enum I2sTransferError {
Overrun,
}
#[derive(Debug, Clone, Copy)]
pub struct I2sTransferConfig<MS, DIR, STD, FMT> {
driver_config: DriverConfig<MS, DIR, STD>,
_fmt: PhantomData<FMT>,
}
impl I2sTransferConfig<Slave, Transmit, Philips, Data16Channel16> {
pub fn new_slave() -> Self {
Self {
driver_config: DriverConfig::new_slave(),
_fmt: PhantomData,
}
}
}
impl I2sTransferConfig<Master, Transmit, Philips, Data16Channel16> {
pub fn new_master() -> Self {
Self {
driver_config: DriverConfig::new_master(),
_fmt: PhantomData,
}
}
}
impl<MS, DIR, STD, FMT> I2sTransferConfig<MS, DIR, STD, FMT>
where
STD: I2sStandard,
FMT: DataFormat,
(STD, FMT): FrameFormat,
{
pub fn i2s_transfer<I: I2sPeripheral>(
self,
i2s_peripheral: I,
) -> I2sTransfer<I, MS, DIR, STD, FMT> {
let driver = self.driver_config.i2s_driver(i2s_peripheral);
I2sTransfer::<I, MS, DIR, STD, FMT> {
driver,
frame: Default::default(),
transfer_count: 0,
sync: false,
_fmt: PhantomData,
}
}
}
impl Default for I2sTransferConfig<Slave, Transmit, Philips, Data16Channel16> {
fn default() -> Self {
Self::new_slave()
}
}
impl<MS, DIR, STD, FMT> I2sTransferConfig<MS, DIR, STD, FMT> {
pub fn transmit(self) -> I2sTransferConfig<MS, Transmit, STD, FMT> {
I2sTransferConfig::<MS, Transmit, STD, FMT> {
driver_config: self.driver_config.transmit(),
_fmt: PhantomData,
}
}
pub fn receive(self) -> I2sTransferConfig<MS, Receive, STD, FMT> {
I2sTransferConfig::<MS, Receive, STD, FMT> {
driver_config: self.driver_config.receive(),
_fmt: PhantomData,
}
}
#[allow(non_camel_case_types)]
pub fn standard<NEW_STD>(self, _standard: NEW_STD) -> I2sTransferConfig<MS, DIR, NEW_STD, FMT>
where
NEW_STD: marker::I2sStandard,
{
I2sTransferConfig::<MS, DIR, NEW_STD, FMT> {
driver_config: self.driver_config.standard(_standard),
_fmt: PhantomData,
}
}
pub fn clock_polarity(self, polarity: ClockPolarity) -> Self {
I2sTransferConfig::<MS, DIR, STD, FMT> {
driver_config: self.driver_config.clock_polarity(polarity),
_fmt: PhantomData,
}
}
#[allow(non_camel_case_types)]
pub fn data_format<NEW_FMT>(self, _format: NEW_FMT) -> I2sTransferConfig<MS, DIR, STD, NEW_FMT>
where
NEW_FMT: marker::DataFormat,
{
I2sTransferConfig::<MS, DIR, STD, NEW_FMT> {
driver_config: self.driver_config.data_format(NEW_FMT::VALUE),
_fmt: PhantomData,
}
}
pub fn to_slave(self) -> I2sTransferConfig<Slave, DIR, STD, FMT> {
I2sTransferConfig::<Slave, DIR, STD, FMT> {
driver_config: self.driver_config.to_slave(),
_fmt: PhantomData,
}
}
pub fn to_master(self) -> I2sTransferConfig<Master, DIR, STD, FMT> {
I2sTransferConfig::<Master, DIR, STD, FMT> {
driver_config: self.driver_config.to_master(),
_fmt: PhantomData,
}
}
}
impl<DIR, STD, FMT> I2sTransferConfig<Master, DIR, STD, FMT> {
pub fn master_clock(self, enable: bool) -> Self {
I2sTransferConfig::<Master, DIR, STD, FMT> {
driver_config: self.driver_config.master_clock(enable),
_fmt: PhantomData,
}
}
pub fn prescaler(self, odd: bool, div: u8) -> Self {
I2sTransferConfig::<Master, DIR, STD, FMT> {
driver_config: self.driver_config.prescaler(odd, div),
_fmt: PhantomData,
}
}
pub fn request_frequency(self, freq: u32) -> Self {
I2sTransferConfig::<Master, DIR, STD, FMT> {
driver_config: self.driver_config.request_frequency(freq),
_fmt: PhantomData,
}
}
pub fn require_frequency(self, freq: u32) -> Self {
I2sTransferConfig::<Master, DIR, STD, FMT> {
driver_config: self.driver_config.require_frequency(freq),
_fmt: PhantomData,
}
}
}
pub struct I2sTransfer<I, MS, DIR, STD, FMT>
where
I: I2sPeripheral,
(STD, FMT): FrameFormat,
{
driver: Driver<I, MS, DIR, STD>,
frame: RawFrame<STD, FMT>,
transfer_count: u8, sync: bool,
_fmt: PhantomData<FMT>,
}
impl<I, MS, DIR, STD, FMT> I2sTransfer<I, MS, DIR, STD, FMT>
where
I: I2sPeripheral,
STD: I2sStandard,
(STD, FMT): FrameFormat,
{
#[inline]
fn _ws_is_start(&self) -> bool {
match STD::WS_START_LEVEL {
false => self.driver.ws_pin().is_low(),
true => self.driver.ws_pin().is_high(),
}
}
}
impl<I, MS, DIR, STD, FMT> I2sTransfer<I, MS, DIR, STD, FMT>
where
I: I2sPeripheral,
STD: I2sStandard,
FMT: DataFormat,
(STD, FMT): FrameFormat,
{
pub fn new(i2s_peripheral: I, config: I2sTransferConfig<MS, DIR, STD, FMT>) -> Self {
config.i2s_transfer(i2s_peripheral)
}
pub fn release(self) -> I {
self.driver.release()
}
}
impl<I, MS, DIR, STD, FMT> I2sTransfer<I, MS, DIR, STD, FMT>
where
I: I2sPeripheral,
(STD, FMT): FrameFormat,
{
pub fn begin(&mut self) {
self.driver.enable()
}
}
impl<I, DIR, STD, FMT> I2sTransfer<I, Slave, DIR, STD, FMT>
where
I: I2sPeripheral,
(STD, FMT): FrameFormat,
{
pub fn end(&mut self) {
self.driver.disable();
self.frame = Default::default();
self.transfer_count = 0;
self.sync = false;
}
}
impl<I, DIR, STD, FMT> I2sTransfer<I, Master, DIR, STD, FMT>
where
I: I2sPeripheral,
(STD, FMT): FrameFormat,
{
pub fn end(&mut self) {
self.driver.disable();
self.driver.reset_clocks();
self.frame = Default::default();
self.transfer_count = 0;
self.sync = false;
}
}
impl<I, DIR, STD, FMT> I2sTransfer<I, Master, DIR, STD, FMT>
where
I: I2sPeripheral,
(STD, FMT): FrameFormat,
{
pub fn sample_rate(&self) -> u32 {
self.driver.sample_rate()
}
}
impl<I, STD, FMT> I2sTransfer<I, Master, Transmit, STD, FMT>
where
I: I2sPeripheral,
(STD, FMT): FrameFormat,
{
pub fn write_iter<ITER, T>(&mut self, samples: ITER)
where
T: ToRawFrame<STD, FMT>,
ITER: IntoIterator<Item = T>,
{
let mut samples = samples.into_iter();
self.driver.enable();
loop {
let status = self.driver.status();
if status.txe() {
if self.transfer_count >= self.frame.as_ref().len() as u8 {
self.transfer_count = 0;
}
if self.transfer_count == 0 {
let smpl = samples.next();
if smpl.is_none() {
break;
}
self.frame = smpl.unwrap().to_raw();
}
self.driver
.write_data_register(self.frame.as_ref()[self.transfer_count as usize]);
self.transfer_count += 1;
}
}
}
pub fn write<T: ToRawFrame<STD, FMT>>(&mut self, frame: T) -> nb::Result<(), Infallible> {
self.driver.enable();
let status = self.driver.status();
if status.txe() {
if self.transfer_count >= self.frame.as_ref().len() as u8 {
self.transfer_count = 0;
}
if self.transfer_count == 0 {
self.frame = frame.to_raw();
self.driver
.write_data_register(self.frame.as_ref()[self.transfer_count as usize]);
self.transfer_count += 1;
return Ok(());
} else {
self.driver
.write_data_register(self.frame.as_ref()[self.transfer_count as usize]);
self.transfer_count += 1;
}
}
Err(WouldBlock)
}
}
impl<I, STD, FMT> I2sTransfer<I, Slave, Transmit, STD, FMT>
where
I: I2sPeripheral,
STD: I2sStandard,
(STD, FMT): FrameFormat,
{
pub fn write_iter<ITER, T>(&mut self, frames: ITER)
where
T: ToRawFrame<STD, FMT>,
ITER: IntoIterator<Item = T>,
{
let mut frames = frames.into_iter();
loop {
if self.sync {
let status = self.driver.status();
if status.txe() {
if self.transfer_count >= self.frame.as_ref().len() as u8 {
self.transfer_count = 0;
}
if self.transfer_count == 0 {
let frm = frames.next();
if frm.is_none() {
break;
}
self.frame = frm.unwrap().to_raw();
}
self.driver
.write_data_register(self.frame.as_ref()[self.transfer_count as usize]);
self.transfer_count += 1;
}
if status.fre() || status.udr() {
self.sync = false;
self.driver.disable();
}
} else if !self._ws_is_start() {
let frm = frames.next();
if frm.is_none() {
break;
}
self.frame = frm.unwrap().to_raw();
self.driver.write_data_register(self.frame.as_ref()[0]);
self.transfer_count = 1;
self.driver.enable();
if !self._ws_is_start() {
self.sync = true;
} else {
self.driver.disable();
}
}
}
}
pub fn write<T: ToRawFrame<STD, FMT>>(&mut self, frame: T) -> nb::Result<(), Infallible> {
if self.sync {
let status = self.driver.status();
if status.txe() {
if self.transfer_count >= self.frame.as_ref().len() as u8 {
self.transfer_count = 0;
}
if self.transfer_count == 0 {
self.frame = frame.to_raw();
self.driver
.write_data_register(self.frame.as_ref()[self.transfer_count as usize]);
self.transfer_count += 1;
return Ok(());
} else {
self.driver
.write_data_register(self.frame.as_ref()[self.transfer_count as usize]);
self.transfer_count += 1;
}
}
if status.fre() || status.udr() {
self.sync = false;
self.driver.disable();
}
} else if !self._ws_is_start() {
self.driver.write_data_register(self.frame.as_ref()[0]);
self.transfer_count = 1;
self.driver.enable();
if !self._ws_is_start() {
self.sync = true;
} else {
self.driver.disable();
}
return Ok(());
}
Err(WouldBlock)
}
}
impl<I, STD, FMT> I2sTransfer<I, Master, Receive, STD, FMT>
where
I: I2sPeripheral,
(STD, FMT): FrameFormat,
{
pub fn read_while<F, T>(&mut self, mut predicate: F) -> Result<(), I2sTransferError>
where
T: FromRawFrame<STD, FMT>,
F: FnMut(T) -> bool,
{
self.driver.enable();
loop {
let status = self.driver.status();
if status.rxne() {
if self.transfer_count >= self.frame.as_ref().len() as u8 {
self.transfer_count = 0;
}
self.frame.as_mut()[self.transfer_count as usize] =
self.driver.read_data_register();
self.transfer_count += 1;
if self.transfer_count >= self.frame.as_ref().len() as u8
&& !predicate(T::from_raw(self.frame))
{
return Ok(());
}
}
if status.ovr() {
self.end();
return Err(I2sTransferError::Overrun);
}
}
}
pub fn read<T: FromRawFrame<STD, FMT>>(&mut self) -> nb::Result<T, I2sTransferError> {
self.driver.enable();
let status = self.driver.status();
if status.rxne() {
if self.transfer_count >= self.frame.as_ref().len() as u8 {
self.transfer_count = 0;
}
self.frame.as_mut()[self.transfer_count as usize] = self.driver.read_data_register();
self.transfer_count += 1;
if self.transfer_count >= self.frame.as_ref().len() as u8 {
return Ok(T::from_raw(self.frame));
}
}
if status.ovr() {
self.end();
return Err(nb::Error::Other(I2sTransferError::Overrun));
}
Err(WouldBlock)
}
}
impl<I, STD, FMT> I2sTransfer<I, Slave, Receive, STD, FMT>
where
I: I2sPeripheral,
STD: I2sStandard,
(STD, FMT): FrameFormat,
{
pub fn read_while<F, T>(&mut self, mut predicate: F)
where
T: FromRawFrame<STD, FMT>,
F: FnMut(T) -> bool,
{
loop {
if self.sync {
let status = self.driver.status();
if status.rxne() {
if self.transfer_count >= self.frame.as_ref().len() as u8 {
self.transfer_count = 0;
}
self.frame.as_mut()[self.transfer_count as usize] =
self.driver.read_data_register();
self.transfer_count += 1;
if self.transfer_count >= self.frame.as_ref().len() as u8
&& !predicate(T::from_raw(self.frame))
{
return;
}
}
if status.fre() || status.ovr() {
self.sync = false;
self.driver.read_data_register();
self.driver.status();
self.driver.disable();
}
} else if !self._ws_is_start() {
self.transfer_count = 0;
self.driver.enable();
if !self._ws_is_start() {
self.sync = true;
} else {
self.driver.disable();
}
}
}
}
pub fn read<T: FromRawFrame<STD, FMT>>(&mut self) -> nb::Result<T, Infallible> {
if !self.sync {
self.driver.disable();
self.transfer_count = 0;
}
if self.sync {
let status = self.driver.status();
if status.rxne() {
if self.transfer_count >= self.frame.as_ref().len() as u8 {
self.transfer_count = 0;
}
self.frame.as_mut()[self.transfer_count as usize] =
self.driver.read_data_register();
self.transfer_count += 1;
if self.transfer_count >= self.frame.as_ref().len() as u8 {
return Ok(T::from_raw(self.frame));
}
}
if status.fre() || status.ovr() {
self.sync = false;
self.driver.disable();
}
} else if !self._ws_is_start() {
self.transfer_count = 0;
self.driver.enable();
self.driver.read_data_register();
self.driver.status();
if !self._ws_is_start() {
self.sync = true;
} else {
self.driver.disable();
}
}
Err(WouldBlock)
}
}