vorago_shared_hal/gpio/
asynch.rs1use core::future::Future;
10
11use embassy_sync::waitqueue::AtomicWaker;
12use embedded_hal_async::digital::Wait;
13use portable_atomic::AtomicBool;
14
15#[cfg(feature = "vor4x")]
16use crate::NUM_PORT_DEFAULT;
17#[cfg(feature = "vor1x")]
18use crate::{InterruptConfig, NUM_PORT_A, NUM_PORT_B};
19
20#[cfg(feature = "vor4x")]
21use super::ll::PortDoesNotSupportInterrupts;
22
23#[cfg(feature = "vor1x")]
24use va108xx as pac;
25
26pub use super::ll::InterruptEdge;
27use super::{
28 Input, Port,
29 ll::{DynPinId, LowLevelGpio},
30};
31
32cfg_if::cfg_if! {
33 if #[cfg(feature = "vor1x")] {
34 static WAKERS_FOR_PORT_A: [AtomicWaker; NUM_PORT_A] = [const { AtomicWaker::new() }; NUM_PORT_A];
35 static WAKERS_FOR_PORT_B: [AtomicWaker; NUM_PORT_B] = [const { AtomicWaker::new() }; NUM_PORT_B];
36 static EDGE_DETECTION_PORT_A: [AtomicBool; NUM_PORT_A] =
37 [const { AtomicBool::new(false) }; NUM_PORT_A];
38 static EDGE_DETECTION_PORT_B: [AtomicBool; NUM_PORT_B] =
39 [const { AtomicBool::new(false) }; NUM_PORT_B];
40 } else {
41 static WAKERS_FOR_PORT_A: [AtomicWaker; NUM_PORT_DEFAULT] =
42 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
43 static WAKERS_FOR_PORT_B: [AtomicWaker; NUM_PORT_DEFAULT] =
44 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
45 static WAKERS_FOR_PORT_C: [AtomicWaker; NUM_PORT_DEFAULT] =
46 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
47 static WAKERS_FOR_PORT_D: [AtomicWaker; NUM_PORT_DEFAULT] =
48 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
49 static WAKERS_FOR_PORT_E: [AtomicWaker; NUM_PORT_DEFAULT] =
50 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
51 static WAKERS_FOR_PORT_F: [AtomicWaker; NUM_PORT_DEFAULT] =
52 [const { AtomicWaker::new() }; NUM_PORT_DEFAULT];
53
54 static EDGE_DETECTION_PORT_A: [AtomicBool; NUM_PORT_DEFAULT] =
55 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
56 static EDGE_DETECTION_PORT_B: [AtomicBool; NUM_PORT_DEFAULT] =
57 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
58 static EDGE_DETECTION_PORT_C: [AtomicBool; NUM_PORT_DEFAULT] =
59 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
60 static EDGE_DETECTION_PORT_D: [AtomicBool; NUM_PORT_DEFAULT] =
61 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
62 static EDGE_DETECTION_PORT_E: [AtomicBool; NUM_PORT_DEFAULT] =
63 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
64 static EDGE_DETECTION_PORT_F: [AtomicBool; NUM_PORT_DEFAULT] =
65 [const { AtomicBool::new(false) }; NUM_PORT_DEFAULT];
66 }
67}
68
69#[inline]
70fn pin_group_to_waker_and_edge_detection_group(
71 port: Port,
72) -> (&'static [AtomicWaker], &'static [AtomicBool]) {
73 match port {
74 Port::A => (WAKERS_FOR_PORT_A.as_ref(), EDGE_DETECTION_PORT_A.as_ref()),
75 Port::B => (WAKERS_FOR_PORT_B.as_ref(), EDGE_DETECTION_PORT_B.as_ref()),
76 #[cfg(feature = "vor4x")]
77 Port::C => (WAKERS_FOR_PORT_C.as_ref(), EDGE_DETECTION_PORT_C.as_ref()),
78 #[cfg(feature = "vor4x")]
79 Port::D => (WAKERS_FOR_PORT_D.as_ref(), EDGE_DETECTION_PORT_D.as_ref()),
80 #[cfg(feature = "vor4x")]
81 Port::E => (WAKERS_FOR_PORT_E.as_ref(), EDGE_DETECTION_PORT_E.as_ref()),
82 #[cfg(feature = "vor4x")]
83 Port::F => (WAKERS_FOR_PORT_F.as_ref(), EDGE_DETECTION_PORT_F.as_ref()),
84 #[cfg(feature = "vor4x")]
85 Port::G => unreachable!(),
86 }
87}
88
89#[cfg(feature = "vor1x")]
97pub fn on_interrupt_for_async_gpio_for_port(port: Port) {
98 on_interrupt_for_async_gpio_for_port_generic(port);
99}
100#[cfg(feature = "vor4x")]
101pub fn on_interrupt_for_async_gpio_for_port(
102 port: Port,
103) -> Result<(), PortDoesNotSupportInterrupts> {
104 if port == Port::G {
105 return Err(PortDoesNotSupportInterrupts);
106 }
107 on_interrupt_for_async_gpio_for_port_generic(port);
108 Ok(())
109}
110
111fn on_interrupt_for_async_gpio_for_port_generic(port: Port) {
112 let gpio = unsafe { port.steal_gpio() };
113
114 let irq_enb = gpio.read_irq_enable();
115 let edge_status = gpio.read_edge_status();
116 let (wakers, edge_detection) = pin_group_to_waker_and_edge_detection_group(port);
117
118 on_interrupt_for_port(irq_enb, edge_status, wakers, edge_detection);
119}
120
121#[inline]
122fn on_interrupt_for_port(
123 mut irq_enb: u32,
124 edge_status: u32,
125 wakers: &'static [AtomicWaker],
126 edge_detection: &'static [AtomicBool],
127) {
128 while irq_enb != 0 {
129 let bit_pos = irq_enb.trailing_zeros() as usize;
130 let bit_mask = 1 << bit_pos;
131
132 wakers[bit_pos].wake();
133
134 if edge_status & bit_mask != 0 {
135 edge_detection[bit_pos].store(true, core::sync::atomic::Ordering::Relaxed);
136
137 irq_enb &= !bit_mask;
139 }
140 }
141}
142
143pub struct InputPinFuture {
149 id: DynPinId,
150 waker_group: &'static [AtomicWaker],
151 edge_detection_group: &'static [AtomicBool],
152}
153
154impl InputPinFuture {
155 #[cfg(feature = "vor1x")]
156 pub fn new_with_input_pin(pin: &mut Input, irq: pac::Interrupt, edge: InterruptEdge) -> Self {
157 let (waker_group, edge_detection_group) =
158 pin_group_to_waker_and_edge_detection_group(pin.id().port());
159 edge_detection_group[pin.id().offset()].store(false, core::sync::atomic::Ordering::Relaxed);
160 pin.configure_edge_interrupt(edge);
161 #[cfg(feature = "vor1x")]
162 pin.enable_interrupt(InterruptConfig::new(irq, true, true));
163 Self {
164 id: pin.id(),
165 waker_group,
166 edge_detection_group,
167 }
168 }
169 #[cfg(feature = "vor4x")]
170 pub fn new_with_input_pin(
171 pin: &mut Input,
172 edge: InterruptEdge,
173 ) -> Result<Self, PortDoesNotSupportInterrupts> {
174 let (waker_group, edge_detection_group) =
175 pin_group_to_waker_and_edge_detection_group(pin.id().port());
176 pin.configure_edge_interrupt(edge);
177 pin.enable_interrupt(true)?;
178 Ok(Self {
179 id: pin.id(),
180 waker_group,
181 edge_detection_group,
182 })
183 }
184}
185
186impl Drop for InputPinFuture {
187 fn drop(&mut self) {
188 let mut ll = LowLevelGpio::new(self.id);
189 #[cfg(feature = "vor1x")]
190 ll.disable_interrupt(false);
191 #[cfg(feature = "vor4x")]
192 ll.disable_interrupt();
193 }
194}
195
196impl Future for InputPinFuture {
197 type Output = ();
198 fn poll(
199 self: core::pin::Pin<&mut Self>,
200 cx: &mut core::task::Context<'_>,
201 ) -> core::task::Poll<Self::Output> {
202 let idx = self.id.offset();
203 self.waker_group[idx].register(cx.waker());
204 if self.edge_detection_group[idx].swap(false, core::sync::atomic::Ordering::Relaxed) {
205 return core::task::Poll::Ready(());
206 }
207 core::task::Poll::Pending
208 }
209}
210
211pub struct InputPinAsync {
212 pin: Input,
213 #[cfg(feature = "vor1x")]
214 irq: va108xx::Interrupt,
215}
216
217impl InputPinAsync {
218 #[cfg(feature = "vor1x")]
225 pub fn new(pin: Input, irq: va108xx::Interrupt) -> Self {
226 Self { pin, irq }
227 }
228 #[cfg(feature = "vor4x")]
229 pub fn new(pin: Input) -> Result<Self, PortDoesNotSupportInterrupts> {
230 if pin.id().port() == Port::G {
231 return Err(PortDoesNotSupportInterrupts);
232 }
233 Ok(Self { pin })
234 }
235
236 pub async fn wait_for_high(&mut self) {
240 #[cfg(feature = "vor1x")]
242 let fut =
243 InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh);
244 #[cfg(feature = "vor4x")]
245 let fut =
246 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::LowToHigh).unwrap();
247 if self.pin.is_high() {
248 return;
249 }
250 fut.await;
251 }
252
253 pub async fn wait_for_low(&mut self) {
257 #[cfg(feature = "vor1x")]
259 let fut =
260 InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow);
261 #[cfg(feature = "vor4x")]
262 let fut =
263 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::HighToLow).unwrap();
264 if self.pin.is_low() {
265 return;
266 }
267 fut.await;
268 }
269
270 pub async fn wait_for_falling_edge(&mut self) {
272 #[cfg(feature = "vor1x")]
274 InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow).await;
275 #[cfg(feature = "vor4x")]
276 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::HighToLow)
277 .unwrap()
278 .await;
279 }
280
281 pub async fn wait_for_rising_edge(&mut self) {
283 #[cfg(feature = "vor1x")]
285 InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh).await;
286 }
287
288 pub async fn wait_for_any_edge(&mut self) {
290 #[cfg(feature = "vor1x")]
292 InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::BothEdges).await;
293 #[cfg(feature = "vor4x")]
294 InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::BothEdges)
295 .unwrap()
296 .await;
297 }
298
299 pub fn release(self) -> Input {
300 self.pin
301 }
302}
303
304impl embedded_hal::digital::ErrorType for InputPinAsync {
305 type Error = core::convert::Infallible;
306}
307
308impl Wait for InputPinAsync {
309 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
310 self.wait_for_high().await;
311 Ok(())
312 }
313
314 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
315 self.wait_for_low().await;
316 Ok(())
317 }
318
319 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
320 self.wait_for_rising_edge().await;
321 Ok(())
322 }
323
324 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
325 self.wait_for_falling_edge().await;
326 Ok(())
327 }
328
329 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
330 self.wait_for_any_edge().await;
331 Ok(())
332 }
333}