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}