1use core::marker::PhantomData;
4
5pub trait GpioExt {
7    type Parts;
9
10    fn split(self) -> Self::Parts;
12}
13
14pub struct Input<MODE> {
16    _mode: PhantomData<MODE>,
17}
18
19pub struct Analog;
21pub struct Floating;
23pub struct PullDown;
25pub struct PullUp;
27
28pub struct Output<MODE> {
30    _mode: PhantomData<MODE>,
31}
32
33pub struct PushPull;
35pub struct OpenDrain;
37
38macro_rules! port {
39    ($PORTX:ident, $portx:ident, [
40        $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty $(, $has_ansel:expr)?),)+
41    ]) => {
42        pub mod $portx {
44            use core::marker::PhantomData;
45            use core::convert::Infallible;
46
47            use embedded_hal_0_2::digital::v2 as eh02;
48            use embedded_hal::digital as eh;
49            use crate::pac::$PORTX;
50
51            #[allow(unused_imports)]
52            use super::Analog;
53            use super::{
54                Floating, GpioExt, Input, OpenDrain, Output,
55                PullDown, PullUp, PushPull,
56            };
57
58            pub struct Parts {
60                $(
61                    pub $pxi: $PXi<$MODE>,
63                )+
64            }
65
66            impl GpioExt for $PORTX {
67                type Parts = Parts;
68
69                fn split(self) -> Parts {
70                    Parts {
71                        $(
72                            $pxi: $PXi { _mode: PhantomData },
73                        )+
74                    }
75                }
76            }
77
78            $(
79                pub struct $PXi<MODE> {
81                    _mode: PhantomData<MODE>,
82                }
83
84                impl<MODE> $PXi<MODE> {
85                    pub fn into_floating_input(
87                        self,
88                    ) -> $PXi<Input<Floating>> {
89                        unsafe {
90                            $(
91                                _ = $has_ansel; (*$PORTX::ptr()).anselclr.write(|w| w.bits(1 << $i));
93                            )?
94                            (*$PORTX::ptr()).trisset.write(|w| w.bits(1 << $i));
95                            (*$PORTX::ptr()).cnpuclr.write(|w| w.bits(1 << $i));
96                            (*$PORTX::ptr()).cnpdclr.write(|w| w.bits(1 << $i));
97                        }
98                        $PXi { _mode: PhantomData }
99                    }
100
101                    pub fn into_pull_down_input(
103                        self,
104                    ) -> $PXi<Input<PullDown>> {
105                        unsafe {
106                            $(
107                                _ = $has_ansel; (*$PORTX::ptr()).anselclr.write(|w| w.bits(1 << $i));
109                            )?
110                            (*$PORTX::ptr()).trisset.write(|w| w.bits(1 << $i));
111                            (*$PORTX::ptr()).cnpuclr.write(|w| w.bits(1 << $i));
112                            (*$PORTX::ptr()).cnpdset.write(|w| w.bits(1 << $i));
113                        }
114                        $PXi { _mode: PhantomData }
115                    }
116
117                    pub fn into_pull_up_input(
119                        self,
120                    ) -> $PXi<Input<PullUp>> {
121                        unsafe {
122                            $(
123                                _ = $has_ansel; (*$PORTX::ptr()).anselclr.write(|w| w.bits(1 << $i));
125                            )?
126                            (*$PORTX::ptr()).trisset.write(|w| w.bits(1 << $i));
127                            (*$PORTX::ptr()).cnpuset.write(|w| w.bits(1 << $i));
128                            (*$PORTX::ptr()).cnpdclr.write(|w| w.bits(1 << $i));
129                        }
130                        $PXi { _mode: PhantomData }
131                    }
132
133                    pub fn into_open_drain_output(
135                        self,
136                    ) -> $PXi<Output<OpenDrain>> {
137                        unsafe {
138                            $(
139                                _ = $has_ansel; (*$PORTX::ptr()).anselclr.write(|w| w.bits(1 << $i));
141                            )?
142                            (*$PORTX::ptr()).trisclr.write(|w| w.bits(1 << $i));
143                            (*$PORTX::ptr()).odcset.write(|w|  w.bits(1 << $i));
144                            (*$PORTX::ptr()).cnpuclr.write(|w| w.bits(1 << $i));
145                            (*$PORTX::ptr()).cnpdclr.write(|w| w.bits(1 << $i));
146                        }
147                        $PXi { _mode: PhantomData }
148                    }
149
150                    pub fn into_push_pull_output(
152                        self,
153                    ) -> $PXi<Output<PushPull>> {
154                        unsafe {
155                            $(
156                                _ = $has_ansel; (*$PORTX::ptr()).anselclr.write(|w| w.bits(1 << $i));
158                            )?
159                            (*$PORTX::ptr()).trisclr.write(|w| w.bits(1 << $i));
160                            (*$PORTX::ptr()).odcclr.write(|w| w.bits(1 << $i));
161                            (*$PORTX::ptr()).cnpuclr.write(|w| w.bits(1 << $i));
162                            (*$PORTX::ptr()).cnpdclr.write(|w| w.bits(1 << $i));
163                        }
164                        $PXi { _mode: PhantomData }
165                    }
166
167                    $(
168                        pub fn into_analog_input(
170                            self,
171                        ) -> $PXi<Input<Analog>> {
172                            _ = $has_ansel; unsafe {
174                                (*$PORTX::ptr()).anselset.write(|w| w.bits(1 << $i));
175                                (*$PORTX::ptr()).trisset.write(|w| w.bits(1 << $i));
176                                (*$PORTX::ptr()).cnpuclr.write(|w| w.bits(1 << $i));
177                                (*$PORTX::ptr()).cnpdclr.write(|w| w.bits(1 << $i));
178                            }
179                            $PXi { _mode: PhantomData }
180                        }
181                    )?
182                }
183
184                impl $PXi<Output<OpenDrain>> {
185                    pub fn internal_pull_up(&mut self, on: bool) {
187                        unsafe {
188                            if on {
189                                (*$PORTX::ptr()).cnpuset.write(|w| w.bits(1 << $i));
190                            } else {
191                                (*$PORTX::ptr()).cnpuclr.write(|w| w.bits(1 << $i));
192                            }
193                        }
194                    }
195                }
196
197                impl<MODE> eh02::OutputPin for $PXi<Output<MODE>> {
198
199                    type Error = ();
200
201                    fn set_high(&mut self) -> Result<(), Self::Error>  {
202                         unsafe { (*$PORTX::ptr()).latset.write(|w| w.bits(1 << $i)) }
204                        Ok(())
205                    }
206
207                    fn set_low(&mut self) ->  Result<(), Self::Error>{
208                        unsafe { (*$PORTX::ptr()).latclr.write(|w| w.bits(1 << $i)) }
210                        Ok(())
211                    }
212                }
213
214                impl<MODE> eh02::StatefulOutputPin for $PXi<Output<MODE>> {
215
216                    fn is_set_high(&self) -> Result<bool, Self::Error> {
217                        Ok(unsafe { (*$PORTX::ptr()).lat.read().bits() & (1 << $i) != 0 })
218                    }
219
220                    fn is_set_low(&self) -> Result<bool, Self::Error> {
221                        Ok(unsafe { (*$PORTX::ptr()).lat.read().bits() & (1 << $i) == 0 })
222                    }
223                }
224
225                impl<MODE> eh02::ToggleableOutputPin for $PXi<Output<MODE>> {
226
227                    type Error = ();
228
229                    fn toggle(&mut self) -> Result<(), Self::Error> {
230                        unsafe { (*$PORTX::ptr()).latinv.write(|w| w.bits(1 << $i)) };
231                        Ok(())
232                    }
233                }
234
235                impl<MODE> eh02::InputPin for $PXi<Input<MODE>> {
236
237                    type Error = ();
238
239                    fn is_high(&self) -> Result<bool, Self::Error> {
240                        Ok(unsafe { (*$PORTX::ptr()).port.read().bits() & (1 << $i) != 0 })
241                    }
242
243                    fn is_low(&self) -> Result<bool, Self::Error> {
244                        Ok(unsafe { (*$PORTX::ptr()).port.read().bits() & (1 << $i) == 0 })
245                    }
246                }
247
248                impl eh02::InputPin for $PXi<Output<OpenDrain>> {
249
250                    type Error = ();
251
252                    fn is_high(&self) -> Result<bool, Self::Error> {
253                        Ok(unsafe { (*$PORTX::ptr()).port.read().bits() & (1 << $i) != 0 })
254                    }
255
256                    fn is_low(&self) -> Result<bool, Self::Error> {
257                        Ok(unsafe { (*$PORTX::ptr()).port.read().bits() & (1 << $i) == 0 })
258                    }
259                }
260
261                impl<MODE> eh::ErrorType for $PXi<MODE> {
262                    type Error = Infallible;
263                }
264
265                impl<MODE> eh::InputPin for $PXi<Input<MODE>> {
266
267                    fn is_high(&mut self) -> Result<bool, Self::Error> {
268                        Ok(unsafe { (*$PORTX::ptr()).port.read().bits() & (1 << $i) != 0 })
269                    }
270
271                    fn is_low(&mut self) -> Result<bool, Self::Error> {
272                        Ok(unsafe { (*$PORTX::ptr()).port.read().bits() & (1 << $i) == 0 })
273                    }
274                }
275
276                impl eh::InputPin for $PXi<Output<OpenDrain>> {
277
278                    fn is_high(&mut self) -> Result<bool, Self::Error> {
279                        Ok(unsafe { (*$PORTX::ptr()).port.read().bits() & (1 << $i) != 0 })
280                    }
281
282                    fn is_low(&mut self) -> Result<bool, Self::Error> {
283                        Ok(unsafe { (*$PORTX::ptr()).port.read().bits() & (1 << $i) == 0 })
284                    }
285                }
286
287                impl<MODE> eh::OutputPin for $PXi<Output<MODE>> {
288
289                    fn set_low(&mut self) -> Result<(), Self::Error> {
290                        unsafe { (*$PORTX::ptr()).latclr.write(|w| w.bits(1 << $i)) }
291                        Ok(())
292                    }
293
294                    fn set_high(&mut self) -> Result<(), Self::Error> {
295                        unsafe { (*$PORTX::ptr()).latset.write(|w| w.bits(1 << $i)) }
296                        Ok(())
297                    }
298                }
299
300                impl<MODE> eh::StatefulOutputPin for $PXi<Output<MODE>> {
301
302                    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
303                        Ok(unsafe { (*$PORTX::ptr()).lat.read().bits() & (1 << $i) != 0 })
304                    }
305
306                    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
307                        Ok(unsafe { (*$PORTX::ptr()).lat.read().bits() & (1 << $i) == 0 })
308                    }
309
310                    fn toggle(&mut self) -> Result<(), Self::Error> {
311                        unsafe { (*$PORTX::ptr()).latinv.write(|w| w.bits(1 << $i)) };
312                        Ok(())
313                    }
314                }
315            )+
316        }
317    }
318}
319
320include!("gpio_tables.rs");