atsamd_hal/sercom/uart/
pads_thumbv7em.rs

1//! UART pad definitions for thumbv7em targets
2
3use 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
12//=============================================================================
13// RxpoTxpo
14//=============================================================================
15
16/// Configure the `RXPO` and `TXPO` fields based on a set of [`Pads`]
17///
18/// According to the datasheet, the `RXPO` and `TXPO` values specify which
19/// SERCOM pads are used for various functions. Moreover, depending on which
20/// pads are actually in use, only certain combinations of these values make
21/// sense and are valid.
22///
23/// This trait is implemented for valid, four-tuple combinations of
24/// [`OptionalPadNum`]s. Those implementations are then lifted to the
25/// corresponding [`Pads`] types.
26///
27/// To satisfy this trait, the combination of [`OptionalPadNum`]s must specify
28/// [`PadNum`] for at least one of `RX` and `TX`. Furthermore, no
29/// two [`PadNum`]s can conflict.
30pub trait RxpoTxpo {
31    /// `RXPO` field value
32    const RXPO: u8;
33
34    /// `RXPO` field value
35    const TXPO: u8;
36}
37
38/// Lift the implementations of [`RxpoTxpo`] from four-tuples of
39/// [`OptionalPadNum`]s to the corresponding [`Pads`] types.
40impl<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
54//=============================================================================
55// Implement RxpoTxpo
56//=============================================================================
57
58/// Filter [`PadNum`] permutations and implement [`RxpoTxpo`]
59macro_rules! impl_rxpotxpo {
60    // This is the entry pattern. Start by checking RTS and CTS.
61    ($RX:ident, $TX:ident, $RTS:ident, $CTS:ident) => { impl_rxpotxpo!(@check_rts_cts, $RX, $TX, $RTS, $CTS); };
62
63    // Check whether RTS and CTS form a valid pair.
64    // They both must be the correct pad or absent.
65    (@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    // If RTS and CTS are not valid, fall through to this pattern.
71    (@check_rts_cts, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident) => { };
72
73    // Assign RXPO based on RX.
74    // Our options are exhaustive, so no fall through pattern is needed.
75    (@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    // Assign TXPO based on TX, RTS and CTS
82    (@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    // If TX is not valid, fall through to this pattern.
90    (@txpo, $RX:ident, $TX:ident, $RTS:ident, $CTS:ident, $RXPO:literal) => { };
91
92    // Filter any remaining permutations that conflict.
93    (@filter, NoneT, NoneT, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; // RX and TX both NoneT
94    (@filter, Pad0, Pad0, $RTS:ident, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; // RX and TX both Pad0
95    (@filter, Pad2, $TX:ident, Pad2, $CTS:ident, $RXPO:literal, $TXPO:literal) => { }; // RX can't share a pad with RTS
96    (@filter, Pad3, $TX:ident, $RTS:ident, Pad3, $RXPO:literal, $TXPO:literal) => { }; // RX can't share a pad with CTS
97    (@filter, Pad1, $TX:ident, $RTS:ident, $CTS:ident, 1, 0) => { }; // RX can't be Pad1 if TXPO is 0 because of XCK conflict
98    (@filter, Pad1, $TX:ident, $RTS:ident, $CTS:ident, 1, 3) => { }; // RX can't be Pad1 if TXPO is 3 because of XCK conflict
99
100    // If there are no conflicts, fall through to this pattern
101    (@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 RxpoTxpo
106    (@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
114/// Try to implement [`RxpoTxpo`] on all possible 4-tuple permutations of
115/// [`OptionalPadNum`]s.
116///
117/// The leading `()` token tree stores a growing permutation of [`PadNum`]s.
118/// When it reaches four [`PadNum`]s, try to implement [`RxpoTxpo`].
119///
120/// The next `[]` token tree is a list of possible [`PadNum`]s to append to the
121/// growing permutation. Loop through this list and append each option to the
122/// permutation.
123///
124/// The final, optional `[]` token tree exists to temporarily store the entire
125/// list before pushing it down for the next permutation element.
126macro_rules! padnum_permutations {
127    // If we have built up four [`PadNum`]s, try to implement [`RxpoTxpo`].
128    // Ignore the remaining list of [`PadNum`]s.
129    (
130        ( $RX:ident $TX:ident $RTS:ident $CTS:ident ) [ $( $Pads:ident )* ]
131    ) => {
132        impl_rxpotxpo!($RX, $TX, $RTS, $CTS);
133    };
134    // If we only have one list of [`PadNum`]s, duplicate it, to save it for the
135    // next permutation element.
136    (
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        // Append the first [`PadNum`] from the list, then push down to the next
145        // permutation element.
146        padnum_permutations!( ( $($Perm)* $Head ) [ $($Pads)+ ] );
147
148        // Loop through the remaining [`PadNum`]s to do the same thing for each.
149        padnum_permutations!( ( $($Perm)* ) [ $($Tail)* ] [ $($Pads)+ ] );
150    };
151    // Once the list of [`PadNum`]s is empty, we're done with this element.
152    ( ( $($Perm:ident)* ) [ ] [ $($Pads:ident)+ ] ) => { };
153    }
154
155padnum_permutations!( () [NoneT Pad0 Pad1 Pad2 Pad3] );
156
157//=============================================================================
158// Pads
159//=============================================================================
160
161/// Container for a set of SERCOM [`Pad`]s
162///
163/// See the [module-level](crate::sercom::uart) documentation for more
164/// details on specifying a `Pads` type and creating instances.
165pub 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    /// Set the `RX` [`Pad`]
203    #[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    /// Set the `TX` [`Pad`]
220    #[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    /// Set the `RTS` [`Pad`], which is always [`Pad2`]
237    #[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    /// Set the `CTS` [`Pad`], which is always [`Pad3`]
254    #[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    /// Consume the [`Pads`] and return each individual [`Pad`]
271    #[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
282/// Define a set of [`Pads`] using [`PinId`]s instead of [`Pin`]s
283///
284/// In some cases, it is more convenient to specify a set of `Pads` using
285/// `PinId`s rather than `Pin`s. This alias makes it easier to do so.
286///
287/// The first parameter is the [`Sercom`], while the
288/// remaining four are effectively [`OptionalPinId`]s representing the
289/// corresponding type parameters of [`Pads`], i.e. `RX`, `TX`, `RTS` & `CTS`.
290/// Each of the remaining type parameters defaults to [`NoneT`].
291///
292/// ```
293/// use atsamd_hal::pac::Peripherals;
294/// use atsamd_hal::gpio::{PA08, PA09, Pins};
295/// use atsamd_hal::sercom::{Sercom0, uart};
296/// use atsamd_hal::typelevel::NoneT;
297///
298/// pub type Pads = uart::PadsFromIds<Sercom0, PA09, PA08>;
299///
300/// pub fn create_pads() -> Pads {
301///     let peripherals = Peripherals::take().unwrap();
302///     let pins = Pins::new(peripherals.PORT);
303///     uart::Pads::default().rx(pins.pa09).tx(pins.pa08)
304/// }
305/// ```
306///
307/// [`Pin`]: crate::gpio::Pin
308/// [`PinId`]: crate::gpio::PinId
309/// [`OptionalPinId`]: crate::gpio::OptionalPinId
310pub 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
318//=============================================================================
319// PadSet
320//=============================================================================
321
322/// Type-level function to recover the [`OptionalPad`] types from a generic set
323/// of [`Pads`]
324///
325/// This trait is used as an interface between the [`Pads`] type and other
326/// types in this module. It acts as a [type-level function], returning the
327/// corresponding [`Sercom`], and [`OptionalPad`] types. It serves to
328/// cut down on the total number of type parameters needed in the [`Config`]
329/// struct. The [`Config`] struct doesn't need access to the [`Pad`]s directly.
330/// Rather, it only needs to apply the [`SomePad`] trait bound when a `Pin` is
331/// required. The [`PadSet`] trait allows each [`Config`] struct to store an
332/// instance of [`Pads`] without itself being generic over all six type
333/// parameters of the [`Pads`] type.
334///
335/// [`Pin`]: crate::gpio::Pin
336/// [`Config`]: crate::sercom::uart::Config
337/// [type-level function]: crate::typelevel#type-level-functions
338pub 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
373//=============================================================================
374// ValidPads
375//=============================================================================
376
377/// Marker trait for valid sets of [`Pads`]
378///
379/// This trait labels sets of [`Pads`] that satisfy the [`RxpoTxpo`]
380/// trait. It guarantees to the [`Config`] struct that this set of `Pads` can
381/// be configured through those traits.
382///
383/// [`Config`]: crate::sercom::uart::Config
384pub 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
423//=============================================================================
424// ValidConfig
425//=============================================================================
426
427/// Marker trait for valid UART [`Config`]urations
428///
429/// A functional UART peripheral must have, at a minimum either a Rx or a Tx
430/// [`Pad`].
431pub trait ValidConfig: AnyConfig {}
432
433impl<P: ValidPads, C: CharSize> ValidConfig for Config<P, C> {}