1use super::{AnyConfig, Capability, CharSize, Config, Duplex, Rx, Tx};
4use crate::{
5    gpio::AnyPin,
6    gpio::Pin,
7    sercom::*,
8    typelevel::{NoneT, Sealed},
9};
10use core::marker::PhantomData;
11
12pub trait RxpoTxpo {
31    const RXPO: u8;
33
34    const TXPO: u8;
36}
37
38impl<S, RX, TX, RTS, CTS> RxpoTxpo for Pads<S, RX, TX, RTS, CTS>
41where
42    S: Sercom,
43    RX: OptionalPad,
44    TX: OptionalPad,
45    RTS: OptionalPad,
46    CTS: OptionalPad,
47    (RX, TX, RTS, CTS): ShareIoSet,
48    (RX::PadNum, TX::PadNum, RTS::PadNum, CTS::PadNum): RxpoTxpo,
49{
50    const RXPO: u8 = <(RX::PadNum, TX::PadNum, RTS::PadNum, CTS::PadNum)>::RXPO;
51    const TXPO: u8 = <(RX::PadNum, TX::PadNum, RTS::PadNum, CTS::PadNum)>::TXPO;
52}
53
54macro_rules! impl_rxpotxpo {
60    ($RX:ident, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@check_rts_cts, $RX, $TX, $RTS, $CTS); };
62
63    (@check_rts_cts, $RX:ident, $TX:ident, NoneT, NoneT) => { impl_rxpotxpo!(@rxpo, $RX, $TX, NoneT, NoneT); };
66    (@check_rts_cts, $RX:ident, $TX:ident, Pad2, NoneT) => { impl_rxpotxpo!(@rxpo, $RX, $TX, Pad2, NoneT); };
67    (@check_rts_cts, $RX:ident, $TX:ident, NoneT, Pad3) => { impl_rxpotxpo!(@rxpo, $RX, $TX, NoneT, Pad3); };
68    (@check_rts_cts, $RX:ident, $TX:ident, Pad2, Pad3) => { impl_rxpotxpo!(@rxpo, $RX, $TX, Pad2, Pad3); };
69
70    (@check_rts_cts, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident) => { };
72
73    (@rxpo, NoneT, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, NoneT, $TX, $RTS, $CTS, 0); };
76    (@rxpo, Pad0,  $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad0,  $TX, $RTS, $CTS, 0); };
77    (@rxpo, Pad1,  $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad1,  $TX, $RTS, $CTS, 1); };
78    (@rxpo, Pad2,  $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad2,  $TX, $RTS, $CTS, 2); };
79    (@rxpo, Pad3,  $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad3,  $TX, $RTS, $CTS, 3); };
80
81    (@txpo, $RX:ident, NoneT, NoneT, NoneT, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, NoneT, NoneT, NoneT, $RXPO, 0); };
83    (@txpo, $RX:ident, NoneT, Pad2, NoneT, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, NoneT, Pad2, NoneT, $RXPO, 3); };
84    (@txpo, $RX:ident, NoneT, Pad2, Pad3, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, NoneT, Pad2, Pad3, $RXPO, 2); };
85    (@txpo, $RX:ident, Pad0, NoneT, NoneT, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, Pad0, NoneT, NoneT, $RXPO, 0); };
86    (@txpo, $RX:ident, Pad0, Pad2, NoneT, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, Pad0, Pad2, NoneT, $RXPO, 3); };
87    (@txpo, $RX:ident, Pad0, Pad2, Pad3, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, Pad0, Pad2, Pad3, $RXPO, 2); };
88
89    (@txpo, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident, $RXPO:literal) => { };
91
92    (@filter, NoneT, NoneT, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; (@filter, Pad0, Pad0, $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, 1, 0) => { }; (@filter, Pad1, $TX:ident, $RTS:ident, $CTS:ident, 1, 3) => { }; (@filter, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => {
102        impl_rxpotxpo!(@implement, $RX, $TX, $RTS, $CTS, $RXPO, $TXPO);
103    };
104
105    (@implement, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => {
107        impl RxpoTxpo for ($RX, $TX, $RTS, $CTS) {
108            const RXPO: u8 = $RXPO;
109            const TXPO: u8 = $TXPO;
110        }
111    };
112}
113
114macro_rules! padnum_permutations {
127    (
130        ( $RX:ident $TX:ident $RTS:ident $CTS:ident ) [ $( $Pads:ident )* ]
131    ) => {
132        impl_rxpotxpo!($RX, $TX, $RTS, $CTS);
133    };
134    (
137        ( $($Perm:ident)* ) [ $($Pads:ident)+ ]
138    ) => {
139        padnum_permutations!( ( $($Perm)* ) [ $($Pads)+ ] [ $($Pads)+ ] );
140    };
141    (
142        ( $($Perm:ident)* ) [ $Head:ident $($Tail:ident)* ] [ $($Pads:ident)+ ]
143    ) => {
144        padnum_permutations!( ( $($Perm)* $Head ) [ $($Pads)+ ] );
147
148        padnum_permutations!( ( $($Perm)* ) [ $($Tail)* ] [ $($Pads)+ ] );
150    };
151    ( ( $($Perm:ident)* ) [ ] [ $($Pads:ident)+ ] ) => { };
153    }
154
155padnum_permutations!( () [NoneT Pad0 Pad1 Pad2 Pad3] );
156
157pub struct Pads<S, RX = NoneT, TX = NoneT, RTS = NoneT, CTS = NoneT>
166where
167    S: Sercom,
168    RX: OptionalPad,
169    TX: OptionalPad,
170    RTS: OptionalPad,
171    CTS: OptionalPad,
172    (RX, TX, RTS, CTS): ShareIoSet,
173{
174    sercom: PhantomData<S>,
175    receive: RX,
176    transmit: TX,
177    ready_to_send: RTS,
178    clear_to_send: CTS,
179}
180
181impl<S: Sercom> Default for Pads<S> {
182    fn default() -> Self {
183        Self {
184            sercom: PhantomData,
185            receive: NoneT,
186            transmit: NoneT,
187            ready_to_send: NoneT,
188            clear_to_send: NoneT,
189        }
190    }
191}
192
193impl<S, RX, TX, RTS, CTS> Pads<S, RX, TX, RTS, CTS>
194where
195    S: Sercom,
196    RX: OptionalPad,
197    TX: OptionalPad,
198    RTS: OptionalPad,
199    CTS: OptionalPad,
200    (RX, TX, RTS, CTS): ShareIoSet,
201{
202    #[inline]
204    pub fn rx<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, Pad<S, Id>, TX, RTS, CTS>
205    where
206        Id: GetPad<S>,
207        (Pad<S, Id>, TX, RTS, CTS): ShareIoSet,
208        Pin<Id, <Id as GetPad<S>>::PinMode>: IsPad,
209    {
210        Pads {
211            sercom: self.sercom,
212            receive: pin.into().into_mode(),
213            transmit: self.transmit,
214            ready_to_send: self.ready_to_send,
215            clear_to_send: self.clear_to_send,
216        }
217    }
218
219    #[inline]
221    pub fn tx<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, RX, Pad<S, Id>, RTS, CTS>
222    where
223        Id: GetPad<S>,
224        (RX, Pad<S, Id>, RTS, CTS): ShareIoSet,
225        Pin<Id, <Id as GetPad<S>>::PinMode>: IsPad,
226    {
227        Pads {
228            sercom: self.sercom,
229            receive: self.receive,
230            transmit: pin.into().into_mode(),
231            ready_to_send: self.ready_to_send,
232            clear_to_send: self.clear_to_send,
233        }
234    }
235
236    #[inline]
238    pub fn rts<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, RX, TX, Pad<S, Id>, CTS>
239    where
240        Id: GetPad<S>,
241        (RX, TX, Pad<S, Id>, CTS): ShareIoSet,
242        Pin<Id, <Id as GetPad<S>>::PinMode>: IsPad,
243    {
244        Pads {
245            sercom: self.sercom,
246            receive: self.receive,
247            transmit: self.transmit,
248            ready_to_send: pin.into().into_mode(),
249            clear_to_send: self.clear_to_send,
250        }
251    }
252
253    #[inline]
255    pub fn cts<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, RX, TX, RTS, Pad<S, Id>>
256    where
257        Id: GetPad<S>,
258        (RX, TX, RTS, Pad<S, Id>): ShareIoSet,
259        Pin<Id, <Id as GetPad<S>>::PinMode>: IsPad,
260    {
261        Pads {
262            sercom: self.sercom,
263            receive: self.receive,
264            transmit: self.transmit,
265            ready_to_send: self.ready_to_send,
266            clear_to_send: pin.into().into_mode(),
267        }
268    }
269
270    #[inline]
272    pub fn free(self) -> (RX, TX, RTS, CTS) {
273        (
274            self.receive,
275            self.transmit,
276            self.ready_to_send,
277            self.clear_to_send,
278        )
279    }
280}
281
282pub type PadsFromIds<S, RX = NoneT, TX = NoneT, RTS = NoneT, CTS = NoneT> = Pads<
311    S,
312    <RX as GetOptionalPad<S>>::Pad,
313    <TX as GetOptionalPad<S>>::Pad,
314    <RTS as GetOptionalPad<S>>::Pad,
315    <CTS as GetOptionalPad<S>>::Pad,
316>;
317
318pub trait PadSet: Sealed {
339    type Sercom: Sercom;
340    type Rx: OptionalPad;
341    type Tx: OptionalPad;
342    type Rts: OptionalPad;
343    type Cts: OptionalPad;
344}
345
346impl<S, RX, TX, RTS, CTS> Sealed for Pads<S, RX, TX, RTS, CTS>
347where
348    S: Sercom,
349    RX: OptionalPad,
350    TX: OptionalPad,
351    RTS: OptionalPad,
352    CTS: OptionalPad,
353    (RX, TX, RTS, CTS): ShareIoSet,
354{
355}
356
357impl<S, RX, TX, RTS, CTS> PadSet for Pads<S, RX, TX, RTS, CTS>
358where
359    S: Sercom,
360    RX: OptionalPad,
361    TX: OptionalPad,
362    RTS: OptionalPad,
363    CTS: OptionalPad,
364    (RX, TX, RTS, CTS): ShareIoSet,
365{
366    type Sercom = S;
367    type Rx = RX;
368    type Tx = TX;
369    type Rts = RTS;
370    type Cts = CTS;
371}
372
373pub trait ValidPads: PadSet + RxpoTxpo {
385    type Capability: Capability;
386}
387
388impl<S, RX, RTS> ValidPads for Pads<S, RX, NoneT, RTS, NoneT>
389where
390    S: Sercom,
391    RX: SomePad,
392    RTS: OptionalPad,
393    (RX, NoneT, RTS, NoneT): ShareIoSet,
394    Self: PadSet + RxpoTxpo,
395{
396    type Capability = Rx;
397}
398
399impl<S, TX, CTS> ValidPads for Pads<S, NoneT, TX, NoneT, CTS>
400where
401    S: Sercom,
402    TX: SomePad,
403    CTS: OptionalPad,
404    (NoneT, TX, NoneT, CTS): ShareIoSet,
405    Self: PadSet + RxpoTxpo,
406{
407    type Capability = Tx;
408}
409
410impl<S, RX, TX, RTS, CTS> ValidPads for Pads<S, RX, TX, RTS, CTS>
411where
412    S: Sercom,
413    RX: SomePad,
414    TX: SomePad,
415    RTS: OptionalPad,
416    CTS: OptionalPad,
417    (RX, TX, RTS, CTS): ShareIoSet,
418    Self: PadSet + RxpoTxpo,
419{
420    type Capability = Duplex;
421}
422
423pub trait ValidConfig: AnyConfig {}
432
433impl<P: ValidPads, C: CharSize> ValidConfig for Config<P, C> {}