use atsamd_hal_macros::hal_cfg;
use super::{AnyConfig, Capability, CharSize, Config, Duplex, Rx, Tx};
use crate::{
sercom::*,
typelevel::{NoneT, Sealed},
};
use core::marker::PhantomData;
#[hal_cfg("sercom0-d21")]
use crate::gpio::AnyPin;
pub trait RxpoTxpo {
const RXPO: u8;
const TXPO: u8;
}
impl<S, RX, TX, RTS, CTS> RxpoTxpo for Pads<S, RX, TX, RTS, CTS>
where
S: Sercom,
RX: OptionalPad,
TX: OptionalPad,
RTS: OptionalPad,
CTS: OptionalPad,
(RX::PadNum, TX::PadNum, RTS::PadNum, CTS::PadNum): RxpoTxpo,
{
const RXPO: u8 = <(RX::PadNum, TX::PadNum, RTS::PadNum, CTS::PadNum)>::RXPO;
const TXPO: u8 = <(RX::PadNum, TX::PadNum, RTS::PadNum, CTS::PadNum)>::TXPO;
}
macro_rules! impl_rxpotxpo {
($RX:ident, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@check_rts_cts, $RX, $TX, $RTS, $CTS); };
(@check_rts_cts, $RX:ident, $TX:ident, NoneT, NoneT) => { impl_rxpotxpo!(@rxpo, $RX, $TX, NoneT, NoneT); };
(@check_rts_cts, $RX:ident, $TX:ident, Pad2, NoneT) => { impl_rxpotxpo!(@rxpo, $RX, $TX, Pad2, NoneT); };
(@check_rts_cts, $RX:ident, $TX:ident, NoneT, Pad3) => { impl_rxpotxpo!(@rxpo, $RX, $TX, NoneT, Pad3); };
(@check_rts_cts, $RX:ident, $TX:ident, Pad2, Pad3) => { impl_rxpotxpo!(@rxpo, $RX, $TX, Pad2, Pad3); };
(@check_rts_cts, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident) => { };
(@rxpo, NoneT, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, NoneT, $TX, $RTS, $CTS, 0); };
(@rxpo, Pad0, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad0, $TX, $RTS, $CTS, 0); };
(@rxpo, Pad1, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad1, $TX, $RTS, $CTS, 1); };
(@rxpo, Pad2, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad2, $TX, $RTS, $CTS, 2); };
(@rxpo, Pad3, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad3, $TX, $RTS, $CTS, 3); };
(@txpo, $RX:ident, NoneT, NoneT, $CTS:ident, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, NoneT, NoneT, $CTS, $RXPO, 0); };
(@txpo, $RX:ident, NoneT, Pad2, $CTS:ident, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, NoneT, Pad2, $CTS, $RXPO, 2); };
(@txpo, $RX:ident, Pad0, NoneT, $CTS:ident, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, Pad0, NoneT, $CTS, $RXPO, 0); };
(@txpo, $RX:ident, Pad2, NoneT, $CTS:ident, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, Pad2, NoneT, $CTS, $RXPO, 1); };
(@txpo, $RX:ident, Pad0, Pad2, $CTS:ident, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, Pad0, Pad2, $CTS, $RXPO, 2); };
(@txpo, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident, $RXPO:literal) => { };
(@filter, NoneT, NoneT, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; (@filter, Pad0, Pad0, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; (@filter, Pad2, Pad2, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; (@filter, Pad2, $TX:ident, Pad2, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; (@filter, Pad3, $TX:ident, $RTS:ident, Pad3, $RXPO:literal, $TXPO:literal) => { }; (@filter, Pad1, $TX:ident, $RTS:ident, $CTS:ident, 0, $TXPO:literal) => { }; (@filter, Pad3, $TX:ident, $RTS:ident, $CTS:ident, 1, $TXPO:literal) => { };
(@filter, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => {
impl_rxpotxpo!(@implement, $RX, $TX, $RTS, $CTS, $RXPO, $TXPO);
};
(@implement, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => {
impl RxpoTxpo for ($RX, $TX, $RTS, $CTS) {
const RXPO: u8 = $RXPO;
const TXPO: u8 = $TXPO;
}
};
}
macro_rules! padnum_permutations {
(
( $RX:ident $TX:ident $RTS:ident $CTS:ident ) [ $( $Pads:ident )* ]
) => {
impl_rxpotxpo!($RX, $TX, $RTS, $CTS);
};
(
( $($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, RX = NoneT, TX = NoneT, RTS = NoneT, CTS = NoneT>
where
S: Sercom,
RX: OptionalPad,
TX: OptionalPad,
RTS: OptionalPad,
CTS: OptionalPad,
{
sercom: PhantomData<S>,
receive: RX,
transmit: TX,
ready_to_send: RTS,
clear_to_send: CTS,
}
impl<S: Sercom> Default for Pads<S> {
fn default() -> Self {
Self {
sercom: PhantomData,
receive: NoneT,
transmit: NoneT,
ready_to_send: NoneT,
clear_to_send: NoneT,
}
}
}
impl<S, RX, TX, RTS, CTS> Pads<S, RX, TX, RTS, CTS>
where
S: Sercom,
RX: OptionalPad,
TX: OptionalPad,
RTS: OptionalPad,
CTS: OptionalPad,
{
#[inline]
pub fn free(self) -> (RX, TX, RTS, CTS) {
(
self.receive,
self.transmit,
self.ready_to_send,
self.clear_to_send,
)
}
}
#[hal_cfg("sercom0-d11")]
impl<S, RX, TX, RTS, CTS> Pads<S, RX, TX, RTS, CTS>
where
S: Sercom,
RX: OptionalPad,
TX: OptionalPad,
RTS: OptionalPad,
CTS: OptionalPad,
{
#[inline]
pub fn rx<P: IsPad>(self, pin: P) -> Pads<S, P, TX, RTS, CTS> {
Pads {
sercom: self.sercom,
receive: pin,
transmit: self.transmit,
ready_to_send: self.ready_to_send,
clear_to_send: self.clear_to_send,
}
}
#[inline]
pub fn tx<P: IsPad>(self, pin: P) -> Pads<S, RX, P, RTS, CTS> {
Pads {
sercom: self.sercom,
receive: self.receive,
transmit: pin,
ready_to_send: self.ready_to_send,
clear_to_send: self.clear_to_send,
}
}
#[inline]
pub fn rts<P: IsPad>(self, pin: P) -> Pads<S, RX, TX, P, CTS> {
Pads {
sercom: self.sercom,
receive: self.receive,
transmit: self.transmit,
ready_to_send: pin,
clear_to_send: self.clear_to_send,
}
}
#[inline]
pub fn cts<P: IsPad>(self, pin: P) -> Pads<S, RX, TX, RTS, P> {
Pads {
sercom: self.sercom,
receive: self.receive,
transmit: self.transmit,
ready_to_send: self.ready_to_send,
clear_to_send: pin,
}
}
}
#[hal_cfg("sercom0-d21")]
impl<S, RX, TX, RTS, CTS> Pads<S, RX, TX, RTS, CTS>
where
S: Sercom,
RX: OptionalPad,
TX: OptionalPad,
RTS: OptionalPad,
CTS: OptionalPad,
{
#[inline]
pub fn rx<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, Pad<S, I>, TX, RTS, CTS>
where
I: GetPad<S>,
Pad<S, I>: IsPad,
{
Pads {
sercom: self.sercom,
receive: pin.into().into_mode(),
transmit: self.transmit,
ready_to_send: self.ready_to_send,
clear_to_send: self.clear_to_send,
}
}
#[inline]
pub fn tx<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, RX, Pad<S, I>, RTS, CTS>
where
I: GetPad<S>,
Pad<S, I>: IsPad,
{
Pads {
sercom: self.sercom,
receive: self.receive,
transmit: pin.into().into_mode(),
ready_to_send: self.ready_to_send,
clear_to_send: self.clear_to_send,
}
}
#[inline]
pub fn rts<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, RX, TX, Pad<S, I>, CTS>
where
I: GetPad<S>,
Pad<S, I>: IsPad,
{
Pads {
sercom: self.sercom,
receive: self.receive,
transmit: self.transmit,
ready_to_send: pin.into().into_mode(),
clear_to_send: self.clear_to_send,
}
}
#[inline]
pub fn cts<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, RX, TX, RTS, Pad<S, I>>
where
I: GetPad<S>,
Pad<S, I>: IsPad,
{
Pads {
sercom: self.sercom,
receive: self.receive,
transmit: self.transmit,
ready_to_send: self.ready_to_send,
clear_to_send: pin.into().into_mode(),
}
}
}
#[hal_cfg("sercom0-d21")]
pub type PadsFromIds<S, RX = NoneT, TX = NoneT, RTS = NoneT, CTS = NoneT> = Pads<
S,
<RX as GetOptionalPad<S>>::Pad,
<TX as GetOptionalPad<S>>::Pad,
<RTS as GetOptionalPad<S>>::Pad,
<CTS as GetOptionalPad<S>>::Pad,
>;
pub trait PadSet: Sealed {
type Sercom: Sercom;
type Rx: OptionalPad;
type Tx: OptionalPad;
type Rts: OptionalPad;
type Cts: OptionalPad;
}
impl<S, RX, TX, RTS, CTS> Sealed for Pads<S, RX, TX, RTS, CTS>
where
S: Sercom,
RX: OptionalPad,
TX: OptionalPad,
RTS: OptionalPad,
CTS: OptionalPad,
{
}
impl<S, RX, TX, RTS, CTS> PadSet for Pads<S, RX, TX, RTS, CTS>
where
S: Sercom,
RX: OptionalPad,
TX: OptionalPad,
RTS: OptionalPad,
CTS: OptionalPad,
{
type Sercom = S;
type Rx = RX;
type Tx = TX;
type Rts = RTS;
type Cts = CTS;
}
pub trait ValidPads: PadSet + RxpoTxpo {
type Capability: Capability;
}
impl<S, RX, RTS> ValidPads for Pads<S, RX, NoneT, RTS, NoneT>
where
S: Sercom,
RX: SomePad,
RTS: OptionalPad,
Self: PadSet + RxpoTxpo,
{
type Capability = Rx;
}
impl<S, TX, CTS> ValidPads for Pads<S, NoneT, TX, NoneT, CTS>
where
S: Sercom,
TX: SomePad,
CTS: OptionalPad,
Self: PadSet + RxpoTxpo,
{
type Capability = Tx;
}
impl<S, RX, TX, RTS, CTS> ValidPads for Pads<S, RX, TX, RTS, CTS>
where
S: Sercom,
RX: SomePad,
TX: SomePad,
RTS: OptionalPad,
CTS: OptionalPad,
Self: PadSet + RxpoTxpo,
{
type Capability = Duplex;
}
pub trait ValidConfig: AnyConfig {}
impl<P: ValidPads, C: CharSize> ValidConfig for Config<P, C> {}