embedded_c_sdk_bind_hal/gpio/
exti.rs

1use crate::ll_api::{ll_cmd::*, GpioExtiFlag};
2use crate::gpio::Pin;
3
4pub enum ExtiMode {
5    Rising,
6    Falling,
7    RisingFalling,
8}
9
10impl ExtiMode {
11    pub(crate) fn to_flag(&self) -> GpioExtiFlag {
12        match self {
13            ExtiMode::Rising => GpioExtiFlag::Rising,
14            ExtiMode::Falling => GpioExtiFlag::Falling,
15            ExtiMode::RisingFalling => GpioExtiFlag::RisingFalling,
16        }
17    }
18}
19
20impl<'d> super::pin::Input<'d> {
21    /// Configures the EXTI (External Interrupt) mode for the pin.
22    ///
23    /// # Arguments
24    /// * `mode` - The EXTI mode to set. This can be rising edge, falling edge, both edges, etc.
25    pub fn exti_config(&self, mode: ExtiMode) {
26        let port = self.pin.pin.port();
27        let pin = self.pin.pin.pin();
28
29        ll_invoke_inner!(INVOKE_ID_GPIO_EXTI, port, pin, mode.to_flag());
30    }
31
32    /// Enables the interrupt for the pin.
33    ///
34    /// This function can be reenabled after disabling it.
35    pub fn enable_interrupt(&self) {
36        let port = self.pin.pin.port();
37        let pin = self.pin.pin.pin();
38
39        ll_invoke_inner!(INVOKE_ID_GPIO_EXTI, port, pin, GpioExtiFlag::Enable);
40    }
41
42    /// Disables the interrupt for the pin.
43    ///
44    /// This function can be used to temporarily disable the interrupt without changing the EXTI mode.
45    pub fn disable_interrupt(&self) {
46        let port = self.pin.pin.port();
47        let pin = self.pin.pin.pin();
48
49        ll_invoke_inner!(INVOKE_ID_GPIO_EXTI, port, pin, GpioExtiFlag::Disable);
50    }
51}
52
53#[allow(non_snake_case)]
54#[no_mangle]
55#[inline]
56/// An unsafe C-compatible external function for hook EXTI IRQs.
57/// # Arguments
58/// * `_line` - The EXTI line number that triggered the interrupt. This corresponds to the pin number.
59unsafe extern "C" fn EXTI_IRQ_hook_rs(_line: u8) {
60    #[cfg(feature = "embassy")]
61    // If the 'embassy' feature is enabled, update the status of the EXTI event in the embassy framework's future system.
62    exti_future::exti_set_status(_line);
63
64    #[cfg(feature = "exti-irq-callback")]
65    {
66        // If the 'exti-irq-callback' feature is enabled, call the user-provided callback function.
67        // This allows users to define their own ISR handling logic.
68        extern "Rust" {
69            fn exti_irq_callback(line: u8);
70        }
71        exti_irq_callback(_line);
72    }
73}
74
75#[cfg(feature = "embassy")]
76pub mod exti_future {
77    use core::future::Future;
78    use core::task::{Context, Poll};
79    use embassy_sync::waitqueue::AtomicWaker;
80    use portable_atomic::{AtomicU16, Ordering};
81    use crate::gpio::Pin;
82
83    const EXTI_COUNT: usize = 16;
84    const NEW_AW: AtomicWaker = AtomicWaker::new();
85    static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT];
86    static EXTI_STATUS: AtomicU16 = AtomicU16::new(0);
87
88    #[inline]
89    pub fn exti_set_status(line: u8) {
90        if line < EXTI_COUNT as u8 {
91            EXTI_STATUS.bit_set(line as u32, Ordering::Relaxed);
92            EXTI_WAKERS[line as usize].wake();
93        }
94    }
95
96    impl<'d> super::super::pin::Input<'d> {
97        pub async fn wait_for_high(&mut self) {
98        let port = self.pin.pin.port();
99        let pin = self.pin.pin.pin();
100            let fut = ExtiInputFuture::new(port, pin, super::ExtiMode::Rising);
101            if Self::is_high(self) {
102                return;
103            }
104            fut.await
105        }
106
107        pub async fn wait_for_low(&mut self) {
108        let port = self.pin.pin.port();
109        let pin = self.pin.pin.pin();
110            let fut = ExtiInputFuture::new(port, pin, super::ExtiMode::Falling);
111            if !Self::is_high(self) {
112                return;
113            }
114            fut.await
115        }
116
117        pub async fn wait_for_rising_edge(&mut self) {
118            let port = self.pin.pin.port();
119            let pin = self.pin.pin.pin();
120            ExtiInputFuture::new(port, pin, super::ExtiMode::Rising).await
121        }
122
123        pub async fn wait_for_falling_edge(&mut self) {
124        let port = self.pin.pin.port();
125        let pin = self.pin.pin.pin();
126            ExtiInputFuture::new(port, pin, super::ExtiMode::Falling).await
127        }
128
129        pub async fn wait_for_any_edge(&mut self) {
130            let port = self.pin.pin.port();
131            let pin = self.pin.pin.pin();
132            ExtiInputFuture::new(port, pin, super::ExtiMode::RisingFalling).await
133        }
134    }
135
136    struct ExtiInputFuture {
137        port: u8,
138        pin: u8,
139    }
140
141    impl ExtiInputFuture {
142        fn new(port: u8, pin: u8, mode: super::ExtiMode) -> Self {
143            ll_invoke_inner!(crate::INVOKE_ID_GPIO_EXTI, port, pin, mode.to_flag());
144            //ll_invoke_inner!(crate::INVOKE_ID_GPIO_EXTI, pin, super::GpioExtiFlag::Enable);
145            Self { port, pin }
146        }
147    }
148
149    impl Drop for ExtiInputFuture {
150        fn drop(&mut self) {
151            ll_invoke_inner!(
152                crate::INVOKE_ID_GPIO_EXTI,
153                self.port,
154                self.pin,
155                super::GpioExtiFlag::Disable
156            );
157        }
158    }
159
160    impl Future for ExtiInputFuture {
161        type Output = ();
162
163        fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
164            EXTI_WAKERS[self.pin as usize].register(cx.waker());
165
166            if EXTI_STATUS.bit_clear(self.pin as u32, Ordering::Relaxed) {
167                Poll::Ready(())
168            } else {
169                Poll::Pending
170            }
171        }
172    }
173
174    impl<'d> embedded_hal_async::digital::Wait for super::super::Input<'d> {
175        async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
176            self.wait_for_high().await;
177            Ok(())
178        }
179
180        async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
181            self.wait_for_low().await;
182            Ok(())
183        }
184
185        async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
186            self.wait_for_rising_edge().await;
187            Ok(())
188        }
189
190        async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
191            self.wait_for_falling_edge().await;
192            Ok(())
193        }
194
195        async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
196            self.wait_for_any_edge().await;
197            Ok(())
198        }
199    }
200}