1use atsamd_hal_macros::hal_cfg;
7
8use core::marker::PhantomData;
9
10#[hal_cfg("sercom0-d21")]
11use crate::gpio::AnyPin;
12use crate::sercom::*;
13use crate::typelevel::{NoneT, Sealed};
14
15use super::{Capability, Duplex, Rx, Tx};
16
17pub trait DipoDopo {
36    const DIPO_DOPO: (u8, u8);
37}
38
39impl<S, DI, DO, CK, SS> DipoDopo for Pads<S, DI, DO, CK, SS>
42where
43    S: Sercom,
44    DI: OptionalPad,
45    DO: OptionalPad,
46    CK: OptionalPad,
47    SS: OptionalPad,
48    (DI::PadNum, DO::PadNum, CK::PadNum, SS::PadNum): DipoDopo,
49{
50    const DIPO_DOPO: (u8, u8) = <(DI::PadNum, DO::PadNum, CK::PadNum, SS::PadNum)>::DIPO_DOPO;
51}
52
53#[rustfmt::skip]
59macro_rules! impl_dipodopo {
60    ($DI:ident, $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@ck_ss, $DI, $DO, $CK, $SS); };
62
63    (@ck_ss, $DI:ident, $DO:ident, Pad1, NoneT) => { impl_dipodopo!(@dipo, $DI, $DO, Pad1, NoneT); };
66    (@ck_ss, $DI:ident, $DO:ident, Pad1, Pad2)  => { impl_dipodopo!(@dipo, $DI, $DO, Pad1, Pad2); };
67    (@ck_ss, $DI:ident, $DO:ident, Pad3, NoneT) => { impl_dipodopo!(@dipo, $DI, $DO, Pad3, NoneT); };
68    (@ck_ss, $DI:ident, $DO:ident, Pad3, Pad1)  => { impl_dipodopo!(@dipo, $DI, $DO, Pad3, Pad1); };
69
70    (@ck_ss, $DI:ident, $DO:ident, $CK:ident, $SS:ident) => { };
72
73    (@dipo, NoneT, $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@dopo, NoneT, $DO, $CK, $SS, 0); };
76    (@dipo, Pad0,  $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@dopo, Pad0,  $DO, $CK, $SS, 0); };
77    (@dipo, Pad1,  $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@dopo, Pad1,  $DO, $CK, $SS, 1); };
78    (@dipo, Pad2,  $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@dopo, Pad2,  $DO, $CK, $SS, 2); };
79    (@dipo, Pad3,  $DO:ident, $CK:ident, $SS:ident) => { impl_dipodopo!(@dopo, Pad3,  $DO, $CK, $SS, 3); };
80
81    (@dopo, $DI:ident, NoneT, Pad1, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, NoneT, Pad1, $SS, $DIPO, 0); };
83    (@dopo, $DI:ident, NoneT, Pad3, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, NoneT, Pad3, $SS, $DIPO, 1); };
84    (@dopo, $DI:ident, Pad0,  Pad1, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, Pad0,  Pad1, $SS, $DIPO, 0); };
85    (@dopo, $DI:ident, Pad2,  Pad3, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, Pad2,  Pad3, $SS, $DIPO, 1); };
86    (@dopo, $DI:ident, Pad3,  Pad1, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, Pad3,  Pad1, $SS, $DIPO, 2); };
87    (@dopo, $DI:ident, Pad0,  Pad3, $SS:ident, $DIPO:literal) => { impl_dipodopo!(@filter, $DI, Pad0,  Pad3, $SS, $DIPO, 3); };
88
89    (@dopo, $DI:ident, $DO:ident, $CK:ident, $SS:ident, $DIPO:literal) => { };
91
92    (@filter, NoneT, NoneT, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
94    (@filter, Pad0, Pad0, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
95    (@filter, Pad1, $DO:ident, Pad1, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
96    (@filter, Pad1, $DO:ident, $CK:ident, Pad1, $DIPO:literal, $DOPO:literal) => { };
97    (@filter, Pad2, Pad2, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
98    (@filter, Pad2, $DO:ident, $CK:ident, Pad2, $DIPO:literal, $DOPO:literal) => { };
99    (@filter, Pad3, Pad3, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
100    (@filter, Pad3, $DO:ident, Pad3, $SS:ident, $DIPO:literal, $DOPO:literal) => { };
101    (@filter, $DI:ident, Pad2, $CK:ident, Pad2, $DIPO:literal, $DOPO:literal) => { };
102
103    (@filter, $DI:ident, $DO:ident, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@revise, $DI, $DO, $CK, $SS, $DIPO, $DOPO); };
105
106    (@revise, NoneT, Pad0, Pad1, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@implement, NoneT, Pad0, Pad1, $SS, 3, $DOPO); };
108    (@revise, NoneT, Pad0, Pad3, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@implement, NoneT, Pad0, Pad3, $SS, 2, $DOPO); };
109    (@revise, Pad0, NoneT, Pad1, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@implement, Pad0, NoneT, Pad1, $SS, $DIPO, 2); };
110    (@revise, Pad2, NoneT, Pad3, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@implement, Pad2, NoneT, Pad3, $SS, $DIPO, 3); };
111
112    (@revise, $DI:ident, $DO:ident, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => { impl_dipodopo!(@implement, $DI, $DO, $CK, $SS, $DIPO, $DOPO); };
114
115    (@implement, $DI:ident, $DO:ident, $CK:ident, $SS:ident, $DIPO:literal, $DOPO:literal) => {
117        impl DipoDopo for ($DI, $DO, $CK, $SS) {
118            const DIPO_DOPO: (u8, u8) = ($DIPO, $DOPO);
119        }
120    };
121}
122
123macro_rules! padnum_permutations {
136    (
139        ( $DI:ident $DO:ident $CK:ident $SS:ident ) [ $( $Pads:ident )* ]
140    ) => {
141        impl_dipodopo!($DI, $DO, $CK, $SS);
142    };
143    (
146        ( $($Perm:ident)* ) [ $($Pads:ident)+ ]
147    ) => {
148        padnum_permutations!( ( $($Perm)* ) [ $($Pads)+ ] [ $($Pads)+ ] );
149    };
150    (
151        ( $($Perm:ident)* ) [ $Head:ident $($Tail:ident)* ] [ $($Pads:ident)+ ]
152    ) => {
153        padnum_permutations!( ( $($Perm)* $Head ) [ $($Pads)+ ] );
156
157        padnum_permutations!( ( $($Perm)* ) [ $($Tail)* ] [ $($Pads)+ ] );
159    };
160    ( ( $($Perm:ident)* ) [ ] [ $($Pads:ident)+ ] ) => { };
162}
163
164padnum_permutations!( () [NoneT Pad0 Pad1 Pad2 Pad3] );
165
166pub struct Pads<S, DI = NoneT, DO = NoneT, CK = NoneT, SS = NoneT>
175where
176    S: Sercom,
177    DI: OptionalPad,
178    DO: OptionalPad,
179    CK: OptionalPad,
180    SS: OptionalPad,
181{
182    sercom: PhantomData<S>,
183    data_in: DI,
184    data_out: DO,
185    sclk: CK,
186    ss: SS,
187}
188
189impl<S: Sercom> Default for Pads<S> {
190    fn default() -> Self {
191        Self {
192            sercom: PhantomData,
193            data_in: NoneT,
194            data_out: NoneT,
195            sclk: NoneT,
196            ss: NoneT,
197        }
198    }
199}
200
201impl<S, DI, DO, CK, SS> Pads<S, DI, DO, CK, SS>
202where
203    S: Sercom,
204    DI: OptionalPad,
205    DO: OptionalPad,
206    CK: OptionalPad,
207    SS: OptionalPad,
208{
209    #[inline]
212    pub fn free(self) -> (DI, DO, CK, SS) {
213        (self.data_in, self.data_out, self.sclk, self.ss)
214    }
215}
216
217#[hal_cfg("sercom0-d11")]
218impl<S, DI, DO, CK, SS> Pads<S, DI, DO, CK, SS>
219where
220    S: Sercom,
221    DI: OptionalPad,
222    DO: OptionalPad,
223    CK: OptionalPad,
224    SS: OptionalPad,
225{
226    #[inline]
235    pub fn data_in<P: IsPad>(self, pin: P) -> Pads<S, P, DO, CK, SS> {
236        Pads {
237            sercom: self.sercom,
238            data_in: pin,
239            data_out: self.data_out,
240            sclk: self.sclk,
241            ss: self.ss,
242        }
243    }
244
245    #[inline]
254    pub fn data_out<P: IsPad>(self, pin: P) -> Pads<S, DI, P, CK, SS> {
255        Pads {
256            sercom: self.sercom,
257            data_in: self.data_in,
258            data_out: pin,
259            sclk: self.sclk,
260            ss: self.ss,
261        }
262    }
263
264    #[inline]
266    pub fn sclk<P: IsPad>(self, pin: P) -> Pads<S, DI, DO, P, SS> {
267        Pads {
268            sercom: self.sercom,
269            data_in: self.data_in,
270            data_out: self.data_out,
271            sclk: pin,
272            ss: self.ss,
273        }
274    }
275
276    #[inline]
278    pub fn ss<P: IsPad>(self, pin: P) -> Pads<S, DI, DO, CK, P> {
279        Pads {
280            sercom: self.sercom,
281            data_in: self.data_in,
282            data_out: self.data_out,
283            sclk: self.sclk,
284            ss: pin,
285        }
286    }
287}
288
289#[hal_cfg("sercom0-d21")]
290impl<S, DI, DO, CK, SS> Pads<S, DI, DO, CK, SS>
291where
292    S: Sercom,
293    DI: OptionalPad,
294    DO: OptionalPad,
295    CK: OptionalPad,
296    SS: OptionalPad,
297{
298    #[inline]
307    pub fn data_in<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, Pad<S, I>, DO, CK, SS>
308    where
309        I: GetPad<S>,
310        Pad<S, I>: IsPad,
311    {
312        Pads {
313            sercom: self.sercom,
314            data_in: pin.into().into_mode(),
315            data_out: self.data_out,
316            sclk: self.sclk,
317            ss: self.ss,
318        }
319    }
320
321    #[inline]
330    pub fn data_out<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, DI, Pad<S, I>, CK, SS>
331    where
332        I: GetPad<S>,
333        Pad<S, I>: IsPad,
334    {
335        Pads {
336            sercom: self.sercom,
337            data_in: self.data_in,
338            data_out: pin.into().into_mode(),
339            sclk: self.sclk,
340            ss: self.ss,
341        }
342    }
343
344    #[inline]
346    pub fn sclk<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, DI, DO, Pad<S, I>, SS>
347    where
348        I: GetPad<S>,
349        Pad<S, I>: IsPad,
350    {
351        Pads {
352            sercom: self.sercom,
353            data_in: self.data_in,
354            data_out: self.data_out,
355            sclk: pin.into().into_mode(),
356            ss: self.ss,
357        }
358    }
359
360    #[inline]
362    pub fn ss<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, DI, DO, CK, Pad<S, I>>
363    where
364        I: GetPad<S>,
365        Pad<S, I>: IsPad,
366    {
367        Pads {
368            sercom: self.sercom,
369            data_in: self.data_in,
370            data_out: self.data_out,
371            sclk: self.sclk,
372            ss: pin.into().into_mode(),
373        }
374    }
375}
376
377#[hal_cfg("sercom0-d21")]
410pub type PadsFromIds<S, DI = NoneT, DO = NoneT, CK = NoneT, SS = NoneT> = Pads<
411    S,
412    <DI as GetOptionalPad<S>>::Pad,
413    <DO as GetOptionalPad<S>>::Pad,
414    <CK as GetOptionalPad<S>>::Pad,
415    <SS as GetOptionalPad<S>>::Pad,
416>;
417
418pub trait PadSet: Sealed {
442    type Sercom: Sercom;
443    type DataIn: OptionalPad;
444    type DataOut: OptionalPad;
445    type Sclk: OptionalPad;
446    type SS: OptionalPad;
447}
448
449impl<S, DI, DO, CK, SS> Sealed for Pads<S, DI, DO, CK, SS>
450where
451    S: Sercom,
452    DI: OptionalPad,
453    DO: OptionalPad,
454    CK: OptionalPad,
455    SS: OptionalPad,
456{
457}
458
459impl<S, DI, DO, CK, SS> PadSet for Pads<S, DI, DO, CK, SS>
460where
461    S: Sercom,
462    DI: OptionalPad,
463    DO: OptionalPad,
464    CK: OptionalPad,
465    SS: OptionalPad,
466{
467    type Sercom = S;
468    type DataIn = DI;
469    type DataOut = DO;
470    type Sclk = CK;
471    type SS = SS;
472}
473
474pub trait ValidPads: PadSet + DipoDopo {
485    type Capability: Capability;
486}
487
488impl<S, DI, CK, SS> ValidPads for Pads<S, DI, NoneT, CK, SS>
489where
490    S: Sercom,
491    DI: SomePad,
492    CK: SomePad,
493    SS: OptionalPad,
494    Pads<S, DI, NoneT, CK, SS>: DipoDopo,
495{
496    type Capability = Rx;
497}
498
499impl<S, DO, CK, SS> ValidPads for Pads<S, NoneT, DO, CK, SS>
500where
501    S: Sercom,
502    DO: SomePad,
503    CK: SomePad,
504    SS: OptionalPad,
505    Pads<S, NoneT, DO, CK, SS>: DipoDopo,
506{
507    type Capability = Tx;
508}
509
510impl<S, DI, DO, CK, SS> ValidPads for Pads<S, DI, DO, CK, SS>
511where
512    S: Sercom,
513    DI: SomePad,
514    DO: SomePad,
515    CK: SomePad,
516    SS: OptionalPad,
517    Pads<S, DI, DO, CK, SS>: DipoDopo,
518{
519    type Capability = Duplex;
520}