1use core::marker::PhantomData;
2
3use crate::{
4 gpio::{bank0::*, pin::pin_sealed::TypeLevelPinId, AnyPin, FunctionSpi},
5 pac::{SPI0, SPI1},
6 typelevel::{OptionT, OptionTNone, OptionTSome, Sealed},
7};
8
9use super::SpiDevice;
10
11macro_rules! pin_validation {
12 ($p:ident) => {
13 paste::paste!{
14 #[doc = "Indicates a valid " $p " pin for SPI0 or SPI1"]
15 pub trait [<ValidPinId $p>]<SPI: SpiDevice>: Sealed {}
16
17 #[doc = "Indicates a valid " $p " pin for SPI0 or SPI1"]
18 pub trait [<ValidPin $p>]<SPI: SpiDevice>: Sealed {}
19
20 impl<T, U: SpiDevice> [<ValidPin $p>]<U> for T
21 where
22 T: AnyPin<Function = FunctionSpi>,
23 T::Id: [<ValidPinId $p>]<U>,
24 {
25 }
26
27 #[doc = "A runtime validated " $p " pin for spi."]
28 pub struct [<ValidatedPin $p>]<P, Spi>(P, PhantomData<Spi>);
29 impl<P, SPI: SpiDevice> Sealed for [<ValidatedPin $p>]<P, SPI> {}
30 impl<P, SPI: SpiDevice> [<ValidPin $p>]<SPI> for [<ValidatedPin $p>]<P, SPI> {}
31 impl<P, S> [<ValidatedPin $p>]<P, S>
32 where
33 P: AnyPin<Function = FunctionSpi>,
34 S: SpiDevice,
35 {
36 #[doc = "Will err if the pin cannot be used as a " $p " pin for that Spi."]
39 pub fn validate(p: P, _u: &S) -> Result<Self, P> {
40 if [<$p:upper>].contains(&(p.borrow().id().num, S::ID)) &&
41 p.borrow().id().bank == crate::gpio::DynBankId::Bank0 {
42 Ok(Self(p, PhantomData))
43 } else {
44 Err(p)
45 }
46 }
47 }
48
49 #[doc = "Indicates a valid optional " $p " pin for SPI0 or SPI1"]
50 pub trait [<ValidOption $p>]<U>: OptionT {}
51
52 impl<U: SpiDevice> [<ValidOption $p>]<U> for OptionTNone {}
53 impl<U, T> [<ValidOption $p>]<U> for OptionTSome<T>
54 where
55 U: SpiDevice,
56 T: [<ValidPin $p>]<U>,
57 {
58 }
59 }
60 };
61 ($($p:ident),*) => {
62 $(
63 pin_validation!($p);
64 )*
65 };
66}
67pin_validation!(Tx, Rx, Sck, Cs);
68
69macro_rules! impl_valid_spi {
70 ($($spi:ident: {
71 rx: [$($rx:ident),*],
72 cs: [$($cs:ident),*],
73 sck: [$($sck:ident),*],
74 tx: [$($tx:ident),*],
75 }),*) => {
76 $(
77 $(impl ValidPinIdRx<$spi> for $rx {})*
78 $(impl ValidPinIdTx<$spi> for $tx {})*
79 $(impl ValidPinIdSck<$spi> for $sck {})*
80 $(impl ValidPinIdCs<$spi> for $cs {})*
81 )*
82
83 const RX: &[(u8, usize)] = &[$($(($rx::ID.num, $spi::ID)),*),*];
84 const TX: &[(u8, usize)] = &[$($(($tx::ID.num, $spi::ID)),*),*];
85 const SCK: &[(u8, usize)] = &[$($(($sck::ID.num, $spi::ID)),*),*];
86 const CS: &[(u8, usize)] = &[$($(($cs::ID.num, $spi::ID)),*),*];
87 };
88}
89
90impl_valid_spi!(
91 SPI0: {
92 rx: [Gpio0, Gpio4, Gpio16, Gpio20],
93 cs: [Gpio1, Gpio5, Gpio17, Gpio21],
94 sck: [Gpio2, Gpio6, Gpio18, Gpio22],
95 tx: [Gpio3, Gpio7, Gpio19, Gpio23],
96 },
97 SPI1: {
98 rx: [Gpio8, Gpio12, Gpio24, Gpio28],
99 cs: [Gpio9, Gpio13, Gpio25, Gpio29],
100 sck: [Gpio10, Gpio14, Gpio26],
101 tx: [Gpio11, Gpio15, Gpio27],
102 }
103);
104
105pub trait ValidSpiPinout<U: SpiDevice>: Sealed {
107 #[allow(missing_docs)]
108 type Rx: ValidOptionRx<U>;
109 #[allow(missing_docs)]
110 type Cs: ValidOptionCs<U>;
111 #[allow(missing_docs)]
112 type Sck: ValidOptionSck<U>;
113 #[allow(missing_docs)]
114 type Tx: ValidOptionTx<U>;
115}
116
117impl<Spi, Tx, Sck> ValidSpiPinout<Spi> for (Tx, Sck)
118where
119 Spi: SpiDevice,
120 Tx: ValidPinTx<Spi>,
121 Sck: ValidPinSck<Spi>,
122{
123 type Rx = OptionTNone;
124 type Cs = OptionTNone;
125 type Sck = OptionTSome<Sck>;
126 type Tx = OptionTSome<Tx>;
127}
128
129impl<Spi, Tx, Rx, Sck> ValidSpiPinout<Spi> for (Tx, Rx, Sck)
130where
131 Spi: SpiDevice,
132 Tx: ValidPinTx<Spi>,
133 Sck: ValidPinSck<Spi>,
134 Rx: ValidPinRx<Spi>,
135{
136 type Rx = OptionTSome<Rx>;
137 type Cs = OptionTNone;
138 type Sck = OptionTSome<Sck>;
139 type Tx = OptionTSome<Tx>;
140}
141
142impl<Spi, Tx, Rx, Sck, Cs> ValidSpiPinout<Spi> for (Tx, Rx, Sck, Cs)
143where
144 Spi: SpiDevice,
145 Tx: ValidPinTx<Spi>,
146 Sck: ValidPinSck<Spi>,
147 Rx: ValidPinRx<Spi>,
148 Cs: ValidPinCs<Spi>,
149{
150 type Rx = OptionTSome<Rx>;
151 type Cs = OptionTSome<Cs>;
152 type Sck = OptionTSome<Sck>;
153 type Tx = OptionTSome<Tx>;
154}