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