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}