Skip to content

Commit ea672e0

Browse files
committed
Add async versions of OutputPin, StatefulOutputPin and InputPin
1 parent 1599b06 commit ea672e0

File tree

1 file changed

+135
-1
lines changed

1 file changed

+135
-1
lines changed

embedded-hal-async/src/digital.rs

+135-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
//! Asynchronous digital I/O.
22
//!
3+
//! The [`OutputPin`], [`StatefulOutputPin`] and [`InputPin`] traits are `async` variants
4+
//! of the [blocking traits](embedded_hal::digital). These traits are useful for when
5+
//! digital I/O may block execution, such as access through an I/O expander or over some
6+
//! other transport.
7+
//!
8+
//! The [`Wait`] trait allows asynchronously waiting for a change in pin level.
9+
//!
310
//! # Example
411
//!
512
//! ```rust
@@ -15,7 +22,134 @@
1522
//! .expect("failed to await input pin")
1623
//! }
1724
//! ```
18-
pub use embedded_hal::digital::{Error, ErrorKind, ErrorType};
25+
//!
26+
//! # For HAL authors
27+
//!
28+
//! If the digital I/O is implemented using memory mapped I/O and acts immediately, then the async traits
29+
//! (except for [`Wait`]) can be implemented by calling the blocking traits and wrapping the result in
30+
//! [`Poll::Ready`](core::task::Poll::Ready).
31+
pub use embedded_hal::digital::{Error, ErrorKind, ErrorType, PinState};
32+
33+
/// Asynchronous single digital push-pull output pin.
34+
pub trait OutputPin: ErrorType {
35+
/// Drives the pin low.
36+
///
37+
/// This returns [`Ready`](core::task::Poll::Ready) when the pin has been driven low.
38+
///
39+
/// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external
40+
/// electrical sources.
41+
async fn set_low(&mut self) -> Result<(), Self::Error>;
42+
43+
/// Drives the pin high.
44+
///
45+
/// This returns [`Ready`](core::task::Poll::Ready) when the pin has been driven high.
46+
///
47+
/// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external
48+
/// electrical sources.
49+
async fn set_high(&mut self) -> Result<(), Self::Error>;
50+
51+
/// Drives the pin high or low depending on the provided value.
52+
///
53+
/// This returns [`Ready`](core::task::Poll::Ready) when the pin has been driven to the provided state.
54+
///
55+
/// *NOTE* the actual electrical state of the pin may not actually be high or low, e.g. due to external
56+
/// electrical sources.
57+
#[inline]
58+
async fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> {
59+
match state {
60+
PinState::Low => self.set_low().await,
61+
PinState::High => self.set_high().await,
62+
}
63+
}
64+
}
65+
66+
impl<T: OutputPin + ?Sized> OutputPin for &mut T {
67+
#[inline]
68+
async fn set_low(&mut self) -> Result<(), Self::Error> {
69+
T::set_low(self).await
70+
}
71+
72+
#[inline]
73+
async fn set_high(&mut self) -> Result<(), Self::Error> {
74+
T::set_high(self).await
75+
}
76+
77+
#[inline]
78+
async fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> {
79+
T::set_state(self, state).await
80+
}
81+
}
82+
83+
/// Asynchronous push-pull output pin that can read its output state.
84+
pub trait StatefulOutputPin: OutputPin {
85+
/// Is the pin in drive high mode?
86+
///
87+
/// This returns [`Ready`](core::task::Poll::Ready) when the pin's drive mode been read.
88+
///
89+
/// *NOTE* this does *not* read the electrical state of the pin.
90+
async fn is_set_high(&mut self) -> Result<bool, Self::Error>;
91+
92+
/// Is the pin in drive low mode?
93+
///
94+
/// This returns [`Ready`](core::task::Poll::Ready) when the pin's drive mode been read.
95+
///
96+
/// *NOTE* this does *not* read the electrical state of the pin.
97+
async fn is_set_low(&mut self) -> Result<bool, Self::Error>;
98+
99+
/// Toggle pin output.
100+
///
101+
/// This returns [`Ready`](core::task::Poll::Ready) when the pin has been toggled.
102+
async fn toggle(&mut self) -> Result<(), Self::Error> {
103+
let was_low: bool = self.is_set_low().await?;
104+
self.set_state(PinState::from(was_low)).await
105+
}
106+
}
107+
108+
impl<T: StatefulOutputPin + ?Sized> StatefulOutputPin for &mut T {
109+
#[inline]
110+
async fn is_set_high(&mut self) -> Result<bool, Self::Error> {
111+
T::is_set_high(self).await
112+
}
113+
114+
#[inline]
115+
async fn is_set_low(&mut self) -> Result<bool, Self::Error> {
116+
T::is_set_low(self).await
117+
}
118+
119+
#[inline]
120+
async fn toggle(&mut self) -> Result<(), Self::Error> {
121+
T::toggle(self).await
122+
}
123+
}
124+
125+
/// Asynchronous single digital input pin.
126+
pub trait InputPin: ErrorType {
127+
/// Is the input pin high?
128+
///
129+
/// This returns [`Ready`](core::task::Poll::Ready) when the pin's electrical state has been read.
130+
///
131+
/// *NOTE* the input state of the pin may have changed before the future is polled.
132+
async fn is_high(&mut self) -> Result<bool, Self::Error>;
133+
134+
/// Is the input pin low?
135+
///
136+
/// This returns [`Ready`](core::task::Poll::Ready) when the pin's electrical state has been read.
137+
///
138+
/// *NOTE* the input state of the pin may have changed before the future is polled.
139+
async fn is_low(&mut self) -> Result<bool, Self::Error>;
140+
}
141+
142+
impl<T: InputPin + ?Sized> InputPin for &mut T {
143+
#[inline]
144+
async fn is_high(&mut self) -> Result<bool, Self::Error> {
145+
T::is_high(self).await
146+
}
147+
148+
#[inline]
149+
async fn is_low(&mut self) -> Result<bool, Self::Error> {
150+
T::is_low(self).await
151+
}
152+
}
19153

20154
/// Asynchronously wait for GPIO pin state.
21155
pub trait Wait: ErrorType {

0 commit comments

Comments
 (0)