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}