use atsamd_hal_macros::hal_cfg;
use core::marker::PhantomData;
#[hal_cfg("sercom0-d21")]
use crate::gpio::AnyPin;
use crate::sercom::*;
use crate::typelevel::{NoneT, Sealed};
use super::{Capability, Duplex, Rx, Tx};
pub trait DipoDopo {
const DIPO_DOPO: (u8, u8);
}
impl<S, DI, DO, CK, SS> DipoDopo for Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
(DI::PadNum, DO::PadNum, CK::PadNum, SS::PadNum): DipoDopo,
{
const DIPO_DOPO: (u8, u8) = <(DI::PadNum, DO::PadNum, CK::PadNum, SS::PadNum)>::DIPO_DOPO;
}
#[rustfmt::skip]
macro_rules! impl_dipodopo {
($DI:ident, $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@ck_ss, $DI, $DO, $CK, $SS); };
(@ck_ss, $DI:ident, $DO:ident, Pad1, NoneT) => { impl_dipodopo!(@dipo, $DI, $DO, Pad1, NoneT); };
(@ck_ss, $DI:ident, $DO:ident, Pad1, Pad2) => { impl_dipodopo!(@dipo, $DI, $DO, Pad1, Pad2); };
(@ck_ss, $DI:ident, $DO:ident, Pad3, NoneT) => { impl_dipodopo!(@dipo, $DI, $DO, Pad3, NoneT); };
(@ck_ss, $DI:ident, $DO:ident, Pad3, Pad1) => { impl_dipodopo!(@dipo, $DI, $DO, Pad3, Pad1); };
(@ck_ss, $DI:ident, $DO:ident, $CK:ident, $SS:ident) => { };
(@dipo, NoneT, $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@dopo, NoneT, $DO, $CK, $SS, 0); };
(@dipo, Pad0, $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@dopo, Pad0, $DO, $CK, $SS, 0); };
(@dipo, Pad1, $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@dopo, Pad1, $DO, $CK, $SS, 1); };
(@dipo, Pad2, $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@dopo, Pad2, $DO, $CK, $SS, 2); };
(@dipo, Pad3, $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@dopo, Pad3, $DO, $CK, $SS, 3); };
(@dopo, $DI:ident, NoneT, Pad1, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, NoneT, Pad1, $SS, $DIPO, 0); };
(@dopo, $DI:ident, NoneT, Pad3, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, NoneT, Pad3, $SS, $DIPO, 1); };
(@dopo, $DI:ident, Pad0, Pad1, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, Pad0, Pad1, $SS, $DIPO, 0); };
(@dopo, $DI:ident, Pad2, Pad3, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, Pad2, Pad3, $SS, $DIPO, 1); };
(@dopo, $DI:ident, Pad3, Pad1, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, Pad3, Pad1, $SS, $DIPO, 2); };
(@dopo, $DI:ident, Pad0, Pad3, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, Pad0, Pad3, $SS, $DIPO, 3); };
(@dopo, $DI:ident, $DO:ident, $CK:ident, $SS:ident, $DIPO:literal) => { };
(@filter, NoneT, NoneT, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
(@filter, Pad0, Pad0, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
(@filter, Pad1, $DO:ident, Pad1, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
(@filter, Pad1, $DO:ident, $CK:ident, Pad1, $DIPO:literal, $DOPO:literal) => { };
(@filter, Pad2, Pad2, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
(@filter, Pad2, $DO:ident, $CK:ident, Pad2, $DIPO:literal, $DOPO:literal) => { };
(@filter, Pad3, Pad3, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
(@filter, Pad3, $DO:ident, Pad3, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
(@filter, $DI:ident, Pad2, $CK:ident, Pad2, $DIPO:literal, $DOPO:literal) => { };
(@filter, $DI:ident, $DO:ident, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@revise, $DI, $DO, $CK, $SS, $DIPO, $DOPO); };
(@revise, NoneT, Pad0, Pad1, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@implement, NoneT, Pad0, Pad1, $SS, 3, $DOPO); };
(@revise, NoneT, Pad0, Pad3, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@implement, NoneT, Pad0, Pad3, $SS, 2, $DOPO); };
(@revise, Pad0, NoneT, Pad1, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@implement, Pad0, NoneT, Pad1, $SS, $DIPO, 2); };
(@revise, Pad2, NoneT, Pad3, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@implement, Pad2, NoneT, Pad3, $SS, $DIPO, 3); };
(@revise, $DI:ident, $DO:ident, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@implement, $DI, $DO, $CK, $SS, $DIPO, $DOPO); };
(@implement, $DI:ident, $DO:ident, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => {
impl DipoDopo for ($DI, $DO, $CK, $SS) {
const DIPO_DOPO: (u8, u8) = ($DIPO, $DOPO);
}
};
}
macro_rules! padnum_permutations {
(
( $DI:ident $DO:ident $CK:ident $SS:ident ) [ $( $Pads:ident )* ]
) => {
impl_dipodopo!($DI, $DO, $CK, $SS);
};
(
( $($Perm:ident)* ) [ $($Pads:ident)+ ]
) => {
padnum_permutations!( ( $($Perm)* ) [ $($Pads)+ ] [ $($Pads)+ ] );
};
(
( $($Perm:ident)* ) [ $Head:ident $($Tail:ident)* ] [ $($Pads:ident)+ ]
) => {
padnum_permutations!( ( $($Perm)* $Head ) [ $($Pads)+ ] );
padnum_permutations!( ( $($Perm)* ) [ $($Tail)* ] [ $($Pads)+ ] );
};
( ( $($Perm:ident)* ) [ ] [ $($Pads:ident)+ ] ) => { };
}
padnum_permutations!( () [NoneT Pad0 Pad1 Pad2 Pad3] );
pub struct Pads<S, DI = NoneT, DO = NoneT, CK = NoneT, SS = NoneT>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
{
sercom: PhantomData<S>,
data_in: DI,
data_out: DO,
sclk: CK,
ss: SS,
}
impl<S: Sercom> Default for Pads<S> {
fn default() -> Self {
Self {
sercom: PhantomData,
data_in: NoneT,
data_out: NoneT,
sclk: NoneT,
ss: NoneT,
}
}
}
impl<S, DI, DO, CK, SS> Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
{
#[inline]
pub fn free(self) -> (DI, DO, CK, SS) {
(self.data_in, self.data_out, self.sclk, self.ss)
}
}
#[hal_cfg("sercom0-d11")]
impl<S, DI, DO, CK, SS> Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
{
#[inline]
pub fn data_in<P: IsPad>(self, pin: P) -> Pads<S, P, DO, CK, SS> {
Pads {
sercom: self.sercom,
data_in: pin,
data_out: self.data_out,
sclk: self.sclk,
ss: self.ss,
}
}
#[inline]
pub fn data_out<P: IsPad>(self, pin: P) -> Pads<S, DI, P, CK, SS> {
Pads {
sercom: self.sercom,
data_in: self.data_in,
data_out: pin,
sclk: self.sclk,
ss: self.ss,
}
}
#[inline]
pub fn sclk<P: IsPad>(self, pin: P) -> Pads<S, DI, DO, P, SS> {
Pads {
sercom: self.sercom,
data_in: self.data_in,
data_out: self.data_out,
sclk: pin,
ss: self.ss,
}
}
#[inline]
pub fn ss<P: IsPad>(self, pin: P) -> Pads<S, DI, DO, CK, P> {
Pads {
sercom: self.sercom,
data_in: self.data_in,
data_out: self.data_out,
sclk: self.sclk,
ss: pin,
}
}
}
#[hal_cfg("sercom0-d21")]
impl<S, DI, DO, CK, SS> Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
{
#[inline]
pub fn data_in<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, Pad<S, I>, DO, CK, SS>
where
I: GetPad<S>,
Pad<S, I>: IsPad,
{
Pads {
sercom: self.sercom,
data_in: pin.into().into_mode(),
data_out: self.data_out,
sclk: self.sclk,
ss: self.ss,
}
}
#[inline]
pub fn data_out<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, DI, Pad<S, I>, CK, SS>
where
I: GetPad<S>,
Pad<S, I>: IsPad,
{
Pads {
sercom: self.sercom,
data_in: self.data_in,
data_out: pin.into().into_mode(),
sclk: self.sclk,
ss: self.ss,
}
}
#[inline]
pub fn sclk<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, DI, DO, Pad<S, I>, SS>
where
I: GetPad<S>,
Pad<S, I>: IsPad,
{
Pads {
sercom: self.sercom,
data_in: self.data_in,
data_out: self.data_out,
sclk: pin.into().into_mode(),
ss: self.ss,
}
}
#[inline]
pub fn ss<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, DI, DO, CK, Pad<S, I>>
where
I: GetPad<S>,
Pad<S, I>: IsPad,
{
Pads {
sercom: self.sercom,
data_in: self.data_in,
data_out: self.data_out,
sclk: self.sclk,
ss: pin.into().into_mode(),
}
}
}
#[hal_cfg("sercom0-d21")]
pub type PadsFromIds<S, DI = NoneT, DO = NoneT, CK = NoneT, SS = NoneT> = Pads<
S,
<DI as GetOptionalPad<S>>::Pad,
<DO as GetOptionalPad<S>>::Pad,
<CK as GetOptionalPad<S>>::Pad,
<SS as GetOptionalPad<S>>::Pad,
>;
pub trait PadSet: Sealed {
type Sercom: Sercom;
type DataIn: OptionalPad;
type DataOut: OptionalPad;
type Sclk: OptionalPad;
type SS: OptionalPad;
}
impl<S, DI, DO, CK, SS> Sealed for Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
{
}
impl<S, DI, DO, CK, SS> PadSet for Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
{
type Sercom = S;
type DataIn = DI;
type DataOut = DO;
type Sclk = CK;
type SS = SS;
}
pub trait ValidPads: PadSet + DipoDopo {
type Capability: Capability;
}
impl<S, DI, CK, SS> ValidPads for Pads<S, DI, NoneT, CK, SS>
where
S: Sercom,
DI: SomePad,
CK: SomePad,
SS: OptionalPad,
Pads<S, DI, NoneT, CK, SS>: DipoDopo,
{
type Capability = Rx;
}
impl<S, DO, CK, SS> ValidPads for Pads<S, NoneT, DO, CK, SS>
where
S: Sercom,
DO: SomePad,
CK: SomePad,
SS: OptionalPad,
Pads<S, NoneT, DO, CK, SS>: DipoDopo,
{
type Capability = Tx;
}
impl<S, DI, DO, CK, SS> ValidPads for Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: SomePad,
DO: SomePad,
CK: SomePad,
SS: OptionalPad,
Pads<S, DI, DO, CK, SS>: DipoDopo,
{
type Capability = Duplex;
}