vorago_shared_hal/gpio/
asynch.rs1#![deny(missing_docs)]
10use core::future::Future;
11
12use embassy_sync::waitqueue::AtomicWaker;
13use embedded_hal_async::digital::Wait;
14use portable_atomic::AtomicBool;
15
16#[cfg(feature = "vor4x")]
17use crate::NUM_PORT_DEFAULT;
18#[cfg(feature = "vor1x")]
19use crate::{InterruptConfig, NUM_PORT_A, NUM_PORT_B};
20
21#[cfg(feature = "vor4x")]
22use super::ll::PortDoesNotSupportInterrupts;
23
24pub use super::ll::InterruptEdge;
25use super::{
26 Input, Port,
27 ll::{DynPinId, LowLevelGpio},
28};
29
30cfg_if::cfg_if! {
31 if #[cfg(feature = "vor1x")] {
32 static WAKERS_FOR_PORT_A: [AtomicWaker; NUM_PORT_A] = [const { AtomicWaker::new() }; NUM_PORT_A];
33 static WAKERS_FOR_PORT_B: [AtomicWaker; NUM_PORT_B] = [const { AtomicWaker::new() }; NUM_PORT_B];
34 static EDGE_DETECTION_PORT_A: [AtomicBool; NUM_PORT_A] =
35 [const { AtomicBool::new(false) }; NUM_PORT_A];
36 static EDGE_DETECTION_PORT_B: [AtomicBool; NUM_PORT_B] =
37 [const { AtomicBool::new(false) }; NUM_PORT_B];
38 } else {
39 static WAKERS_FOR_PORT_A: [AtomicWaker; NUM_PORT_DEFAULT] =
40 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
41 static WAKERS_FOR_PORT_B: [AtomicWaker; NUM_PORT_DEFAULT] =
42 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
43 static WAKERS_FOR_PORT_C: [AtomicWaker; NUM_PORT_DEFAULT] =
44 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
45 static WAKERS_FOR_PORT_D: [AtomicWaker; NUM_PORT_DEFAULT] =
46 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
47 static WAKERS_FOR_PORT_E: [AtomicWaker; NUM_PORT_DEFAULT] =
48 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
49 static WAKERS_FOR_PORT_F: [AtomicWaker; NUM_PORT_DEFAULT] =
50 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
51
52 static EDGE_DETECTION_PORT_A: [AtomicBool; NUM_PORT_DEFAULT] =
53 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
54 static EDGE_DETECTION_PORT_B: [AtomicBool; NUM_PORT_DEFAULT] =
55 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
56 static EDGE_DETECTION_PORT_C: [AtomicBool; NUM_PORT_DEFAULT] =
57 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
58 static EDGE_DETECTION_PORT_D: [AtomicBool; NUM_PORT_DEFAULT] =
59 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
60 static EDGE_DETECTION_PORT_E: [AtomicBool; NUM_PORT_DEFAULT] =
61 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
62 static EDGE_DETECTION_PORT_F: [AtomicBool; NUM_PORT_DEFAULT] =
63 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
64 }
65}
66
67#[inline]
68fn pin_group_to_waker_and_edge_detection_group(
69 port: Port,
70) -> (&'static [AtomicWaker], &'static [AtomicBool]) {
71 match port {
72 Port::A => (WAKERS_FOR_PORT_A.as_ref(), EDGE_DETECTION_PORT_A.as_ref()),
73 Port::B => (WAKERS_FOR_PORT_B.as_ref(), EDGE_DETECTION_PORT_B.as_ref()),
74 #[cfg(feature = "vor4x")]
75 Port::C => (WAKERS_FOR_PORT_C.as_ref(), EDGE_DETECTION_PORT_C.as_ref()),
76 #[cfg(feature = "vor4x")]
77 Port::D => (WAKERS_FOR_PORT_D.as_ref(), EDGE_DETECTION_PORT_D.as_ref()),
78 #[cfg(feature = "vor4x")]
79 Port::E => (WAKERS_FOR_PORT_E.as_ref(), EDGE_DETECTION_PORT_E.as_ref()),
80 #[cfg(feature = "vor4x")]
81 Port::F => (WAKERS_FOR_PORT_F.as_ref(), EDGE_DETECTION_PORT_F.as_ref()),
82 #[cfg(feature = "vor4x")]
83 Port::G => unreachable!(),
84 }
85}
86
87#[cfg(feature = "vor1x")]
95pub fn on_interrupt_for_async_gpio_for_port(port: Port) {
96 on_interrupt_for_async_gpio_for_port_generic(port);
97}
98
99#[cfg(feature = "vor4x")]
107pub fn on_interrupt_for_async_gpio_for_port(
108 port: Port,
109) -> Result<(), PortDoesNotSupportInterrupts> {
110 if port == Port::G {
111 return Err(PortDoesNotSupportInterrupts);
112 }
113 on_interrupt_for_async_gpio_for_port_generic(port);
114 Ok(())
115}
116
117fn on_interrupt_for_async_gpio_for_port_generic(port: Port) {
118 let mut gpio = unsafe { port.steal_regs() };
119
120 let irq_enb = gpio.read_irq_enable();
121 let edge_status = gpio.read_edge_status();
122 let (wakers, edge_detection) = pin_group_to_waker_and_edge_detection_group(port);
123
124 on_interrupt_for_port(irq_enb, edge_status, wakers, edge_detection);
125}
126
127#[inline]
128fn on_interrupt_for_port(
129 mut irq_enb: u32,
130 edge_status: u32,
131 wakers: &'static [AtomicWaker],
132 edge_detection: &'static [AtomicBool],
133) {
134 while irq_enb != 0 {
136 let bit_pos = irq_enb.trailing_zeros() as usize;
139 let bit_mask = 1 << bit_pos;
140
141 if edge_status & bit_mask != 0 {
142 edge_detection[bit_pos].store(true, core::sync::atomic::Ordering::Relaxed);
143 wakers[bit_pos].wake();
144 }
145 irq_enb &= !bit_mask;
147 }
148}
149
150pub struct InputPinFuture {
156 id: DynPinId,
157 waker_group: &'static [AtomicWaker],
158 edge_detection_group: &'static [AtomicBool],
159}
160
161impl InputPinFuture {
162 #[cfg(feature = "vor1x")]
164 pub fn new_with_input_pin(pin: &mut Input, edge: InterruptEdge) -> Self {
165 let (waker_group, edge_detection_group) =
166 pin_group_to_waker_and_edge_detection_group(pin.id().port());
167 edge_detection_group[pin.id().offset()].store(false, core::sync::atomic::Ordering::Relaxed);
168 pin.configure_edge_interrupt(edge);
169 pin.enable_interrupt_gpio_only();
170 Self {
171 id: pin.id(),
172 waker_group,
173 edge_detection_group,
174 }
175 }
176
177 #[cfg(feature = "vor4x")]
179 pub fn new_with_input_pin(
180 pin: &mut Input,
181 edge: InterruptEdge,
182 ) -> Result<Self, PortDoesNotSupportInterrupts> {
183 let (waker_group, edge_detection_group) =
184 pin_group_to_waker_and_edge_detection_group(pin.id().port());
185 pin.configure_edge_interrupt(edge);
186 pin.enable_interrupt_gpio_only();
187 Ok(Self {
188 id: pin.id(),
189 waker_group,
190 edge_detection_group,
191 })
192 }
193}
194
195impl Drop for InputPinFuture {
196 fn drop(&mut self) {
197 let mut ll = LowLevelGpio::new(self.id);
198 #[cfg(feature = "vor1x")]
199 ll.disable_interrupt(false);
200 #[cfg(feature = "vor4x")]
201 ll.disable_interrupt();
202 }
203}
204
205impl Future for InputPinFuture {
206 type Output = ();
207 fn poll(
208 self: core::pin::Pin<&mut Self>,
209 cx: &mut core::task::Context<'_>,
210 ) -> core::task::Poll<Self::Output> {
211 let idx = self.id.offset();
212 self.waker_group[idx].register(cx.waker());
213 if self.edge_detection_group[idx].swap(false, core::sync::atomic::Ordering::Relaxed) {
214 return core::task::Poll::Ready(());
215 }
216 core::task::Poll::Pending
217 }
218}
219
220pub struct InputPinAsync {
222 pin: Input,
223}
224
225impl InputPinAsync {
226 #[cfg(feature = "vor1x")]
233 pub fn new(mut pin: Input, irq_config: InterruptConfig) -> Self {
234 pin.enable_interrupt(irq_config, false);
236 Self { pin }
237 }
238
239 #[cfg(feature = "vor4x")]
246 pub fn new(mut pin: Input) -> Result<Self, PortDoesNotSupportInterrupts> {
247 if pin.id().port() == Port::G {
248 return Err(PortDoesNotSupportInterrupts);
249 }
250 pin.enable_interrupt(true, false)?;
252 Ok(Self { pin })
253 }
254
255 pub async fn wait_for_high(&mut self) {
259 #[cfg(feature = "vor1x")]
261 let fut = InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::LowToHigh);
262 #[cfg(feature = "vor4x")]
263 let fut =
264 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::LowToHigh).unwrap();
265 if self.pin.is_high() {
266 return;
267 }
268 fut.await;
269 }
270
271 #[inline]
273 pub fn is_high(&self) -> bool {
274 self.pin.is_high()
275 }
276
277 #[inline]
279 pub fn is_low(&self) -> bool {
280 self.pin.is_low()
281 }
282
283 #[inline]
285 pub fn inner(&self) -> &Input {
286 &self.pin
287 }
288
289 #[inline]
291 pub fn inner_mut(&mut self) -> &mut Input {
292 &mut self.pin
293 }
294
295 pub async fn wait_for_low(&mut self) {
299 #[cfg(feature = "vor1x")]
301 let fut = InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::HighToLow);
302 #[cfg(feature = "vor4x")]
303 let fut =
304 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::HighToLow).unwrap();
305 if self.pin.is_low() {
306 return;
307 }
308 fut.await;
309 }
310
311 pub async fn wait_for_falling_edge(&mut self) {
313 #[cfg(feature = "vor1x")]
315 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::HighToLow).await;
316 #[cfg(feature = "vor4x")]
317 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::HighToLow)
318 .unwrap()
319 .await;
320 }
321
322 pub async fn wait_for_rising_edge(&mut self) {
324 #[cfg(feature = "vor1x")]
326 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::LowToHigh).await;
327 }
328
329 pub async fn wait_for_any_edge(&mut self) {
331 #[cfg(feature = "vor1x")]
333 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::BothEdges).await;
334 #[cfg(feature = "vor4x")]
335 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::BothEdges)
336 .unwrap()
337 .await;
338 }
339
340 #[inline]
342 pub fn release(self) -> Input {
343 self.pin
344 }
345}
346
347impl embedded_hal::digital::ErrorType for InputPinAsync {
348 type Error = core::convert::Infallible;
349}
350
351impl Wait for InputPinAsync {
352 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
353 self.wait_for_high().await;
354 Ok(())
355 }
356
357 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
358 self.wait_for_low().await;
359 Ok(())
360 }
361
362 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
363 self.wait_for_rising_edge().await;
364 Ok(())
365 }
366
367 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
368 self.wait_for_falling_edge().await;
369 Ok(())
370 }
371
372 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
373 self.wait_for_any_edge().await;
374 Ok(())
375 }
376}
377
378impl embedded_hal::digital::InputPin for InputPinAsync {
379 fn is_low(&mut self) -> Result<bool, Self::Error> {
380 Ok(self.inner().is_low())
381 }
382
383 fn is_high(&mut self) -> Result<bool, Self::Error> {
384 Ok(self.inner().is_high())
385 }
386}