1 | //! Digital I/O |
2 | //! |
3 | //! Version 2 / fallible traits. Infallible implementations should set Error to `!`. |
4 | |
5 | use core::{convert::From, ops::Not}; |
6 | |
7 | /// Digital output pin state |
8 | /// |
9 | /// Conversion from `bool` and logical negation are also implemented |
10 | /// for this type. |
11 | /// ```rust |
12 | /// # use embedded_hal::digital::v2::PinState; |
13 | /// let state = PinState::from(false); |
14 | /// assert_eq!(state, PinState::Low); |
15 | /// assert_eq!(!state, PinState::High); |
16 | /// ``` |
17 | #[derive (Debug, PartialEq, Eq, Clone, Copy)] |
18 | pub enum PinState { |
19 | /// Low pin state |
20 | Low, |
21 | /// High pin state |
22 | High, |
23 | } |
24 | |
25 | impl From<bool> for PinState { |
26 | fn from(value: bool) -> Self { |
27 | match value { |
28 | false => PinState::Low, |
29 | true => PinState::High, |
30 | } |
31 | } |
32 | } |
33 | |
34 | impl Not for PinState { |
35 | type Output = PinState; |
36 | |
37 | fn not(self) -> Self::Output { |
38 | match self { |
39 | PinState::High => PinState::Low, |
40 | PinState::Low => PinState::High, |
41 | } |
42 | } |
43 | } |
44 | |
45 | /// Single digital push-pull output pin |
46 | pub trait OutputPin { |
47 | /// Error type |
48 | type Error; |
49 | |
50 | /// Drives the pin low |
51 | /// |
52 | /// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external |
53 | /// electrical sources |
54 | fn set_low(&mut self) -> Result<(), Self::Error>; |
55 | |
56 | /// Drives the pin high |
57 | /// |
58 | /// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external |
59 | /// electrical sources |
60 | fn set_high(&mut self) -> Result<(), Self::Error>; |
61 | |
62 | /// Drives the pin high or low depending on the provided value |
63 | /// |
64 | /// *NOTE* the actual electrical state of the pin may not actually be high or low, e.g. due to external |
65 | /// electrical sources |
66 | fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> { |
67 | match state { |
68 | PinState::Low => self.set_low(), |
69 | PinState::High => self.set_high(), |
70 | } |
71 | } |
72 | } |
73 | |
74 | /// Push-pull output pin that can read its output state |
75 | /// |
76 | /// *This trait is available if embedded-hal is built with the `"unproven"` feature.* |
77 | #[cfg (feature = "unproven" )] |
78 | pub trait StatefulOutputPin: OutputPin { |
79 | /// Is the pin in drive high mode? |
80 | /// |
81 | /// *NOTE* this does *not* read the electrical state of the pin |
82 | fn is_set_high(&self) -> Result<bool, Self::Error>; |
83 | |
84 | /// Is the pin in drive low mode? |
85 | /// |
86 | /// *NOTE* this does *not* read the electrical state of the pin |
87 | fn is_set_low(&self) -> Result<bool, Self::Error>; |
88 | } |
89 | |
90 | /// Output pin that can be toggled |
91 | /// |
92 | /// *This trait is available if embedded-hal is built with the `"unproven"` feature.* |
93 | /// |
94 | /// See [toggleable](toggleable) to use a software implementation if |
95 | /// both [OutputPin](trait.OutputPin.html) and |
96 | /// [StatefulOutputPin](trait.StatefulOutputPin.html) are |
97 | /// implemented. Otherwise, implement this using hardware mechanisms. |
98 | #[cfg (feature = "unproven" )] |
99 | pub trait ToggleableOutputPin { |
100 | /// Error type |
101 | type Error; |
102 | |
103 | /// Toggle pin output. |
104 | fn toggle(&mut self) -> Result<(), Self::Error>; |
105 | } |
106 | |
107 | /// If you can read **and** write the output state, a pin is |
108 | /// toggleable by software. |
109 | /// |
110 | /// ``` |
111 | /// use embedded_hal::digital::v2::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; |
112 | /// use embedded_hal::digital::v2::toggleable; |
113 | /// |
114 | /// /// A virtual output pin that exists purely in software |
115 | /// struct MyPin { |
116 | /// state: bool |
117 | /// } |
118 | /// |
119 | /// impl OutputPin for MyPin { |
120 | /// type Error = void::Void; |
121 | /// |
122 | /// fn set_low(&mut self) -> Result<(), Self::Error> { |
123 | /// self.state = false; |
124 | /// Ok(()) |
125 | /// } |
126 | /// fn set_high(&mut self) -> Result<(), Self::Error> { |
127 | /// self.state = true; |
128 | /// Ok(()) |
129 | /// } |
130 | /// } |
131 | /// |
132 | /// impl StatefulOutputPin for MyPin { |
133 | /// fn is_set_low(&self) -> Result<bool, Self::Error> { |
134 | /// Ok(!self.state) |
135 | /// } |
136 | /// fn is_set_high(&self) -> Result<bool, Self::Error> { |
137 | /// Ok(self.state) |
138 | /// } |
139 | /// } |
140 | /// |
141 | /// /// Opt-in to the software implementation. |
142 | /// impl toggleable::Default for MyPin {} |
143 | /// |
144 | /// let mut pin = MyPin { state: false }; |
145 | /// pin.toggle().unwrap(); |
146 | /// assert!(pin.is_set_high().unwrap()); |
147 | /// pin.toggle().unwrap(); |
148 | /// assert!(pin.is_set_low().unwrap()); |
149 | /// ``` |
150 | #[cfg (feature = "unproven" )] |
151 | pub mod toggleable { |
152 | use super::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; |
153 | |
154 | /// Software-driven `toggle()` implementation. |
155 | /// |
156 | /// *This trait is available if embedded-hal is built with the `"unproven"` feature.* |
157 | pub trait Default: OutputPin + StatefulOutputPin {} |
158 | |
159 | impl<P> ToggleableOutputPin for P |
160 | where |
161 | P: Default, |
162 | { |
163 | type Error = P::Error; |
164 | |
165 | /// Toggle pin output |
166 | fn toggle(&mut self) -> Result<(), Self::Error> { |
167 | if self.is_set_low()? { |
168 | self.set_high() |
169 | } else { |
170 | self.set_low() |
171 | } |
172 | } |
173 | } |
174 | } |
175 | |
176 | /// Single digital input pin |
177 | /// |
178 | /// *This trait is available if embedded-hal is built with the `"unproven"` feature.* |
179 | #[cfg (feature = "unproven" )] |
180 | pub trait InputPin { |
181 | /// Error type |
182 | type Error; |
183 | |
184 | /// Is the input pin high? |
185 | fn is_high(&self) -> Result<bool, Self::Error>; |
186 | |
187 | /// Is the input pin low? |
188 | fn is_low(&self) -> Result<bool, Self::Error>; |
189 | } |
190 | |
191 | /// Single pin that can switch from input to output mode, and vice-versa. |
192 | /// |
193 | /// Example use (assumes the `Error` type is the same for the `IoPin`, |
194 | /// `InputPin`, and `OutputPin`): |
195 | /// |
196 | /// *This trait is available if embedded-hal is built with the `"unproven"` feature.* |
197 | #[cfg (feature = "unproven" )] |
198 | pub trait IoPin<TInput, TOutput> |
199 | where |
200 | TInput: InputPin + IoPin<TInput, TOutput>, |
201 | TOutput: OutputPin + IoPin<TInput, TOutput>, |
202 | { |
203 | /// Error type. |
204 | type Error; |
205 | |
206 | /// Tries to convert this pin to input mode. |
207 | /// |
208 | /// If the pin is already in input mode, this method should succeed. |
209 | fn into_input_pin(self) -> Result<TInput, Self::Error>; |
210 | |
211 | /// Tries to convert this pin to output mode with the given initial state. |
212 | /// |
213 | /// If the pin is already in the requested state, this method should |
214 | /// succeed. |
215 | fn into_output_pin(self, state: PinState) -> Result<TOutput, Self::Error>; |
216 | } |
217 | |