lora_e5_bsp/
pb.rs

1//! Push-buttons
2
3use stm32wlxx_hal::{
4    cortex_m::interrupt::CriticalSection,
5    gpio::{pins, Exti, Input, PinState, Pull},
6};
7
8const PULL: Pull = Pull::Up;
9
10/// Push-button D0.
11#[derive(Debug)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct D0 {
14    gpio: Input<pins::A0>,
15}
16
17/// Push-button labeled "Boot".
18#[derive(Debug)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub struct Boot {
21    gpio: Input<pins::B13>,
22}
23
24/// Simple trait for a push-button
25pub trait PushButton {
26    /// Input pin for the push-button
27    ///
28    /// This can be used to access the EXTI trait for the pin.
29    ///
30    /// # Example
31    ///
32    /// Setup EXTI to fire an interrupt when D0 is pushed.
33    ///
34    /// ```no_run
35    /// use lora_e5_bsp::{
36    ///     hal::{
37    ///         cortex_m,
38    ///         gpio::{Exti, ExtiTrg, PortA},
39    ///         pac,
40    ///     },
41    ///     pb::{PushButton, D0},
42    /// };
43    ///
44    /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
45    ///
46    /// let gpioa: PortA = PortA::split(dp.GPIOA, &mut dp.RCC);
47    /// let d0 = cortex_m::interrupt::free(|cs| D0::new(gpioa.a0, cs));
48    ///
49    /// <D0 as PushButton>::Pin::setup_exti_c1(&mut dp.EXTI, &mut dp.SYSCFG, ExtiTrg::Falling);
50    /// ```
51    type Pin: Exti;
52
53    /// Returns `True` if the button is currently being pushed.
54    fn is_pushed(&self) -> bool;
55}
56
57impl PushButton for D0 {
58    type Pin = pins::A0;
59
60    #[inline]
61    fn is_pushed(&self) -> bool {
62        self.gpio.level() == PinState::Low
63    }
64}
65
66impl PushButton for Boot {
67    type Pin = pins::B13;
68
69    #[inline]
70    fn is_pushed(&self) -> bool {
71        self.gpio.level() == PinState::Low
72    }
73}
74
75impl D0 {
76    /// Create a new push-button D0.
77    ///
78    /// # Example
79    ///
80    /// ```no_run
81    /// use lora_e5_bsp::{
82    ///     hal::{cortex_m, gpio::PortA, pac},
83    ///     pb::{PushButton, D0},
84    /// };
85    ///
86    /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
87    ///
88    /// let gpioa: PortA = PortA::split(dp.GPIOA, &mut dp.RCC);
89    /// let d0 = cortex_m::interrupt::free(|cs| D0::new(gpioa.a0, cs));
90    /// ```
91    pub fn new(a0: pins::A0, cs: &CriticalSection) -> Self {
92        Self {
93            gpio: Input::new(a0, PULL, cs),
94        }
95    }
96
97    /// Free the GPIO pin from the push-button struct.
98    ///
99    /// # Example
100    ///
101    /// ```no_run
102    /// use lora_e5_bsp::{
103    ///     hal::{cortex_m, gpio::PortA, pac},
104    ///     pb::{PushButton, D0},
105    /// };
106    ///
107    /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
108    ///
109    /// let gpioa: PortA = PortA::split(dp.GPIOA, &mut dp.RCC);
110    /// let d0 = cortex_m::interrupt::free(|cs| D0::new(gpioa.a0, cs));
111    /// // ... use push button
112    /// let c0 = d0.free();
113    /// ```
114    pub fn free(self) -> pins::A0 {
115        self.gpio.free()
116    }
117
118    /// Steal the push-button from whatever is currently using it.
119    ///
120    /// # Safety
121    ///
122    /// 1. Ensure that the code stealing the push-button has exclusive access
123    ///    to the underlying GPIO.
124    ///    Singleton checks are bypassed with this method.
125    /// 2. You are responsible for setting up the underlying GPIO correctly.
126    ///    No setup will occur when using this method.
127    ///
128    /// # Example
129    ///
130    /// ```
131    /// use lora_e5_bsp::pb::D0;
132    ///
133    /// // ... setup happens here
134    ///
135    /// let d0: D0 = unsafe { D0::steal() };
136    /// ```
137    pub unsafe fn steal() -> Self {
138        Self {
139            gpio: Input::steal(),
140        }
141    }
142}
143
144impl Boot {
145    /// Create a new boot push-button.
146    ///
147    /// # Example
148    ///
149    /// ```no_run
150    /// use lora_e5_bsp::{
151    ///     hal::{cortex_m, gpio::PortB, pac},
152    ///     pb::{Boot, PushButton},
153    /// };
154    ///
155    /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
156    ///
157    /// let gpiob: PortB = PortB::split(dp.GPIOB, &mut dp.RCC);
158    /// let boot = cortex_m::interrupt::free(|cs| Boot::new(gpiob.b13, cs));
159    /// ```
160    pub fn new(b13: pins::B13, cs: &CriticalSection) -> Self {
161        Self {
162            gpio: Input::new(b13, PULL, cs),
163        }
164    }
165
166    /// Free the GPIO pin from the push-button struct.
167    ///
168    /// # Example
169    ///
170    /// ```no_run
171    /// use lora_e5_bsp::{
172    ///     hal::{cortex_m, gpio::PortB, pac},
173    ///     pb::{Boot, PushButton},
174    /// };
175    ///
176    /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
177    ///
178    /// let gpiob: PortB = PortB::split(dp.GPIOB, &mut dp.RCC);
179    /// let boot = cortex_m::interrupt::free(|cs| Boot::new(gpiob.b13, cs));
180    /// // ... use push button
181    /// let b13 = boot.free();
182    /// ```
183    pub fn free(self) -> pins::B13 {
184        self.gpio.free()
185    }
186
187    /// Steal the push-button from whatever is currently using it.
188    ///
189    /// This will **not** initialize the GPIO peripheral.
190    ///
191    /// # Safety
192    ///
193    /// 1. Ensure that the code stealing the push-button has exclusive access
194    ///    to the underlying GPIO.
195    ///    Singleton checks are bypassed with this method.
196    /// 2. You are responsible for setting up the underlying GPIO correctly.
197    ///    No setup will occur when using this method.
198    ///
199    /// # Example
200    ///
201    /// ```
202    /// use lora_e5_bsp::pb::Boot;
203    ///
204    /// // ... setup happens here
205    ///
206    /// let boot: Boot = unsafe { Boot::steal() };
207    /// ```
208    pub unsafe fn steal() -> Self {
209        Self {
210            gpio: Input::steal(),
211        }
212    }
213}