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}