xpanse_api/interfaces/
buttons.rs1use alloc::{boxed::Box, sync::Arc};
9use core::future::Future;
10use core::marker::PhantomData;
11use core::pin::Pin;
12
13use embassy_rp::{
14 Peri,
15 gpio::{AnyPin, Input, Pull},
16};
17use embassy_sync::blocking_mutex::CriticalSectionMutex;
18use embassy_time::Timer;
19
20mod private {
21 pub trait Sealed {}
22}
23
24pub trait ButtonRole: private::Sealed + 'static + Send {}
29
30macro_rules! role {
31 ($($n:ident),* $(,)?) => {
32 $(
33 pub struct $n;
34 impl private::Sealed for $n {}
35 impl ButtonRole for $n {}
36 )*
37 };
38}
39
40role!(A, B, X, Y, Up, Down, Left, Right);
41
42pub trait Button<R: ButtonRole>: Send {
44 fn wait_for_pressed<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
48 fn is_pressed(&self) -> bool;
50}
51
52pub struct SingleButton<R: ButtonRole> {
54 pin: Input<'static>,
55 _role: PhantomData<R>,
56}
57
58struct SharedButton<R: ButtonRole> {
59 pin: Arc<CriticalSectionMutex<Input<'static>>>,
60 _role: PhantomData<R>,
61}
62
63impl<R: ButtonRole> SharedButton<R> {
64 fn is_low(&self) -> bool {
65 self.pin.lock(Input::is_low)
66 }
67}
68
69impl<R: ButtonRole> SingleButton<R> {
70 pub fn new(pin: Peri<'static, AnyPin>) -> Self {
72 Self {
73 pin: Input::new(pin, Pull::Up),
74 _role: PhantomData,
75 }
76 }
77}
78
79impl<R: ButtonRole> Button<R> for SingleButton<R> {
80 fn wait_for_pressed<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
81 Box::pin(async move {
82 while self.pin.is_low() {
83 self.pin.wait_for_high().await;
84 Timer::after_millis(20).await;
85 }
86
87 loop {
88 self.pin.wait_for_low().await;
89 Timer::after_millis(20).await;
90 if self.pin.is_low() {
91 return;
92 }
93 }
94 })
95 }
96
97 fn is_pressed(&self) -> bool {
98 self.pin.is_low()
99 }
100}
101
102impl<R: ButtonRole> Button<R> for SharedButton<R> {
103 fn wait_for_pressed<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
104 Box::pin(async move {
105 while self.is_low() {
106 Timer::after_millis(20).await;
107 }
108
109 loop {
110 Timer::after_millis(20).await;
111 if self.is_low() {
112 return;
113 }
114 }
115 })
116 }
117
118 fn is_pressed(&self) -> bool {
119 self.is_low()
120 }
121}
122
123pub fn pin_button<R: ButtonRole>(pin: Peri<'static, AnyPin>) -> Box<dyn Button<R>> {
145 Box::new(SingleButton::<R>::new(pin))
146}
147
148pub fn aliased_pin_buttons<R: ButtonRole, Alias: ButtonRole>(
153 pin: Peri<'static, AnyPin>,
154) -> (Box<dyn Button<R>>, Box<dyn Button<Alias>>) {
155 let pin = Arc::new(CriticalSectionMutex::new(Input::new(pin, Pull::Up)));
156 (
157 Box::new(SharedButton::<R> {
158 pin: pin.clone(),
159 _role: PhantomData,
160 }),
161 Box::new(SharedButton::<Alias> {
162 pin,
163 _role: PhantomData,
164 }),
165 )
166}