atsamd_hal/sercom/uart/
pads_thumbv6m.rs

1//! UART pad definitions for thumbv6m targets
2
3use atsamd_hal_macros::hal_cfg;
4
5use super::{AnyConfig, Capability, CharSize, Config, Duplex, Rx, Tx};
6use crate::{
7    sercom::*,
8    typelevel::{NoneT, Sealed},
9};
10use core::marker::PhantomData;
11
12#[hal_cfg("sercom0-d21")]
13use crate::gpio::AnyPin;
14
15//=============================================================================
16// RxpoTxpo
17//=============================================================================
18
19/// Configure the `RXPO` and `TXPO` fields based on a set of [`Pads`]
20///
21/// According to the datasheet, the `RXPO` and `TXPO` values specify which
22/// SERCOM pads are used for various functions. Moreover, depending on which
23/// pads are actually in use, only certain combinations of these values make
24/// sense and are valid.
25///
26/// This trait is implemented for valid, four-tuple combinations of
27/// [`OptionalPadNum`]s. Those implementations are then lifted to the
28/// corresponding [`Pads`] types.
29///
30/// To satisfy this trait, the combination of [`OptionalPadNum`]s must specify
31/// [`PadNum`] for at least one of `RX` and `TX`. Furthermore, no
32/// two [`PadNum`]s can conflict.
33pub trait RxpoTxpo {
34    /// `RXPO` field value
35    const RXPO: u8;
36
37    /// `RXPO` field value
38    const TXPO: u8;
39}
40
41/// Lift the implementations of [`RxpoTxpo`] from four-tuples of
42/// [`OptionalPadNum`]s to the corresponding [`Pads`] types.
43impl<S, RX, TX, RTS, CTS> RxpoTxpo for Pads<S, RX, TX, RTS, CTS>
44where
45    S: Sercom,
46    RX: OptionalPad,
47    TX: OptionalPad,
48    RTS: OptionalPad,
49    CTS: OptionalPad,
50    (RX::PadNum, TX::PadNum, RTS::PadNum, CTS::PadNum): RxpoTxpo,
51{
52    const RXPO: u8 = <(RX::PadNum, TX::PadNum, RTS::PadNum, CTS::PadNum)>::RXPO;
53    const TXPO: u8 = <(RX::PadNum, TX::PadNum, RTS::PadNum, CTS::PadNum)>::TXPO;
54}
55
56//=============================================================================
57// Implement RxpoTxpo
58//=============================================================================
59
60/// Filter [`PadNum`] permutations and implement [`RxpoTxpo`]
61macro_rules! impl_rxpotxpo {
62    // This is the entry pattern. Start by checking RTS and CTS.
63    ($RX:ident, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@check_rts_cts, $RX, $TX, $RTS, $CTS); };
64
65    // Check whether RTS and CTS form a valid pair.
66    // They both must be the correct pad or absent.
67    (@check_rts_cts, $RX:ident, $TX:ident, NoneT, NoneT) => { impl_rxpotxpo!(@rxpo, $RX, $TX, NoneT, NoneT); };
68    (@check_rts_cts, $RX:ident, $TX:ident, Pad2, NoneT) => { impl_rxpotxpo!(@rxpo, $RX, $TX, Pad2, NoneT); };
69    (@check_rts_cts, $RX:ident, $TX:ident, NoneT, Pad3) => { impl_rxpotxpo!(@rxpo, $RX, $TX, NoneT, Pad3); };
70    (@check_rts_cts, $RX:ident, $TX:ident, Pad2, Pad3) => { impl_rxpotxpo!(@rxpo, $RX, $TX, Pad2, Pad3); };
71
72    // If RTS and CTS are not valid, fall through to this pattern.
73    (@check_rts_cts, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident) => { };
74
75    // Assign RXPO based on RX.
76    // Our options are exhaustive, so no fall through pattern is needed.
77    (@rxpo, NoneT, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, NoneT, $TX, $RTS, $CTS, 0); };
78    (@rxpo, Pad0,  $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad0,  $TX, $RTS, $CTS, 0); };
79    (@rxpo, Pad1,  $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad1,  $TX, $RTS, $CTS, 1); };
80    (@rxpo, Pad2,  $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad2,  $TX, $RTS, $CTS, 2); };
81    (@rxpo, Pad3,  $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@txpo, Pad3,  $TX, $RTS, $CTS, 3); };
82
83    // Assign TXPO based on TX and RTS
84    (@txpo, $RX:ident, NoneT, NoneT, $CTS:ident, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, NoneT, NoneT, $CTS, $RXPO, 0); };
85    (@txpo, $RX:ident, NoneT, Pad2, $CTS:ident, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, NoneT, Pad2, $CTS, $RXPO, 2); };
86    (@txpo, $RX:ident, Pad0, NoneT, $CTS:ident, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, Pad0, NoneT, $CTS, $RXPO, 0); };
87    (@txpo, $RX:ident, Pad2, NoneT, $CTS:ident, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, Pad2, NoneT, $CTS, $RXPO, 1); };
88    (@txpo, $RX:ident, Pad0, Pad2, $CTS:ident, $RXPO:literal) => { impl_rxpotxpo!(@filter, $RX, Pad0, Pad2, $CTS, $RXPO, 2); };
89
90    // If TX is not valid, fall through to this pattern.
91    (@txpo, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident, $RXPO:literal) => { };
92
93    // Filter any remaining permutations that conflict.
94    (@filter, NoneT, NoneT, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; // RX and TX both NoneT
95    (@filter, Pad0, Pad0, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; // RX and TX both Pad0
96    (@filter, Pad2, Pad2, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; // RX and TX both Pad2
97    (@filter, Pad2, $TX:ident, Pad2, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; // RX can't share a pad with RTS
98    (@filter, Pad3, $TX:ident, $RTS:ident, Pad3, $RXPO:literal, $TXPO:literal) => { }; // RX can't share a pad with CTS
99    (@filter, Pad1, $TX:ident, $RTS:ident, $CTS:ident, 0, $TXPO:literal) => { }; // RX can't be Pad1 when TXPO is 0 because of XCK conflict
100    (@filter, Pad3, $TX:ident, $RTS:ident, $CTS:ident, 1, $TXPO:literal) => { }; // RX can't be Pad3 when TXPO is 1 because of XCK conflict
101
102    // If there are no conflicts, fall through to this pattern
103    (@filter, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => {
104        impl_rxpotxpo!(@implement, $RX, $TX, $RTS, $CTS, $RXPO, $TXPO);
105    };
106
107    // If there are no conflicts, fall through to this pattern and implement RxpoTxpo
108    (@implement, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => {
109        impl RxpoTxpo for ($RX, $TX, $RTS, $CTS) {
110            const RXPO: u8 = $RXPO;
111            const TXPO: u8 = $TXPO;
112        }
113    };
114}
115
116/// Try to implement [`RxpoTxpo`] on all possible 4-tuple permutations of
117/// [`OptionalPadNum`]s.
118///
119/// The leading `()` token tree stores a growing permutation of [`PadNum`]s.
120/// When it reaches four [`PadNum`]s, try to implement [`RxpoTxpo`].
121///
122/// The next `[]` token tree is a list of possible [`PadNum`]s to append to the
123/// growing permutation. Loop through this list and append each option to the
124/// permutation.
125///
126/// The final, optional `[]` token tree exists to temporarily store the entire
127/// list before pushing it down for the next permutation element.
128macro_rules! padnum_permutations {
129    // If we have built up four [`PadNum`]s, try to implement [`RxpoTxpo`].
130    // Ignore the remaining list of [`PadNum`]s.
131    (
132        ( $RX:ident $TX:ident $RTS:ident $CTS:ident ) [ $( $Pads:ident )* ]
133    ) => {
134        impl_rxpotxpo!($RX, $TX, $RTS, $CTS);
135    };
136    // If we only have one list of [`PadNum`]s, duplicate it, to save it for the
137    // next permutation element.
138    (
139        ( $($Perm:ident)* ) [ $($Pads:ident)+ ]
140    ) => {
141        padnum_permutations!( ( $($Perm)* ) [ $($Pads)+ ] [ $($Pads)+ ] );
142    };
143    (
144        ( $($Perm:ident)* ) [ $Head:ident $($Tail:ident)* ] [ $($Pads:ident)+ ]
145    ) => {
146        // Append the first [`PadNum`] from the list, then push down to the next
147        // permutation element.
148        padnum_permutations!( ( $($Perm)* $Head ) [ $($Pads)+ ] );
149
150        // Loop through the remaining [`PadNum`]s to do the same thing for each.
151        padnum_permutations!( ( $($Perm)* ) [ $($Tail)* ] [ $($Pads)+ ] );
152    };
153    // Once the list of [`PadNum`]s is empty, we're done with this element.
154    ( ( $($Perm:ident)* ) [ ] [ $($Pads:ident)+ ] ) => { };
155    }
156
157padnum_permutations!( () [NoneT Pad0 Pad1 Pad2 Pad3] );
158
159//=============================================================================
160// Pads
161//=============================================================================
162
163/// Container for a set of SERCOM [`Pad`]s
164///
165/// See the [module-level](crate::sercom::uart) documentation for more
166/// details on specifying a `Pads` type and creating instances.
167pub struct Pads<S, RX = NoneT, TX = NoneT, RTS = NoneT, CTS = NoneT>
168where
169    S: Sercom,
170    RX: OptionalPad,
171    TX: OptionalPad,
172    RTS: OptionalPad,
173    CTS: OptionalPad,
174{
175    sercom: PhantomData<S>,
176    receive: RX,
177    transmit: TX,
178    ready_to_send: RTS,
179    clear_to_send: CTS,
180}
181
182impl<S: Sercom> Default for Pads<S> {
183    fn default() -> Self {
184        Self {
185            sercom: PhantomData,
186            receive: NoneT,
187            transmit: NoneT,
188            ready_to_send: NoneT,
189            clear_to_send: NoneT,
190        }
191    }
192}
193
194impl<S, RX, TX, RTS, CTS> Pads<S, RX, TX, RTS, CTS>
195where
196    S: Sercom,
197    RX: OptionalPad,
198    TX: OptionalPad,
199    RTS: OptionalPad,
200    CTS: OptionalPad,
201{
202    /// Consume the [`Pads`] and return each individual [`Pad`]
203    #[inline]
204    pub fn free(self) -> (RX, TX, RTS, CTS) {
205        (
206            self.receive,
207            self.transmit,
208            self.ready_to_send,
209            self.clear_to_send,
210        )
211    }
212}
213
214#[hal_cfg("sercom0-d11")]
215impl<S, RX, TX, RTS, CTS> Pads<S, RX, TX, RTS, CTS>
216where
217    S: Sercom,
218    RX: OptionalPad,
219    TX: OptionalPad,
220    RTS: OptionalPad,
221    CTS: OptionalPad,
222{
223    /// Set the `RX` [`Pad`]
224    #[inline]
225    pub fn rx<P: IsPad>(self, pin: P) -> Pads<S, P, TX, RTS, CTS> {
226        Pads {
227            sercom: self.sercom,
228            receive: pin,
229            transmit: self.transmit,
230            ready_to_send: self.ready_to_send,
231            clear_to_send: self.clear_to_send,
232        }
233    }
234
235    /// Set the `TX` [`Pad`]
236    #[inline]
237    pub fn tx<P: IsPad>(self, pin: P) -> Pads<S, RX, P, RTS, CTS> {
238        Pads {
239            sercom: self.sercom,
240            receive: self.receive,
241            transmit: pin,
242            ready_to_send: self.ready_to_send,
243            clear_to_send: self.clear_to_send,
244        }
245    }
246
247    /// Set the `RTS` [`Pad`]
248    #[inline]
249    pub fn rts<P: IsPad>(self, pin: P) -> Pads<S, RX, TX, P, CTS> {
250        Pads {
251            sercom: self.sercom,
252            receive: self.receive,
253            transmit: self.transmit,
254            ready_to_send: pin,
255            clear_to_send: self.clear_to_send,
256        }
257    }
258
259    /// Set the `CTS` [`Pad`]
260    #[inline]
261    pub fn cts<P: IsPad>(self, pin: P) -> Pads<S, RX, TX, RTS, P> {
262        Pads {
263            sercom: self.sercom,
264            receive: self.receive,
265            transmit: self.transmit,
266            ready_to_send: self.ready_to_send,
267            clear_to_send: pin,
268        }
269    }
270}
271
272#[hal_cfg("sercom0-d21")]
273impl<S, RX, TX, RTS, CTS> Pads<S, RX, TX, RTS, CTS>
274where
275    S: Sercom,
276    RX: OptionalPad,
277    TX: OptionalPad,
278    RTS: OptionalPad,
279    CTS: OptionalPad,
280{
281    /// Set the `RX` [`Pad`]
282    #[inline]
283    pub fn rx<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, Pad<S, I>, TX, RTS, CTS>
284    where
285        I: GetPad<S>,
286        Pad<S, I>: IsPad,
287    {
288        Pads {
289            sercom: self.sercom,
290            receive: pin.into().into_mode(),
291            transmit: self.transmit,
292            ready_to_send: self.ready_to_send,
293            clear_to_send: self.clear_to_send,
294        }
295    }
296
297    /// Set the `TX` [`Pad`]
298    #[inline]
299    pub fn tx<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, RX, Pad<S, I>, RTS, CTS>
300    where
301        I: GetPad<S>,
302        Pad<S, I>: IsPad,
303    {
304        Pads {
305            sercom: self.sercom,
306            receive: self.receive,
307            transmit: pin.into().into_mode(),
308            ready_to_send: self.ready_to_send,
309            clear_to_send: self.clear_to_send,
310        }
311    }
312
313    /// Set the `RTS` [`Pad`]
314    #[inline]
315    pub fn rts<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, RX, TX, Pad<S, I>, CTS>
316    where
317        I: GetPad<S>,
318        Pad<S, I>: IsPad,
319    {
320        Pads {
321            sercom: self.sercom,
322            receive: self.receive,
323            transmit: self.transmit,
324            ready_to_send: pin.into().into_mode(),
325            clear_to_send: self.clear_to_send,
326        }
327    }
328
329    /// Set the `CTS` [`Pad`]
330    #[inline]
331    pub fn cts<I>(self, pin: impl AnyPin<Id = I>) -> Pads<S, RX, TX, RTS, Pad<S, I>>
332    where
333        I: GetPad<S>,
334        Pad<S, I>: IsPad,
335    {
336        Pads {
337            sercom: self.sercom,
338            receive: self.receive,
339            transmit: self.transmit,
340            ready_to_send: self.ready_to_send,
341            clear_to_send: pin.into().into_mode(),
342        }
343    }
344}
345
346/// Define a set of [`Pads`] using [`PinId`]s instead of [`Pin`]s
347///
348/// In some cases, it is more convenient to specify a set of `Pads` using
349/// `PinId`s rather than `Pin`s. This alias makes it easier to do so.
350///
351/// The first type parameter is the [`Sercom`], while the remaining four are
352/// effectively [`OptionalPinId`]s representing the corresponding type
353/// parameters of [`Pads`], i.e. `RX`, `TX`, `RTS` & `CTS`. Each of the
354/// remaining type parameters defaults to [`NoneT`].
355///
356/// ```
357/// use atsamd_hal::pac::Peripherals;
358/// use atsamd_hal::gpio::{PA08, PA09, Pins};
359/// use atsamd_hal::sercom::{Sercom0, uart};
360/// use atsamd_hal::typelevel::NoneT;
361///
362/// pub type Pads = uart::PadsFromIds<Sercom0, PA08, PA09>;
363///
364/// pub fn create_pads() -> Pads {
365///     let peripherals = Peripherals::take().unwrap();
366///     let pins = Pins::new(peripherals.PORT);
367///     uart::Pads::default().rx(pins.pa09).tx(pins.pa08)
368/// }
369/// ```
370///
371/// [`Pin`]: crate::gpio::Pin
372/// [`PinId`]: crate::gpio::PinId
373/// [`OptionalPinId`]: crate::gpio::OptionalPinId
374
375#[hal_cfg("sercom0-d21")]
376pub type PadsFromIds<S, RX = NoneT, TX = NoneT, RTS = NoneT, CTS = NoneT> = Pads<
377    S,
378    <RX as GetOptionalPad<S>>::Pad,
379    <TX as GetOptionalPad<S>>::Pad,
380    <RTS as GetOptionalPad<S>>::Pad,
381    <CTS as GetOptionalPad<S>>::Pad,
382>;
383
384//=============================================================================
385// PadSet
386//=============================================================================
387
388/// Type-level function to recover the [`OptionalPad`] types from a generic set
389/// of [`Pads`]
390///
391/// This trait is used as an interface between the [`Pads`] type and other
392/// types in this module. It acts as a [type-level function], returning the
393/// corresponding [`Sercom`] and [`OptionalPad`] types. It serves to cut down on
394/// the total number of type parameters needed in the [`Config`] struct. The
395/// [`Config`] struct doesn't need access to the [`Pin`]s directly.  Rather, it
396/// only needs to apply the [`SomePad`] trait bound when a `Pin` is required.
397/// The [`PadSet`] trait allows each [`Config`] struct to store an instance of
398/// [`Pads`] without itself being generic over all six type parameters of the
399/// [`Pads`] type.
400///
401/// [`Pin`]: crate::gpio::Pin
402/// [type-level function]: crate::typelevel#type-level-functions
403/// [`Config`]: crate::sercom::uart::Config
404pub trait PadSet: Sealed {
405    type Sercom: Sercom;
406    type Rx: OptionalPad;
407    type Tx: OptionalPad;
408    type Rts: OptionalPad;
409    type Cts: OptionalPad;
410}
411
412impl<S, RX, TX, RTS, CTS> Sealed for Pads<S, RX, TX, RTS, CTS>
413where
414    S: Sercom,
415    RX: OptionalPad,
416    TX: OptionalPad,
417    RTS: OptionalPad,
418    CTS: OptionalPad,
419{
420}
421
422impl<S, RX, TX, RTS, CTS> PadSet for Pads<S, RX, TX, RTS, CTS>
423where
424    S: Sercom,
425    RX: OptionalPad,
426    TX: OptionalPad,
427    RTS: OptionalPad,
428    CTS: OptionalPad,
429{
430    type Sercom = S;
431    type Rx = RX;
432    type Tx = TX;
433    type Rts = RTS;
434    type Cts = CTS;
435}
436
437//=============================================================================
438// ValidPads
439//=============================================================================
440
441/// Marker trait for valid sets of [`Pads`]
442///
443/// This trait labels sets of [`Pads`] that satisfy the [`RxpoTxpo`] trait. It
444/// guarantees to the [`Config`] struct that this set of `Pads` can be
445/// configured through that trait.
446///
447/// [`Config`]: crate::sercom::uart::Config
448pub trait ValidPads: PadSet + RxpoTxpo {
449    type Capability: Capability;
450}
451
452impl<S, RX, RTS> ValidPads for Pads<S, RX, NoneT, RTS, NoneT>
453where
454    S: Sercom,
455    RX: SomePad,
456    RTS: OptionalPad,
457    Self: PadSet + RxpoTxpo,
458{
459    type Capability = Rx;
460}
461
462impl<S, TX, CTS> ValidPads for Pads<S, NoneT, TX, NoneT, CTS>
463where
464    S: Sercom,
465    TX: SomePad,
466    CTS: OptionalPad,
467    Self: PadSet + RxpoTxpo,
468{
469    type Capability = Tx;
470}
471
472impl<S, RX, TX, RTS, CTS> ValidPads for Pads<S, RX, TX, RTS, CTS>
473where
474    S: Sercom,
475    RX: SomePad,
476    TX: SomePad,
477    RTS: OptionalPad,
478    CTS: OptionalPad,
479    Self: PadSet + RxpoTxpo,
480{
481    type Capability = Duplex;
482}
483
484//=============================================================================
485// ValidConfig
486//=============================================================================
487
488/// Marker trait for valid UART [`Config`]urations
489///
490/// A functional UART peripheral must have, at a minimum either a Rx or a Tx
491/// [`Pad`].
492pub trait ValidConfig: AnyConfig {}
493
494impl<P: ValidPads, C: CharSize> ValidConfig for Config<P, C> {}