diff --git a/embedded-hal/src/lib.rs b/embedded-hal/src/lib.rs index 8b65ded47..45265e975 100644 --- a/embedded-hal/src/lib.rs +++ b/embedded-hal/src/lib.rs @@ -80,13 +80,18 @@ pub mod delay; pub mod digital; pub mod i2c; +pub mod sai; pub mod serial; pub mod spi; mod private { use crate::i2c::{SevenBitAddress, TenBitAddress}; + use crate::sai::{I2sLeftMode, I2sMode, TdmMode}; pub trait Sealed {} impl Sealed for SevenBitAddress {} impl Sealed for TenBitAddress {} + impl Sealed for I2sMode {} + impl Sealed for I2sLeftMode {} + impl Sealed for TdmMode {} } diff --git a/embedded-hal/src/sai.rs b/embedded-hal/src/sai.rs new file mode 100644 index 000000000..e557f2353 --- /dev/null +++ b/embedded-hal/src/sai.rs @@ -0,0 +1,173 @@ +//! Blocking Synchronous Audio Interface API + +use crate::private; + +/// SAI mode +/// +/// Note: This trait is sealed and should not be implemented outside of this crate. +pub trait SaiCommMode: private::Sealed + 'static {} + +/// Standard I2S mode +pub struct I2sMode; + +/// I2S mode with left/MSB alignement +pub struct I2sLeftMode; + +/// TDM mode +pub struct TdmMode; + +impl SaiCommMode for I2sMode {} +impl SaiCommMode for I2sLeftMode {} +impl SaiCommMode for TdmMode {} + +/// I2S trait +pub trait I2s: I2sRx + I2sTx {} + +/// I2S receiver-only trait +pub trait I2sRx: SaiRx + SaiRxInterlaced {} + +/// I2S transmitter-only trait +pub trait I2sTx: SaiTx + SaiTxInterlaced {} + +/// I2S left/MSB aligned trait +pub trait I2sLeft: I2sLeftRx + I2sLeftTx {} + +/// I2S left/MSB aligned receiver-only trait +pub trait I2sLeftRx: SaiRx + SaiRxInterlaced {} + +/// I2S left/MSB aligned transmitter-only trait +pub trait I2sLeftTx: SaiTx + SaiTxInterlaced {} + +/// TDM trait +pub trait Tdm: TdmRx + TdmTx {} + +/// TDM receiver trait +pub trait TdmRx: + SaiRx + SaiRxInterlaced +{ +} + +/// TDM transmitter trait +pub trait TdmTx: + SaiTx + SaiTxInterlaced +{ +} + +/// SAI RX trait +pub trait SaiRx { + /// Error type + type Error: core::fmt::Debug; + /// Sample type + type Sample: Sized; + + /// Reads enough bytes to fill all `CHANNELS` with `samples`. + fn read<'w>(&mut self, samples: [&'w mut [W]; CHANNELS]) -> Result<(), Self::Error>; +} + +/// SAI RX interlaced trait +pub trait SaiRxInterlaced { + /// Error type + type Error: core::fmt::Debug; + /// Sample type + type Sample: Sized; + + /// Reads enough bytes to fill the interlaced `samples` buffer. + fn read_interlaced<'w>(&mut self, samples: &'w mut [W]) -> Result<(), Self::Error>; +} + +/// SAI TX trait +pub trait SaiTx { + /// Error type + type Error: core::fmt::Debug; + /// Sample type + type Sample: Sized; + + /// Sends `samples` to the `CHANNELS`. + fn write<'w>(&mut self, samples: [&'w [W]; CHANNELS]) -> Result<(), Self::Error>; + + /// Sends `samples` to the `CHANNELS`. + fn write_iter(&mut self, samples: [WI; CHANNELS]) -> Result<(), Self::Error> + where + WI: core::iter::IntoIterator; +} + +/// SAI TX interlaced trait +pub trait SaiTxInterlaced { + /// Error type + type Error: core::fmt::Debug; + /// Sample type + type Sample: Sized; + + /// Sends `samples` from an interlaced buffer. + fn write_interlaced<'w>(&mut self, samples: &'w [W]) -> Result<(), Self::Error>; + + /// Sends `samples` to the `CHANNELS`. + fn write_interlaced_iter(&mut self, samples: WI) -> Result<(), Self::Error> + where + WI: core::iter::IntoIterator; +} + +/// SAI error +pub trait Error: core::fmt::Debug { + /// Convert error to a generic SAI error kind + /// + /// By using this method, SAI errors freely defined by HAL implementations + /// can be converted to a set of generic SAI errors upon which generic + /// code can act. + fn kind(&self) -> ErrorKind; +} + +impl Error for core::convert::Infallible { + fn kind(&self) -> ErrorKind { + match *self {} + } +} + +/// SAI error kind +/// +/// This represents a common set of SPI operation errors. HAL implementations are +/// free to define more specific or additional error types. However, by providing +/// a mapping to these common SPI errors, generic code can still react to them. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[non_exhaustive] +pub enum ErrorKind { + // /// The peripheral receive buffer was overrun + // Overrun, + // /// Multiple devices on the SPI bus are trying to drive the slave select pin, e.g. in a multi-master setup + // ModeFault, + // /// Received data does not conform to the peripheral configuration + // FrameFormat, + // /// An error occurred while asserting or deasserting the Chip Select pin. + // ChipSelectFault, + /// A different error occurred. The original error may contain more information. + Other, +} + +impl Error for ErrorKind { + fn kind(&self) -> ErrorKind { + *self + } +} + +impl core::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Other => write!( + f, + "A different error occurred. The original error may contain more information" + ), + } + } +} + +/// SAI error type trait +/// +/// This just defines the error type, to be used by the other SAI traits. +pub trait ErrorType { + /// Error type + type Error: Error; +} + +impl ErrorType for &mut T { + type Error = T::Error; +}