Skip to main content

rp2040_hal/uart/
pins.rs

1use core::marker::PhantomData;
2
3use crate::gpio::{bank0::*, pin::pin_sealed::TypeLevelPinId, AnyPin, FunctionUart};
4use crate::pac::{UART0, UART1};
5use crate::typelevel::{OptionT, OptionTNone, OptionTSome, Sealed};
6
7use super::UartDevice;
8
9// All type level checked pins are inherently valid.
10macro_rules! pin_validation {
11    ($p:ident) => {
12        paste::paste!{
13            #[doc = "Indicates a valid " $p " pin for UART0 or UART1"]
14            pub trait [<ValidPinId $p>]<UART: UartDevice>: Sealed {}
15
16            #[doc = "Indicates a valid " $p " pin for UART0 or UART1"]
17            pub trait [<ValidPin $p>]<UART: UartDevice>: Sealed {}
18
19            impl<T, U: UartDevice> [<ValidPin $p>]<U> for T
20            where
21                T: AnyPin<Function = FunctionUart>,
22                T::Id: [<ValidPinId $p>]<U>,
23            {
24            }
25
26            #[doc = "A runtime validated " $p " pin for uart."]
27            pub struct [<ValidatedPin $p>]<P, Uart>(P, PhantomData<Uart>);
28            impl<P, UART: UartDevice> Sealed for [<ValidatedPin $p>]<P, UART> {}
29            impl<P, UART: UartDevice> [<ValidPin $p>]<UART> for [<ValidatedPin $p>]<P, UART> {}
30            impl<P, U> [<ValidatedPin $p>]<P, U>
31            where
32                P: AnyPin<Function = FunctionUart>,
33                U: UartDevice,
34            {
35                /// Validate a pin's function on a uart peripheral.
36                ///
37                #[doc = "Will err if the pin cannot be used as a " $p " pin for that Uart."]
38                pub fn validate(p: P, _u: &U) -> Result<Self, P> {
39                    if [<$p:upper>].contains(&(p.borrow().id().num, U::ID)) &&
40                        p.borrow().id().bank == crate::gpio::DynBankId::Bank0 {
41                        Ok(Self(p, PhantomData))
42                    } else {
43                        Err(p)
44                    }
45                }
46            }
47
48            #[doc = "Indicates a valid optional " $p " pin for UART0 or UART1"]
49            pub trait [<ValidOption $p>]<U>: OptionT {}
50
51            impl<U: UartDevice> [<ValidOption $p>]<U> for OptionTNone {}
52            impl<U, T> [<ValidOption $p>]<U> for OptionTSome<T>
53            where
54                U: UartDevice,
55                T: [<ValidPin $p>]<U>,
56            {
57            }
58        }
59    };
60    ($($p:ident),*) => {
61        $(
62            pin_validation!($p);
63         )*
64    };
65}
66pin_validation!(Tx, Rx, Cts, Rts);
67
68macro_rules! impl_valid_uart {
69    ($($uart:ident: {
70        tx: [$($tx:ident),*],
71        rx: [$($rx:ident),*],
72        cts: [$($cts:ident),*],
73        rts: [$($rts:ident),*],
74    }),*) => {
75        $(
76            $(impl ValidPinIdTx<$uart> for $tx {})*
77            $(impl ValidPinIdRx<$uart> for $rx {})*
78            $(impl ValidPinIdCts<$uart> for $cts {})*
79            $(impl ValidPinIdRts<$uart> for $rts {})*
80        )*
81        const RX: &[(u8, usize)] = &[$($(($rx::ID.num, $uart::ID)),*),*];
82        const TX: &[(u8, usize)] = &[$($(($tx::ID.num, $uart::ID)),*),*];
83        const CTS: &[(u8, usize)] = &[$($(($cts::ID.num, $uart::ID)),*),*];
84        const RTS: &[(u8, usize)] = &[$($(($rts::ID.num, $uart::ID)),*),*];
85    };
86}
87
88impl_valid_uart!(
89    UART0: {
90        tx: [Gpio0, Gpio12, Gpio16, Gpio28],
91        rx: [Gpio1, Gpio13, Gpio17, Gpio29],
92        cts: [Gpio2, Gpio14, Gpio18],
93        rts: [Gpio3, Gpio15, Gpio19],
94    },
95    UART1: {
96        tx: [Gpio4, Gpio8, Gpio20, Gpio24],
97        rx: [Gpio5, Gpio9, Gpio21, Gpio25],
98        cts: [Gpio6, Gpio10, Gpio22, Gpio26],
99        rts: [Gpio7, Gpio11, Gpio23, Gpio27],
100    }
101);
102
103/// Declares a valid UART pinout.
104pub trait ValidUartPinout<U: UartDevice>: Sealed {
105    #[allow(missing_docs)]
106    type Rx: ValidOptionRx<U>;
107    #[allow(missing_docs)]
108    type Tx: ValidOptionTx<U>;
109    #[allow(missing_docs)]
110    type Cts: ValidOptionCts<U>;
111    #[allow(missing_docs)]
112    type Rts: ValidOptionRts<U>;
113}
114
115impl<Uart, Tx, Rx> ValidUartPinout<Uart> for (Tx, Rx)
116where
117    Uart: UartDevice,
118    Tx: ValidPinTx<Uart>,
119    Rx: ValidPinRx<Uart>,
120{
121    type Tx = OptionTSome<Tx>;
122    type Rx = OptionTSome<Rx>;
123    type Cts = OptionTNone;
124    type Rts = OptionTNone;
125}
126
127impl<Uart, Tx, Rx, Cts, Rts> ValidUartPinout<Uart> for (Tx, Rx, Cts, Rts)
128where
129    Uart: UartDevice,
130    Tx: ValidPinTx<Uart>,
131    Rx: ValidPinRx<Uart>,
132    Cts: ValidPinCts<Uart>,
133    Rts: ValidPinRts<Uart>,
134{
135    type Rx = OptionTSome<Rx>;
136    type Tx = OptionTSome<Tx>;
137    type Cts = OptionTSome<Cts>;
138    type Rts = OptionTSome<Rts>;
139}
140
141/// Customizable Uart pinout, allowing you to set the pins individually.
142///
143/// The following pins are valid UART pins:
144///
145/// |UART |     TX      |     RX      |    CTS      |    RTS      |
146/// |-----|-------------|-------------|-------------|-------------|
147/// |UART0|0, 12, 16, 28|1, 13, 17, 29|2, 14, 18    |3, 15, 19    |
148/// |UART1|4, 8, 20, 24 |5, 9, 21, 25 |6, 10, 22, 26|7, 11, 23, 27|
149///
150/// Every field can be set to [`OptionTNone`] to not configure them.
151///
152/// Note that you can also use tuples `(RX, TX)` or `(RX, TX, CTS, RTS)` instead of this type.
153///
154/// This struct can either be filled manually or with a builder pattern:
155///
156/// ```no_run
157/// # use rp2040_hal::uart::{Pins, ValidUartPinout};
158/// # use rp2040_hal::pac::UART0;
159/// # let gpio_pins: rp2040_hal::gpio::Pins = unsafe { core::mem::zeroed() };
160/// let pins = Pins::default()
161///     .tx(gpio_pins.gpio0.into_function())
162///     .rx(gpio_pins.gpio1.into_function());
163///
164/// fn assert_is_valid_uart0<T: ValidUartPinout<UART0>>(_: T) {}
165///
166/// assert_is_valid_uart0(pins);
167/// ```
168pub struct Pins<Tx, Rx, Cts, Rts> {
169    #[allow(missing_docs)]
170    pub tx: Tx,
171    #[allow(missing_docs)]
172    pub rx: Rx,
173    #[allow(missing_docs)]
174    pub cts: Cts,
175    #[allow(missing_docs)]
176    pub rts: Rts,
177}
178
179impl Default for Pins<OptionTNone, OptionTNone, OptionTNone, OptionTNone> {
180    fn default() -> Self {
181        Self {
182            tx: OptionTNone,
183            rx: OptionTNone,
184            rts: OptionTNone,
185            cts: OptionTNone,
186        }
187    }
188}
189
190impl<Tx, Rx, Cts, Rts> Pins<Tx, Rx, Cts, Rts> {
191    /// Set the TX pin
192    pub fn tx<NewTx>(self, tx: NewTx) -> Pins<OptionTSome<NewTx>, Rx, Cts, Rts> {
193        Pins {
194            tx: OptionTSome(tx),
195            rx: self.rx,
196            rts: self.rts,
197            cts: self.cts,
198        }
199    }
200    /// Set the RX pin
201    pub fn rx<NewRx>(self, rx: NewRx) -> Pins<Tx, OptionTSome<NewRx>, Cts, Rts> {
202        Pins {
203            tx: self.tx,
204            rx: OptionTSome(rx),
205            rts: self.rts,
206            cts: self.cts,
207        }
208    }
209    /// Set the CTS pin
210    pub fn cts<NewCts>(self, cts: NewCts) -> Pins<Tx, Rx, OptionTSome<NewCts>, Rts> {
211        Pins {
212            tx: self.tx,
213            rx: self.rx,
214            rts: self.rts,
215            cts: OptionTSome(cts),
216        }
217    }
218    /// Set the RTS pin
219    pub fn rts<NewRts>(self, rts: NewRts) -> Pins<Tx, Rx, Cts, OptionTSome<NewRts>> {
220        Pins {
221            tx: self.tx,
222            rx: self.rx,
223            rts: OptionTSome(rts),
224            cts: self.cts,
225        }
226    }
227}
228
229impl<Tx, Rx, Cts, Rts> Sealed for Pins<Tx, Rx, Cts, Rts> {}
230impl<Uart, Tx, Rx, Cts, Rts> ValidUartPinout<Uart> for Pins<Tx, Rx, Cts, Rts>
231where
232    Uart: UartDevice,
233    Tx: ValidOptionTx<Uart>,
234    Rx: ValidOptionRx<Uart>,
235    Cts: ValidOptionCts<Uart>,
236    Rts: ValidOptionRts<Uart>,
237{
238    type Rx = Rx;
239    type Tx = Tx;
240    type Cts = Cts;
241    type Rts = Rts;
242}