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