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