Skip to content

Commit 7ec0ea4

Browse files
committed
Add asynchronous versions of most HAL traits
1 parent 181d44b commit 7ec0ea4

26 files changed

+1336
-0
lines changed

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@ repository = "https://github.com/rust-embedded/embedded-hal"
1515
version = "0.2.3"
1616

1717
[dependencies]
18+
futures = { version = "0.3.4", optional = true }
1819
nb = { version = "0.1.1", features = ["unstable"] }
1920

2021
[dev-dependencies]
2122
stm32f3 = { version = "0.8", features = ["stm32f303", "rt"] }
2223
futures = "0.1.17"
2324

25+
[features]
26+
asynchronous = ["futures"]

src/asynchronous/gpio.rs

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
//! General input/output pins.
2+
//!
3+
//! The [`InputPin`] and [`OutputPin`] traits define pins that can be read and written digitally
4+
//! (i.e. either in a low or high state).
5+
//!
6+
//! There are additionally various `Into*` traits that allow users to re-configure pins to switch
7+
//! between different modes of operation, e.g. [`IntoFloatingInputPin`] turns a pin into an
8+
//! [`InputPin`] that does not employ any pull-up or pull-down resistors.
9+
use core::pin;
10+
use core::task;
11+
12+
pub mod get;
13+
pub mod set;
14+
15+
/// A generic pin that can't be interacted with.
16+
pub trait Pin {
17+
/// The common error type for all pin operations.
18+
///
19+
/// A single error type for all operations is enforced for simplicity.
20+
type Error;
21+
}
22+
23+
/// A pin that can be read from.
24+
pub trait InputPin: Pin {
25+
/// Polls a read operation of this pin to completion.
26+
fn poll_get(
27+
self: pin::Pin<&mut Self>,
28+
cx: &mut task::Context<'_>,
29+
) -> task::Poll<Result<bool, Self::Error>>;
30+
}
31+
32+
/// Extension functions for instances of [`InputPin`].
33+
pub trait InputPinExt: InputPin {
34+
/// Gets the current high or low state of this pin.
35+
fn get(&mut self) -> get::Get<Self>
36+
where
37+
Self: Unpin,
38+
{
39+
get::get(self)
40+
}
41+
}
42+
43+
impl<A> InputPinExt for A where A: InputPin {}
44+
45+
/// A pin that can be written to.
46+
pub trait OutputPin: Pin {
47+
/// Polls a write operation of this pin to completion.
48+
fn poll_set(
49+
self: pin::Pin<&mut Self>,
50+
cx: &mut task::Context<'_>,
51+
high: bool,
52+
) -> task::Poll<Result<(), Self::Error>>;
53+
}
54+
55+
/// Extension functions for instances of [`OutputPin`].
56+
pub trait OutputPinExt: OutputPin {
57+
/// Sets the current high or low state of this pin.
58+
fn set(&mut self, high: bool) -> set::Set<Self>
59+
where
60+
Self: Unpin,
61+
{
62+
set::set(self, high)
63+
}
64+
}
65+
66+
impl<A> OutputPinExt for A where A: OutputPin {}
67+
68+
/// A pin that can be turned into an [`InputPin`] that does not employ any pull-up or pull-down
69+
/// resistors.
70+
pub trait IntoFloatingInputPin: Pin {
71+
/// The type of an [`InputPin`] that does not employ any pull-up or pull-down resistors.
72+
type FloatingInputPin: InputPin<Error = Self::Error> + Unpin;
73+
74+
/// Attempts to re-configure this pin into the new mode.
75+
fn into_floating_input_pin(self) -> Result<Self::FloatingInputPin, Self::Error>;
76+
}
77+
78+
/// A pin that can be turned into an [`InputPin`] that has a pull-up resistor attached.
79+
pub trait IntoPullUpInputPin: Pin {
80+
/// The type of an [`InputPin`] that has a pull-up resistor attached.
81+
type PullUpInputPin: InputPin<Error = Self::Error> + Unpin;
82+
83+
/// Attempts to re-configure this pin into the new mode.
84+
fn into_pull_up_input_pin(self) -> Result<Self::PullUpInputPin, Self::Error>;
85+
}
86+
87+
/// A pin that can be turned into an [`InputPin`] that has a pull-down resistor attached.
88+
pub trait IntoPullDownInputPin: Pin {
89+
/// The type of an [`InputPin`] that has a pull-down resistor attached.
90+
type PullDownInputPin: InputPin<Error = Self::Error> + Unpin;
91+
92+
/// Attempts to re-configure this pin into the new mode.
93+
fn into_pull_down_input_pin(self) -> Result<Self::PullDownInputPin, Self::Error>;
94+
}
95+
96+
/// A pin that can be turned into an [`OutputPin`] that is in open drain mode.
97+
pub trait IntoOpenDrainOutputPin: Pin {
98+
/// The type of an [`OutputPin`] that is in open drain mode.
99+
type OpenDrainOutputPin: OutputPin<Error = Self::Error> + Unpin;
100+
101+
/// Attempts to re-configure this pin into the new mode.
102+
fn into_open_drain_output_pin(
103+
self,
104+
initial_high: bool,
105+
) -> Result<Self::OpenDrainOutputPin, Self::Error>;
106+
}
107+
108+
/// A pin that can be turned into an [`OutputPin`] that is in push-pull mode.
109+
pub trait IntoPushPullOutputPin: Pin {
110+
/// The type of an [`OutputPin`] that is in push-pull mode.
111+
type PushPullOutputPin: OutputPin<Error = Self::Error> + Unpin;
112+
113+
/// Attempts to re-configure this pin into the new mode.
114+
fn into_push_pull_output_pin(
115+
self,
116+
initial_high: bool,
117+
) -> Result<Self::PushPullOutputPin, Self::Error>;
118+
}
119+
120+
/// A virtual pin that is not actually connected to a physical pin.
121+
///
122+
/// The pin will always read a fixed value, can be configured to be in any mode, and will always
123+
/// have writes result in no-ops.
124+
#[derive(Clone, Copy, Debug)]
125+
pub struct NoConnect(bool);
126+
127+
impl NoConnect {
128+
/// Creates a new [`NoConnect`] that will always read the specified high/low value.
129+
pub fn new(value: bool) -> Self {
130+
NoConnect(value)
131+
}
132+
}
133+
134+
impl Pin for NoConnect {
135+
type Error = futures::never::Never;
136+
}
137+
138+
impl InputPin for NoConnect {
139+
fn poll_get(
140+
self: pin::Pin<&mut Self>,
141+
_cx: &mut task::Context<'_>,
142+
) -> task::Poll<Result<bool, Self::Error>> {
143+
task::Poll::Ready(Ok(false))
144+
}
145+
}
146+
147+
impl OutputPin for NoConnect {
148+
fn poll_set(
149+
self: pin::Pin<&mut Self>,
150+
_cx: &mut task::Context<'_>,
151+
_high: bool,
152+
) -> task::Poll<Result<(), Self::Error>> {
153+
task::Poll::Ready(Ok(()))
154+
}
155+
}
156+
157+
impl IntoFloatingInputPin for NoConnect {
158+
type FloatingInputPin = Self;
159+
160+
fn into_floating_input_pin(self) -> Result<Self::FloatingInputPin, Self::Error> {
161+
Ok(self)
162+
}
163+
}
164+
165+
impl IntoPullUpInputPin for NoConnect {
166+
type PullUpInputPin = Self;
167+
168+
fn into_pull_up_input_pin(self) -> Result<Self::PullUpInputPin, Self::Error> {
169+
Ok(self)
170+
}
171+
}
172+
173+
impl IntoPullDownInputPin for NoConnect {
174+
type PullDownInputPin = Self;
175+
176+
fn into_pull_down_input_pin(self) -> Result<Self::PullDownInputPin, Self::Error> {
177+
Ok(self)
178+
}
179+
}
180+
181+
impl IntoOpenDrainOutputPin for NoConnect {
182+
type OpenDrainOutputPin = Self;
183+
184+
fn into_open_drain_output_pin(
185+
self,
186+
_initial_high: bool,
187+
) -> Result<Self::OpenDrainOutputPin, Self::Error> {
188+
Ok(self)
189+
}
190+
}
191+
192+
impl IntoPushPullOutputPin for NoConnect {
193+
type PushPullOutputPin = Self;
194+
195+
fn into_push_pull_output_pin(
196+
self,
197+
_initial_high: bool,
198+
) -> Result<Self::PushPullOutputPin, Self::Error> {
199+
Ok(self)
200+
}
201+
}

src/asynchronous/gpio/get.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//! Defines futures for getting the value off of a GPIO pin.
2+
use core::future;
3+
use core::pin;
4+
use core::task;
5+
6+
/// A future which reads the value off a GPIO pin.
7+
#[derive(Debug)]
8+
#[must_use = "futures do nothing unless you `.await` or poll them"]
9+
pub struct Get<'a, A>
10+
where
11+
A: super::InputPin + Unpin + ?Sized,
12+
{
13+
pin: &'a mut A,
14+
}
15+
16+
/// Creates a new [`Get`] for the provided GPIO pin.
17+
pub fn get<A>(pin: &mut A) -> Get<A>
18+
where
19+
A: super::InputPin + Unpin + ?Sized,
20+
{
21+
Get { pin }
22+
}
23+
24+
impl<A> future::Future for Get<'_, A>
25+
where
26+
A: super::InputPin + Unpin + ?Sized,
27+
{
28+
type Output = Result<bool, A::Error>;
29+
30+
fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
31+
let this = &mut *self;
32+
pin::Pin::new(&mut *this.pin).poll_get(cx)
33+
}
34+
}

src/asynchronous/gpio/set.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//! Defines futures for setting the value of a GPIO pin.
2+
use core::future;
3+
use core::pin;
4+
use core::task;
5+
6+
/// A future which sets the value of a GPIO pin.
7+
#[derive(Debug)]
8+
#[must_use = "futures do nothing unless you `.await` or poll them"]
9+
pub struct Set<'a, A>
10+
where
11+
A: super::OutputPin + Unpin + ?Sized,
12+
{
13+
pin: &'a mut A,
14+
high: bool,
15+
}
16+
17+
/// Creates a new [`Set`] for the provided GPIO pin, that, when polled, will drive it to the
18+
/// specified high or low value.
19+
pub fn set<A>(pin: &mut A, high: bool) -> Set<A>
20+
where
21+
A: super::OutputPin + Unpin + ?Sized,
22+
{
23+
Set { pin, high }
24+
}
25+
26+
impl<A> future::Future for Set<'_, A>
27+
where
28+
A: super::OutputPin + Unpin + ?Sized,
29+
{
30+
type Output = Result<(), A::Error>;
31+
32+
fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
33+
let this = &mut *self;
34+
pin::Pin::new(&mut *this.pin).poll_set(cx, this.high)
35+
}
36+
}

0 commit comments

Comments
 (0)