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    /// The GPIO driver will disable listening for the event once it occurs,
100    /// or if the `Future` is dropped - which also means this method is **not**
101    /// cancellation-safe, it will always wait for a future event.
102    ///
103    /// Note that calling this function will overwrite previous
104    /// [`listen`][Self::listen] operations for this pin.
105    ///
106    /// ## Example
107    ///
108    /// ```rust, no_run
109    /// # {before_snippet}
110    /// use esp_hal::gpio::{Event, Input, InputConfig};
111    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
112    ///
113    /// input_pin.wait_for(Event::LowLevel).await;
114    /// # {after_snippet}
115    /// ```
116    #[inline]
117    pub async fn wait_for(&mut self, event: Event) {
118        self.pin.wait_for(event).await
119    }
120
121    #[procmacros::doc_replace]
122    /// Wait until the pin is high.
123    ///
124    /// See [Self::wait_for] for more information.
125    ///
126    /// ## Example
127    ///
128    /// ```rust, no_run
129    /// # {before_snippet}
130    /// use esp_hal::gpio::{Event, Input, InputConfig};
131    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
132    ///
133    /// input_pin.wait_for_high().await;
134    /// # {after_snippet}
135    /// ```
136    #[inline]
137    pub async fn wait_for_high(&mut self) {
138        self.pin.wait_for_high().await
139    }
140
141    #[procmacros::doc_replace]
142    /// Wait until the pin is low.
143    ///
144    /// See [Self::wait_for] for more information.
145    ///
146    /// ## Example
147    ///
148    /// ```rust, no_run
149    /// # {before_snippet}
150    /// use esp_hal::gpio::{Event, Input, InputConfig};
151    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
152    ///
153    /// input_pin.wait_for_low().await;
154    /// # {after_snippet}
155    /// ```
156    #[inline]
157    pub async fn wait_for_low(&mut self) {
158        self.pin.wait_for_low().await
159    }
160
161    #[procmacros::doc_replace]
162    /// Wait for the pin to undergo a transition from low to high.
163    ///
164    /// See [Self::wait_for] for more information.
165    ///
166    /// ## Example
167    ///
168    /// ```rust, no_run
169    /// # {before_snippet}
170    /// use esp_hal::gpio::{Event, Input, InputConfig};
171    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
172    ///
173    /// input_pin.wait_for_rising_edge().await;
174    /// # {after_snippet}
175    /// ```
176    #[inline]
177    pub async fn wait_for_rising_edge(&mut self) {
178        self.pin.wait_for_rising_edge().await
179    }
180
181    #[procmacros::doc_replace]
182    /// Wait for the pin to undergo a transition from high to low.
183    ///
184    /// See [Self::wait_for] for more information.
185    ///
186    /// ## Example
187    ///
188    /// ```rust, no_run
189    /// # {before_snippet}
190    /// use esp_hal::gpio::{Event, Input, InputConfig};
191    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
192    ///
193    /// input_pin.wait_for_falling_edge().await;
194    /// # {after_snippet}
195    /// ```
196    #[inline]
197    pub async fn wait_for_falling_edge(&mut self) {
198        self.pin.wait_for_falling_edge().await
199    }
200
201    #[procmacros::doc_replace]
202    /// Wait for the pin to undergo any transition, i.e low to high OR high
203    /// to low.
204    ///
205    /// See [Self::wait_for] for more information.
206    ///
207    /// ## Example
208    ///
209    /// ```rust, no_run
210    /// # {before_snippet}
211    /// use esp_hal::gpio::{Event, Input, InputConfig};
212    /// let mut input_pin = Input::new(peripherals.GPIO4, InputConfig::default());
213    ///
214    /// input_pin.wait_for_any_edge().await;
215    /// # {after_snippet}
216    /// ```
217    #[inline]
218    pub async fn wait_for_any_edge(&mut self) {
219        self.pin.wait_for_any_edge().await
220    }
221}
222
223#[must_use = "futures do nothing unless you `.await` or poll them"]
224struct PinFuture<'f, 'd> {
225    pin: &'f mut Flex<'d>,
226}
227
228impl PinFuture<'_, '_> {
229    fn bank(&self) -> GpioBank {
230        self.pin.pin.bank()
231    }
232
233    fn mask(&self) -> u32 {
234        self.pin.pin.mask()
235    }
236
237    fn is_done(&self) -> bool {
238        // Only the interrupt handler should clear the async bit, and only if the
239        // specific pin is handling an interrupt. This way the user may clear the
240        // interrupt status without worrying about the async bit being cleared.
241        self.bank().async_operations().load(Ordering::Acquire) & self.mask() == 0
242    }
243}
244
245impl core::future::Future for PinFuture<'_, '_> {
246    type Output = ();
247
248    fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
249        self.pin.pin.waker().register(cx.waker());
250
251        if self.is_done() {
252            Poll::Ready(())
253        } else {
254            Poll::Pending
255        }
256    }
257}
258
259impl Drop for PinFuture<'_, '_> {
260    fn drop(&mut self) {
261        // If the future has completed, unlistening and removing the async bit will have
262        // been done by the interrupt handler.
263
264        if !self.is_done() {
265            self.pin.unlisten_and_clear();
266
267            // Unmark pin as async so that a future listen call doesn't wake a waker for no
268            // reason.
269            self.bank()
270                .async_operations()
271                .fetch_and(!self.mask(), Ordering::Relaxed);
272        }
273    }
274}