1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//! Mock types that implement the `embeddded-hal` traits without using
//! any real hardware.
//!
//! They're used for writing example code that will run on non-embedded targets.
//!
//! Based on the [stm32f103xx_hal](https://github.com/japaric/stm32f103xx-hal)
//! implementation by Jorge Aparicio.

use core::marker::PhantomData;

/// The internal state of a mock input or output pin.
#[derive(Debug)]
enum State {
    High,
    Low,
    Float,
}

/// Input mode marker
#[derive(Debug)]
pub struct Input<MODE> {
    _mode: PhantomData<MODE>,
}

/// Floating input marker
#[derive(Debug)]
pub struct Floating;

/// Pulled up input marker
#[derive(Debug)]
pub struct PullUp;

/// Output mode marker
#[derive(Debug)]
pub struct Output<MODE> {
    _mode: PhantomData<MODE>,
}

/// Push/pull output marker
#[derive(Debug)]
pub struct PushPull;

/// Open drain output marker
#[derive(Debug)]
pub struct OpenDrain;

/// Extension trait to split a mock GPIO peripheral into independent pins
pub trait GpioExt {
    /// The type to split the GPIO into
    type Parts;

    /// Split the GPIO block into independent pins and registers
    fn split() -> Self::Parts;
}

/// Create a whole module around the given mock GPIO port struct. Define structs
/// for its pins and impl useful things.
macro_rules! gpio {
    ($PORT:ident, $port:ident,  [$( ($Pin:ident, $pin:ident, $default_mode:ty) ),+ $(,)* ]) => {
        /// A module containing a mock port of GPIO pins.
        pub mod $port {
            use super::{State, Input,Output, Floating, PushPull, OpenDrain, GpioExt, PullUp, $PORT};
            use core::marker::PhantomData;
            use embedded_hal::digital::v2::{InputPin, OutputPin};

            /// The pins of a mock GPIO port
            #[derive(Debug)]
            pub struct Parts {
                $(
                    #[allow(missing_docs)]
                    pub $pin: $Pin<$default_mode>,
                )+
            }

            impl GpioExt for $PORT {
                type Parts = Parts;

                fn split() -> Parts {
                    Self::Parts {
                        $(
                            $pin: $Pin::default(),
                        )+
                    }
                }
            }

            $(
                /// A mock GPIO pin in a particular mode.
                #[derive(Debug)]
                pub struct $Pin<MODE> {
                    state: State,
                    _mode: PhantomData<MODE>,
                }


                impl Default for $Pin<Input<Floating>> {
                    fn default() -> Self {
                        Self {
                            state: State::Float,
                            _mode: PhantomData,
                        }
                    }
                }

                impl Default for $Pin<Input<PullUp>> {
                    fn default() -> Self {
                        Self {
                            state: State::High,
                            _mode: PhantomData,
                        }
                    }
                }

                impl Default for $Pin<Output<PushPull>> {
                    fn default() -> Self {
                        Self {
                            // TODO is default state actually low?
                            state: State::Low,
                            _mode: PhantomData,
                        }
                    }
                }

                impl Default for $Pin<Output<OpenDrain>> {
                    fn default() -> Self {
                        Self {
                            state: State::Float,
                            _mode: PhantomData,
                        }
                    }
                }

                impl<MODE> $Pin<MODE> {
                    /// Change the mode of this mock pin to an output with low and high states.
                    pub fn into_push_pull_output(self) -> $Pin<Output<PushPull>> {
                        $Pin::default()
                    }

                    /// Change the mode of this mock pin to an output with low and floating states.
                    pub fn into_open_drain_output(self) -> $Pin<Output<OpenDrain>> {
                        $Pin::default()
                    }

                    /// Change the mode of this mock pin to a floating input.
                    pub fn into_floating_input(self) -> $Pin<Input<Floating>> {
                        $Pin::default()
                    }

                    /// Change the mode of this mock pin to an input with a pullup resistor.
                    pub fn into_pull_up_input(self) -> $Pin<Input<PullUp>> {
                        $Pin::default()
                    }
                }

                impl OutputPin for $Pin<Output<PushPull>> {
                    type Error = core::convert::Infallible;
                    /// Drive the mock pin high.
                    fn set_high(&mut self) -> Result<(), Self::Error> {
                        Ok(self.state = State::High)
                    }
                    /// Drive the mock pin low.
                    fn set_low(&mut self) -> Result<(), Self::Error> {
                        Ok(self.state = State::Low)
                    }
                }

                impl OutputPin for $Pin<Output<OpenDrain>> {
                    type Error = core::convert::Infallible;
                    /// Leave the mock pin floating.
                    fn set_high(&mut self) -> Result<(), Self::Error> {
                        Ok(self.state = State::Float)
                    }

                    /// Drive the mock pin low.
                    fn set_low(&mut self) -> Result<(), Self::Error> {
                        Ok(self.state = State::Low)
                    }
                }

                impl<MODE> InputPin for $Pin<Input<MODE>> {
                    type Error = core::convert::Infallible;
                    /// Is the mock input pin high? Panic if it's floating.
                    fn is_high(&self) -> Result<bool,Self::Error> {
                        Ok(!self.is_low()?)
                    }
                    /// Is the mock input pin low? Panic if it's floating.
                    fn is_low(&self) -> Result<bool, Self::Error> {
                        match self.state {
                            State::Low => Ok(true),
                            State::High => Ok(false),
                            State::Float => {
                                panic!("Tried to read a floating input, value is non-deterministic!")
                            }
                        }
                    }
                }
            )+
        }
    };
}

/// A struct representing a mock port of GPIO pins.
#[derive(Debug)]
pub struct GPIOA;

gpio!( GPIOA, gpioa, [
    (PA0, pa0, Input<Floating>),
    (PA1, pa1, Input<Floating>),
    (PA2, pa2, Input<Floating>),
    (PA3, pa3, Input<Floating>),
    (PA4, pa4, Input<Floating>),
    (PA5, pa5, Input<Floating>),
    (PA6, pa6, Input<Floating>),
    (PA7, pa7, Input<Floating>),
    (PA8, pa8, Input<Floating>),
    (PA9, pa9, Input<Floating>),
    (PA10, pa10, Input<Floating>),
    (PA11, pa11, Input<Floating>),
    (PA12, pa12, Input<Floating>),
    (PA13, pa13, Input<Floating>),
    (PA14, pa14, Input<Floating>),
    (PA15, pa15, Input<Floating>),
]);