Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] I2S/SAI traits - take 3 #426

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions embedded-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
}
173 changes: 173 additions & 0 deletions embedded-hal/src/sai.rs
Original file line number Diff line number Diff line change
@@ -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<W>: I2sRx<W> + I2sTx<W> {}

/// I2S receiver-only trait
pub trait I2sRx<W>: SaiRx<I2sMode, W, 2> + SaiRxInterlaced<I2sMode, W, 2> {}

/// I2S transmitter-only trait
pub trait I2sTx<W>: SaiTx<I2sMode, W, 2> + SaiTxInterlaced<I2sMode, W, 2> {}

/// I2S left/MSB aligned trait
pub trait I2sLeft<W>: I2sLeftRx<W> + I2sLeftTx<W> {}

/// I2S left/MSB aligned receiver-only trait
pub trait I2sLeftRx<W>: SaiRx<I2sLeftMode, W, 2> + SaiRxInterlaced<I2sLeftMode, W, 2> {}

/// I2S left/MSB aligned transmitter-only trait
pub trait I2sLeftTx<W>: SaiTx<I2sLeftMode, W, 2> + SaiTxInterlaced<I2sLeftMode, W, 2> {}

/// TDM trait
pub trait Tdm<W, const CHANNELS: usize>: TdmRx<W, CHANNELS> + TdmTx<W, CHANNELS> {}

/// TDM receiver trait
pub trait TdmRx<W, const CHANNELS: usize>:
SaiRx<TdmMode, W, CHANNELS> + SaiRxInterlaced<TdmMode, W, CHANNELS>
{
}

/// TDM transmitter trait
pub trait TdmTx<W, const CHANNELS: usize>:
SaiTx<TdmMode, W, CHANNELS> + SaiTxInterlaced<TdmMode, W, CHANNELS>
{
}

/// SAI RX trait
pub trait SaiRx<M: SaiCommMode, W: Sized, const CHANNELS: usize> {
/// 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<M: SaiCommMode, W: Sized, const CHANNELS: usize> {
/// 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<M: SaiCommMode, W: Sized, const CHANNELS: usize> {
/// 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<WI>(&mut self, samples: [WI; CHANNELS]) -> Result<(), Self::Error>
where
WI: core::iter::IntoIterator<Item = W>;
}

/// SAI TX interlaced trait
pub trait SaiTxInterlaced<M: SaiCommMode, W: Sized, const CHANNELS: usize> {
/// 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<WI>(&mut self, samples: WI) -> Result<(), Self::Error>
where
WI: core::iter::IntoIterator<Item = W>;
}

/// 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<T: ErrorType> ErrorType for &mut T {
type Error = T::Error;
}