Skip to main content

esp_hal/gpio/
asynch.rs

1use core::{
2    sync::atomic::Ordering,
3    task::{Context, Poll},
4};
5
6use crate::gpio::{Event, Flex, GpioBank, Input, InputPin};
7
8impl Flex<'_> {
9    /// Wait until the pin experiences a particular [`Event`].
10    ///
11    /// The GPIO driver will disable listening for the event once it occurs,
12    /// or if the `Future` is dropped - which also means this method is **not**
13    /// cancellation-safe, it will always wait for a future event.
14    ///
15    /// Note that calling this function will overwrite previous
16    /// [`listen`][Self::listen] operations for this pin.
17    ///
18    /// A wait continues through a light sleep, and a pin that waits also ends the sleep, like a
19    /// listening pin. There is one exception: a wait for an edge on a pin that is already at the
20    /// level at the end of that edge. See [`listen`][Self::listen].
21    #[inline]
22    #[instability::unstable]
23    pub async fn wait_for(&mut self, event: Event) {
24        // Make sure this pin is not being processed by an interrupt handler. We need to
25        // always take a critical section even if the pin is not listening, because the
26        // interrupt handler may be running on another core and the interrupt handler
27        // may be in the process of processing the pin if the interrupt status is set -
28        // regardless of the pin actually listening or not.
29        if self.is_listening() || self.is_interrupt_set() {
30            self.unlisten_and_clear();
31        }
32
33        // At this point the pin is no longer listening, and not being processed, so we
34        // can safely do our setup.
35
36        // Mark pin as async. The interrupt handler clears this bit before processing a
37        // pin and unlistens it, so this call will not race with the interrupt
38        // handler (because it must have finished before `unlisten` above, or the
39        // handler no longer )
40        self.pin
41            .bank()
42            .async_operations()
43            .fetch_or(self.pin.mask(), Ordering::Relaxed);
44
45        // Start listening for the event. We only need to do this once, as disabling
46        // the interrupt will signal the future to complete.
47        self.pin.listen(event);
48
49        PinFuture { pin: self }.await;
50    }
51
52    /// Wait until the pin is high.
53    ///
54    /// See [Self::wait_for] for more information.
55    #[inline]
56    #[instability::unstable]
57    pub async fn wait_for_high(&mut self) {
58        self.wait_for(Event::HighLevel).await
59    }
60
61    /// Wait until the pin is low.
62    ///
63    /// See [Self::wait_for] for more information.
64    #[inline]
65    #[instability::unstable]
66    pub async fn wait_for_low(&mut self) {
67        self.wait_for(Event::LowLevel).await
68    }
69
70    /// Wait for the pin to undergo a transition from low to high.
71    ///
72    /// See [Self::wait_for] for more information.
73    #[inline]
74    #[instability::unstable]
75    pub async fn wait_for_rising_edge(&mut self) {
76        self.wait_for(Event::RisingEdge).await
77    }
78
79    /// Wait for the pin to undergo a transition from high to low.
80    ///
81    /// See [Self::wait_for] for more information.
82    #[inline]
83    #[instability::unstable]
84    pub async fn wait_for_falling_edge(&mut self) {
85        self.wait_for(Event::FallingEdge).await
86    }
87
88    /// Wait for the pin to undergo any transition, i.e low to high OR high
89    /// to low.
90    ///
91    /// See [Self::wait_for] for more information.
92    #[inline]
93    #[instability::unstable]
94    pub async fn wait_for_any_edge(&mut self) {
95        self.wait_for(Event::AnyEdge).await
96    }
97}
98
99impl Input<'_> {
100    #[procmacros::doc_replace]
101    /// Wait until the pin experiences a particular [`Event`].
102    ///
103    /// ## Example
104    ///
105    /// ```rust, no_run
106    /// # {before_snippet}
107    /// use esp_hal::gpio::{Event, Input, InputConfig};
108    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
109    ///
110    /// input_pin.wait_for(Event::LowLevel).await;
111    /// # {after_snippet}
112    /// ```
113    ///
114    /// ## Cancellation
115    ///
116    /// This function is not cancellation-safe.
117    ///
118    /// - Calling this function will overwrite previous [`listen`][Self::listen] operations for this
119    ///   pin, making it side-effectful.
120    /// - Dropping the [`Future`] returned by this function will cancel the wait operation. If the
121    ///   event occurs after the future is dropped, a consequent wait operation will ignore the
122    ///   event.
123    ///
124    /// A wait continues through a light sleep, and a pin that waits also ends the sleep, like a
125    /// listening pin. There is one exception: a wait for an edge on a pin that is already at the
126    /// level at the end of that edge. See [`listen`][Self::listen].
127    #[inline]
128    #[instability::unstable]
129    pub async fn wait_for(&mut self, event: Event) {
130        self.pin.wait_for(event).await
131    }
132
133    #[procmacros::doc_replace]
134    /// Wait until the pin is high.
135    ///
136    /// See [Self::wait_for] for more information.
137    ///
138    /// ## Example
139    ///
140    /// ```rust, no_run
141    /// # {before_snippet}
142    /// use esp_hal::gpio::{Event, Input, InputConfig};
143    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
144    ///
145    /// input_pin.wait_for_high().await;
146    /// # {after_snippet}
147    /// ```
148    #[inline]
149    pub async fn wait_for_high(&mut self) {
150        self.pin.wait_for_high().await
151    }
152
153    #[procmacros::doc_replace]
154    /// Wait until the pin is low.
155    ///
156    /// See [Self::wait_for] for more information.
157    ///
158    /// ## Example
159    ///
160    /// ```rust, no_run
161    /// # {before_snippet}
162    /// use esp_hal::gpio::{Event, Input, InputConfig};
163    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
164    ///
165    /// input_pin.wait_for_low().await;
166    /// # {after_snippet}
167    /// ```
168    #[inline]
169    pub async fn wait_for_low(&mut self) {
170        self.pin.wait_for_low().await
171    }
172
173    #[procmacros::doc_replace]
174    /// Wait for the pin to undergo a transition from low to high.
175    ///
176    /// See [Self::wait_for] for more information.
177    ///
178    /// ## Example
179    ///
180    /// ```rust, no_run
181    /// # {before_snippet}
182    /// use esp_hal::gpio::{Event, Input, InputConfig};
183    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
184    ///
185    /// input_pin.wait_for_rising_edge().await;
186    /// # {after_snippet}
187    /// ```
188    #[inline]
189    pub async fn wait_for_rising_edge(&mut self) {
190        self.pin.wait_for_rising_edge().await
191    }
192
193    #[procmacros::doc_replace]
194    /// Wait for the pin to undergo a transition from high to low.
195    ///
196    /// See [Self::wait_for] for more information.
197    ///
198    /// ## Example
199    ///
200    /// ```rust, no_run
201    /// # {before_snippet}
202    /// use esp_hal::gpio::{Event, Input, InputConfig};
203    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
204    ///
205    /// input_pin.wait_for_falling_edge().await;
206    /// # {after_snippet}
207    /// ```
208    #[inline]
209    pub async fn wait_for_falling_edge(&mut self) {
210        self.pin.wait_for_falling_edge().await
211    }
212
213    #[procmacros::doc_replace]
214    /// Wait for the pin to undergo any transition, i.e low to high OR high
215    /// to low.
216    ///
217    /// See [Self::wait_for] for more information.
218    ///
219    /// ## Example
220    ///
221    /// ```rust, no_run
222    /// # {before_snippet}
223    /// use esp_hal::gpio::{Event, Input, InputConfig};
224    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
225    ///
226    /// input_pin.wait_for_any_edge().await;
227    /// # {after_snippet}
228    /// ```
229    #[inline]
230    pub async fn wait_for_any_edge(&mut self) {
231        self.pin.wait_for_any_edge().await
232    }
233}
234
235#[must_use = "futures do nothing unless you `.await` or poll them"]
236struct PinFuture<'f, 'd> {
237    pin: &'f mut Flex<'d>,
238}
239
240impl PinFuture<'_, '_> {
241    fn bank(&self) -> GpioBank {
242        self.pin.pin.bank()
243    }
244
245    fn mask(&self) -> u32 {
246        self.pin.pin.mask()
247    }
248
249    fn is_done(&self) -> bool {
250        // Only the interrupt handler should clear the async bit, and only if the
251        // specific pin is handling an interrupt. This way the user may clear the
252        // interrupt status without worrying about the async bit being cleared.
253        self.bank().async_operations().load(Ordering::Acquire) & self.mask() == 0
254    }
255}
256
257impl core::future::Future for PinFuture<'_, '_> {
258    type Output = ();
259
260    fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
261        self.pin.pin.waker().register(cx.waker());
262
263        if self.is_done() {
264            Poll::Ready(())
265        } else {
266            Poll::Pending
267        }
268    }
269}
270
271impl Drop for PinFuture<'_, '_> {
272    fn drop(&mut self) {
273        // If the future has completed, unlistening and removing the async bit will have
274        // been done by the interrupt handler.
275
276        if !self.is_done() {
277            self.pin.unlisten_and_clear();
278
279            // Unmark pin as async so that a future listen call doesn't wake a waker for no
280            // reason.
281            self.bank()
282                .async_operations()
283                .fetch_and(!self.mask(), Ordering::Relaxed);
284        }
285    }
286}