1 | //! Digital I/O. |
2 | |
3 | use core::{convert::From, ops::Not}; |
4 | |
5 | #[cfg (feature = "defmt-03" )] |
6 | use crate::defmt; |
7 | |
8 | /// Error. |
9 | pub trait Error: core::fmt::Debug { |
10 | /// Convert error to a generic error kind |
11 | /// |
12 | /// By using this method, errors freely defined by HAL implementations |
13 | /// can be converted to a set of generic errors upon which generic |
14 | /// code can act. |
15 | fn kind(&self) -> ErrorKind; |
16 | } |
17 | |
18 | impl Error for core::convert::Infallible { |
19 | fn kind(&self) -> ErrorKind { |
20 | match *self {} |
21 | } |
22 | } |
23 | |
24 | /// Error kind. |
25 | /// |
26 | /// This represents a common set of operation errors. HAL implementations are |
27 | /// free to define more specific or additional error types. However, by providing |
28 | /// a mapping to these common errors, generic code can still react to them. |
29 | #[derive (Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] |
30 | #[cfg_attr (feature = "defmt-03" , derive(defmt::Format))] |
31 | #[non_exhaustive ] |
32 | pub enum ErrorKind { |
33 | /// A different error occurred. The original error may contain more information. |
34 | Other, |
35 | } |
36 | |
37 | impl Error for ErrorKind { |
38 | #[inline ] |
39 | fn kind(&self) -> ErrorKind { |
40 | *self |
41 | } |
42 | } |
43 | |
44 | impl core::fmt::Display for ErrorKind { |
45 | #[inline ] |
46 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
47 | match self { |
48 | Self::Other => write!( |
49 | f, |
50 | "A different error occurred. The original error may contain more information" |
51 | ), |
52 | } |
53 | } |
54 | } |
55 | |
56 | /// Error type trait. |
57 | /// |
58 | /// This just defines the error type, to be used by the other traits. |
59 | pub trait ErrorType { |
60 | /// Error type |
61 | type Error: Error; |
62 | } |
63 | |
64 | impl<T: ErrorType + ?Sized> ErrorType for &T { |
65 | type Error = T::Error; |
66 | } |
67 | |
68 | impl<T: ErrorType + ?Sized> ErrorType for &mut T { |
69 | type Error = T::Error; |
70 | } |
71 | |
72 | /// Digital output pin state. |
73 | /// |
74 | /// Conversion from `bool` and logical negation are also implemented |
75 | /// for this type. |
76 | /// ```rust |
77 | /// # use embedded_hal::digital::PinState; |
78 | /// let state = PinState::from(false); |
79 | /// assert_eq!(state, PinState::Low); |
80 | /// assert_eq!(!state, PinState::High); |
81 | /// ``` |
82 | #[derive (Debug, PartialEq, Eq, Clone, Copy)] |
83 | #[cfg_attr (feature = "defmt-03" , derive(defmt::Format))] |
84 | pub enum PinState { |
85 | /// Low pin state. |
86 | Low, |
87 | /// High pin state. |
88 | High, |
89 | } |
90 | |
91 | impl From<bool> for PinState { |
92 | #[inline ] |
93 | fn from(value: bool) -> Self { |
94 | match value { |
95 | false => PinState::Low, |
96 | true => PinState::High, |
97 | } |
98 | } |
99 | } |
100 | |
101 | impl Not for PinState { |
102 | type Output = PinState; |
103 | |
104 | #[inline ] |
105 | fn not(self) -> Self::Output { |
106 | match self { |
107 | PinState::High => PinState::Low, |
108 | PinState::Low => PinState::High, |
109 | } |
110 | } |
111 | } |
112 | |
113 | impl From<PinState> for bool { |
114 | #[inline ] |
115 | fn from(value: PinState) -> bool { |
116 | match value { |
117 | PinState::Low => false, |
118 | PinState::High => true, |
119 | } |
120 | } |
121 | } |
122 | |
123 | /// Single digital push-pull output pin. |
124 | pub trait OutputPin: ErrorType { |
125 | /// Drives the pin low. |
126 | /// |
127 | /// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external |
128 | /// electrical sources. |
129 | fn set_low(&mut self) -> Result<(), Self::Error>; |
130 | |
131 | /// Drives the pin high. |
132 | /// |
133 | /// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external |
134 | /// electrical sources. |
135 | fn set_high(&mut self) -> Result<(), Self::Error>; |
136 | |
137 | /// Drives the pin high or low depending on the provided value. |
138 | /// |
139 | /// *NOTE* the actual electrical state of the pin may not actually be high or low, e.g. due to external |
140 | /// electrical sources. |
141 | #[inline ] |
142 | fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> { |
143 | match state { |
144 | PinState::Low => self.set_low(), |
145 | PinState::High => self.set_high(), |
146 | } |
147 | } |
148 | } |
149 | |
150 | impl<T: OutputPin + ?Sized> OutputPin for &mut T { |
151 | #[inline ] |
152 | fn set_low(&mut self) -> Result<(), Self::Error> { |
153 | T::set_low(self) |
154 | } |
155 | |
156 | #[inline ] |
157 | fn set_high(&mut self) -> Result<(), Self::Error> { |
158 | T::set_high(self) |
159 | } |
160 | |
161 | #[inline ] |
162 | fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> { |
163 | T::set_state(self, state) |
164 | } |
165 | } |
166 | |
167 | /// Push-pull output pin that can read its output state. |
168 | pub trait StatefulOutputPin: OutputPin { |
169 | /// Is the pin in drive high mode? |
170 | /// |
171 | /// *NOTE* this does *not* read the electrical state of the pin. |
172 | fn is_set_high(&mut self) -> Result<bool, Self::Error>; |
173 | |
174 | /// Is the pin in drive low mode? |
175 | /// |
176 | /// *NOTE* this does *not* read the electrical state of the pin. |
177 | fn is_set_low(&mut self) -> Result<bool, Self::Error>; |
178 | |
179 | /// Toggle pin output. |
180 | fn toggle(&mut self) -> Result<(), Self::Error> { |
181 | let was_low: bool = self.is_set_low()?; |
182 | self.set_state(PinState::from(was_low)) |
183 | } |
184 | } |
185 | |
186 | impl<T: StatefulOutputPin + ?Sized> StatefulOutputPin for &mut T { |
187 | #[inline ] |
188 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { |
189 | T::is_set_high(self) |
190 | } |
191 | |
192 | #[inline ] |
193 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { |
194 | T::is_set_low(self) |
195 | } |
196 | |
197 | #[inline ] |
198 | fn toggle(&mut self) -> Result<(), Self::Error> { |
199 | T::toggle(self) |
200 | } |
201 | } |
202 | |
203 | /// Single digital input pin. |
204 | pub trait InputPin: ErrorType { |
205 | /// Is the input pin high? |
206 | fn is_high(&mut self) -> Result<bool, Self::Error>; |
207 | |
208 | /// Is the input pin low? |
209 | fn is_low(&mut self) -> Result<bool, Self::Error>; |
210 | } |
211 | |
212 | impl<T: InputPin + ?Sized> InputPin for &mut T { |
213 | #[inline ] |
214 | fn is_high(&mut self) -> Result<bool, Self::Error> { |
215 | T::is_high(self) |
216 | } |
217 | |
218 | #[inline ] |
219 | fn is_low(&mut self) -> Result<bool, Self::Error> { |
220 | T::is_low(self) |
221 | } |
222 | } |
223 | |