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}