embedded_hal/digital/v2.rs
1//! Digital I/O
2//!
3//! Version 2 / fallible traits. Infallible implementations should set Error to `!`.
4
5use 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)]
18pub enum PinState {
19 /// Low pin state
20 Low,
21 /// High pin state
22 High,
23}
24
25impl 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
34impl 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
46pub 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")]
78pub 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")]
99pub 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")]
151pub 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")]
180pub 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")]
198pub trait IoPin<TInput, TOutput>
199where
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}