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}