esp_hal/gpio/asynch.rs
1use core::{
2 sync::atomic::Ordering,
3 task::{Context, Poll},
4};
5
6use procmacros::ram;
7
8use crate::{
9 asynch::AtomicWaker,
10 gpio::{Event, Flex, GpioBank, Input, NUM_PINS},
11};
12
13#[ram]
14pub(super) static PIN_WAKERS: [AtomicWaker; NUM_PINS] = [const { AtomicWaker::new() }; NUM_PINS];
15
16impl Flex<'_> {
17 /// Wait until the pin experiences a particular [`Event`].
18 ///
19 /// The GPIO driver will disable listening for the event once it occurs,
20 /// or if the `Future` is dropped - which also means this method is **not**
21 /// cancellation-safe, it will always wait for a future event.
22 ///
23 /// Note that calling this function will overwrite previous
24 /// [`listen`][Self::listen] operations for this pin.
25 #[inline]
26 #[instability::unstable]
27 pub async fn wait_for(&mut self, event: Event) {
28 // Make sure this pin is not being processed by an interrupt handler. We need to
29 // always take a critical section even if the pin is not listening, because the
30 // interrupt handler may be running on another core and the interrupt handler
31 // may be in the process of processing the pin if the interrupt status is set -
32 // regardless of the pin actually listening or not.
33 if self.is_listening() || self.is_interrupt_set() {
34 self.unlisten_and_clear();
35 }
36
37 // At this point the pin is no longer listening, and not being processed, so we
38 // can safely do our setup.
39
40 // Mark pin as async. The interrupt handler clears this bit before processing a
41 // pin and unlistens it, so this call will not race with the interrupt
42 // handler (because it must have finished before `unlisten` above, or the
43 // handler no longer )
44 self.pin
45 .bank()
46 .async_operations()
47 .fetch_or(self.pin.mask(), Ordering::Relaxed);
48
49 // Start listening for the event. We only need to do this once, as disabling
50 // the interrupt will signal the future to complete.
51 self.listen(event);
52
53 PinFuture { pin: self }.await
54 }
55
56 /// Wait until the pin is high.
57 ///
58 /// See [Self::wait_for] for more information.
59 #[inline]
60 #[instability::unstable]
61 pub async fn wait_for_high(&mut self) {
62 self.wait_for(Event::HighLevel).await
63 }
64
65 /// Wait until the pin is low.
66 ///
67 /// See [Self::wait_for] for more information.
68 #[inline]
69 #[instability::unstable]
70 pub async fn wait_for_low(&mut self) {
71 self.wait_for(Event::LowLevel).await
72 }
73
74 /// Wait for the pin to undergo a transition from low to high.
75 ///
76 /// See [Self::wait_for] for more information.
77 #[inline]
78 #[instability::unstable]
79 pub async fn wait_for_rising_edge(&mut self) {
80 self.wait_for(Event::RisingEdge).await
81 }
82
83 /// Wait for the pin to undergo a transition from high to low.
84 ///
85 /// See [Self::wait_for] for more information.
86 #[inline]
87 #[instability::unstable]
88 pub async fn wait_for_falling_edge(&mut self) {
89 self.wait_for(Event::FallingEdge).await
90 }
91
92 /// Wait for the pin to undergo any transition, i.e low to high OR high
93 /// to low.
94 ///
95 /// See [Self::wait_for] for more information.
96 #[inline]
97 #[instability::unstable]
98 pub async fn wait_for_any_edge(&mut self) {
99 self.wait_for(Event::AnyEdge).await
100 }
101}
102
103impl Input<'_> {
104 /// Wait until the pin experiences a particular [`Event`].
105 ///
106 /// The GPIO driver will disable listening for the event once it occurs,
107 /// or if the `Future` is dropped - which also means this method is **not**
108 /// cancellation-safe, it will always wait for a future event.
109 ///
110 /// Note that calling this function will overwrite previous
111 /// [`listen`][Self::listen] operations for this pin.
112 #[inline]
113 pub async fn wait_for(&mut self, event: Event) {
114 self.pin.wait_for(event).await
115 }
116
117 /// Wait until the pin is high.
118 ///
119 /// See [Self::wait_for] for more information.
120 #[inline]
121 pub async fn wait_for_high(&mut self) {
122 self.pin.wait_for_high().await
123 }
124
125 /// Wait until the pin is low.
126 ///
127 /// See [Self::wait_for] for more information.
128 #[inline]
129 pub async fn wait_for_low(&mut self) {
130 self.pin.wait_for_low().await
131 }
132
133 /// Wait for the pin to undergo a transition from low to high.
134 ///
135 /// See [Self::wait_for] for more information.
136 #[inline]
137 pub async fn wait_for_rising_edge(&mut self) {
138 self.pin.wait_for_rising_edge().await
139 }
140
141 /// Wait for the pin to undergo a transition from high to low.
142 ///
143 /// See [Self::wait_for] for more information.
144 #[inline]
145 pub async fn wait_for_falling_edge(&mut self) {
146 self.pin.wait_for_falling_edge().await
147 }
148
149 /// Wait for the pin to undergo any transition, i.e low to high OR high
150 /// to low.
151 ///
152 /// See [Self::wait_for] for more information.
153 #[inline]
154 pub async fn wait_for_any_edge(&mut self) {
155 self.pin.wait_for_any_edge().await
156 }
157}
158
159#[must_use = "futures do nothing unless you `.await` or poll them"]
160struct PinFuture<'f, 'd> {
161 pin: &'f mut Flex<'d>,
162}
163
164impl PinFuture<'_, '_> {
165 fn number(&self) -> u8 {
166 self.pin.number()
167 }
168
169 fn bank(&self) -> GpioBank {
170 self.pin.pin.bank()
171 }
172
173 fn mask(&self) -> u32 {
174 self.pin.pin.mask()
175 }
176
177 fn is_done(&self) -> bool {
178 // Only the interrupt handler should clear the async bit, and only if the
179 // specific pin is handling an interrupt. This way the user may clear the
180 // interrupt status without worrying about the async bit being cleared.
181 self.bank().async_operations().load(Ordering::Acquire) & self.mask() == 0
182 }
183}
184
185impl core::future::Future for PinFuture<'_, '_> {
186 type Output = ();
187
188 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
189 PIN_WAKERS[self.number() as usize].register(cx.waker());
190
191 if self.is_done() {
192 Poll::Ready(())
193 } else {
194 Poll::Pending
195 }
196 }
197}
198
199impl Drop for PinFuture<'_, '_> {
200 fn drop(&mut self) {
201 // If the future has completed, unlistening and removing the async bit will have
202 // been done by the interrupt handler.
203
204 if !self.is_done() {
205 self.pin.unlisten_and_clear();
206
207 // Unmark pin as async so that a future listen call doesn't wake a waker for no
208 // reason.
209 self.bank()
210 .async_operations()
211 .fetch_and(!self.mask(), Ordering::Relaxed);
212 }
213 }
214}