1use core::future::Future;
20use core::pin::Pin;
21use core::task::{Context, Poll};
22use portable_atomic::Ordering;
23
24use agb::input::{Button, ButtonController, Tri};
25use embassy_sync::waitqueue::AtomicWaker;
26
27#[cfg(feature = "time")]
28use embassy_time;
29
30#[cfg(feature = "executor")]
31use embassy_executor;
32
33const KEYPAD_INPUT: *mut u16 = 0x04000130 as *mut u16;
35
36const BUTTON_COUNT: usize = 10;
37static BUTTON_WAKERS: [AtomicWaker; BUTTON_COUNT] = [const { AtomicWaker::new() }; BUTTON_COUNT];
39
40static GLOBAL_BUTTON_STATE: portable_atomic::AtomicU16 = portable_atomic::AtomicU16::new(0);
42
43static POLLING_TASK_RUNNING: portable_atomic::AtomicBool = portable_atomic::AtomicBool::new(false);
45
46#[derive(Debug, Clone, Copy)]
48pub enum PollingRate {
49 Hz30,
51 Hz60,
53 Hz90,
55 Hz120,
57 Custom(u32),
59}
60
61impl PollingRate {
62 pub fn as_hz(self) -> u32 {
64 match self {
65 PollingRate::Hz30 => 30,
66 PollingRate::Hz60 => 60,
67 PollingRate::Hz90 => 90,
68 PollingRate::Hz120 => 120,
69 PollingRate::Custom(hz) => hz.clamp(10, 240),
70 }
71 }
72}
73
74impl Default for PollingRate {
75 fn default() -> Self {
76 PollingRate::Hz60
77 }
78}
79
80#[derive(Debug, Clone, Copy)]
82pub struct InputConfig {
83 pub poll_rate: PollingRate,
85}
86
87impl InputConfig {
88 pub fn new(poll_rate: PollingRate) -> Self {
90 Self { poll_rate }
91 }
92}
93
94impl Default for InputConfig {
95 fn default() -> Self {
96 Self {
97 poll_rate: PollingRate::default(),
98 }
99 }
100}
101
102impl From<PollingRate> for InputConfig {
103 fn from(poll_rate: PollingRate) -> Self {
104 Self { poll_rate }
105 }
106}
107
108fn button_to_index(button: Button) -> Option<usize> {
110 match button {
111 Button::A => Some(0),
112 Button::B => Some(1),
113 Button::SELECT => Some(2),
114 Button::START => Some(3),
115 Button::RIGHT => Some(4),
116 Button::LEFT => Some(5),
117 Button::UP => Some(6),
118 Button::DOWN => Some(7),
119 Button::R => Some(8),
120 Button::L => Some(9),
121 _ => None,
122 }
123}
124
125fn ensure_input_initialized() {
127 if !POLLING_TASK_RUNNING.swap(true, Ordering::SeqCst) {
128 let current = !unsafe { KEYPAD_INPUT.read_volatile() };
130 GLOBAL_BUTTON_STATE.store(current, Ordering::SeqCst);
131 }
132}
133
134fn poll_input_changes() {
136 let current = !unsafe { KEYPAD_INPUT.read_volatile() };
137 let previous = GLOBAL_BUTTON_STATE.load(Ordering::SeqCst);
138
139 if current != previous {
140 let changed = current ^ previous;
142 let buttons = [
143 Button::A,
144 Button::B,
145 Button::SELECT,
146 Button::START,
147 Button::RIGHT,
148 Button::LEFT,
149 Button::UP,
150 Button::DOWN,
151 Button::R,
152 Button::L,
153 ];
154
155 for (i, button) in buttons.iter().enumerate() {
156 let button_mask = button.bits() as u16;
157 if (changed & button_mask) != 0 {
158 BUTTON_WAKERS[i].wake();
160 }
161 }
162
163 GLOBAL_BUTTON_STATE.store(current, Ordering::SeqCst);
165 }
166}
167
168#[cfg(all(feature = "time", feature = "executor"))]
170#[embassy_executor::task]
171pub async fn input_polling_task(config: InputConfig) {
172 let poll_interval_ms = 1000 / config.poll_rate.as_hz() as u64;
173
174 let current = !unsafe { KEYPAD_INPUT.read_volatile() };
176 GLOBAL_BUTTON_STATE.store(current, Ordering::SeqCst);
177
178 loop {
179 poll_input_changes();
180 embassy_time::Timer::after(embassy_time::Duration::from_millis(poll_interval_ms)).await;
181 }
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
186pub enum ButtonEvent {
187 Pressed,
189 Released,
191}
192
193#[must_use = "futures do nothing unless you `.await` or poll them"]
195struct ButtonEventFuture {
196 button: Button,
197 waiting_for_press: bool,
198 completed: bool,
199}
200
201impl ButtonEventFuture {
202 fn new(button: Button, waiting_for_press: bool) -> Self {
203 Self {
204 button,
205 waiting_for_press,
206 completed: false,
207 }
208 }
209}
210
211impl Future for ButtonEventFuture {
212 type Output = ButtonEvent;
213
214 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
215 if self.completed {
216 return Poll::Ready(if self.waiting_for_press {
217 ButtonEvent::Pressed
218 } else {
219 ButtonEvent::Released
220 });
221 }
222
223 if let Some(index) = button_to_index(self.button) {
224 BUTTON_WAKERS[index].register(cx.waker());
225
226 let current = !unsafe { KEYPAD_INPUT.read_volatile() };
228 let is_pressed = (current & self.button.bits() as u16) != 0;
229
230 if self.waiting_for_press && is_pressed {
231 self.completed = true;
232 Poll::Ready(ButtonEvent::Pressed)
233 } else if !self.waiting_for_press && !is_pressed {
234 self.completed = true;
235 Poll::Ready(ButtonEvent::Released)
236 } else {
237 Poll::Pending
238 }
239 } else {
240 Poll::Ready(if self.waiting_for_press {
241 ButtonEvent::Pressed
242 } else {
243 ButtonEvent::Released
244 })
245 }
246 }
247}
248
249#[must_use = "futures do nothing unless you `.await` or poll them"]
251struct AnyButtonEventFuture {
252 last_state: u16,
253}
254
255impl AnyButtonEventFuture {
256 fn new() -> Self {
257 let current = !unsafe { KEYPAD_INPUT.read_volatile() };
258 Self {
259 last_state: current,
260 }
261 }
262}
263
264impl Future for AnyButtonEventFuture {
265 type Output = (Button, ButtonEvent);
266
267 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
268 for waker in &BUTTON_WAKERS {
270 waker.register(cx.waker());
271 }
272
273 let current = !unsafe { KEYPAD_INPUT.read_volatile() };
275 let changed = current ^ self.last_state;
276
277 if changed != 0 {
278 let buttons = [
280 Button::A,
281 Button::B,
282 Button::SELECT,
283 Button::START,
284 Button::RIGHT,
285 Button::LEFT,
286 Button::UP,
287 Button::DOWN,
288 Button::R,
289 Button::L,
290 ];
291
292 for button in buttons.iter() {
293 let button_mask = button.bits() as u16;
294 if (changed & button_mask) != 0 {
295 let is_pressed = (current & button_mask) != 0;
296
297 if is_pressed {
299 self.last_state |= button_mask;
300 } else {
301 self.last_state &= !button_mask;
302 }
303
304 return Poll::Ready((
305 *button,
306 if is_pressed {
307 ButtonEvent::Pressed
308 } else {
309 ButtonEvent::Released
310 },
311 ));
312 }
313 }
314 }
315
316 Poll::Pending
317 }
318}
319
320pub struct AsyncInput {
322 controller: ButtonController,
323 _config: InputConfig,
324}
325
326impl AsyncInput {
327 pub(crate) fn new() -> Self {
328 Self::with_config(InputConfig::default())
329 }
330
331 pub(crate) fn with_config(config: InputConfig) -> Self {
332 ensure_input_initialized();
333
334 Self {
335 controller: ButtonController::new(),
336 _config: config,
337 }
338 }
339
340 pub async fn wait_for_button_press(&mut self, button: Button) -> ButtonEvent {
342 let current = !unsafe { KEYPAD_INPUT.read_volatile() };
344 let is_pressed = (current & button.bits() as u16) != 0;
345
346 if is_pressed {
347 ButtonEventFuture::new(button, false).await;
349 }
350
351 ButtonEventFuture::new(button, true).await
353 }
354
355 pub async fn wait_for_any_button_press(&mut self) -> (Button, ButtonEvent) {
357 AnyButtonEventFuture::new().await
358 }
359
360 pub async fn wait_for_button_press_polling(&mut self, button: Button) -> ButtonEvent {
362 ButtonPressFuture::new(&mut self.controller, button).await
363 }
364
365 pub async fn wait_for_any_button_press_polling(&mut self) -> (Button, ButtonEvent) {
367 AnyButtonPressFuture::new(&mut self.controller).await
368 }
369
370 pub fn update(&mut self) {
372 self.controller.update();
373 }
374
375 pub fn is_pressed(&self, button: Button) -> bool {
377 let current = !unsafe { KEYPAD_INPUT.read_volatile() };
378 (current & button.bits() as u16) != 0
379 }
380
381 pub fn is_pressed_polling(&self, button: Button) -> bool {
383 self.controller.is_pressed(button)
384 }
385
386 pub fn is_just_pressed_polling(&self, button: Button) -> bool {
388 self.controller.is_just_pressed(button)
389 }
390
391 pub fn x_tri(&self) -> Tri {
393 self.controller.x_tri()
394 }
395
396 pub fn y_tri(&self) -> Tri {
398 self.controller.y_tri()
399 }
400
401 pub(crate) fn button_state_bits(&self) -> u16 {
403 let mut bits = 0u16;
404 for button in [
405 Button::A,
406 Button::B,
407 Button::START,
408 Button::SELECT,
409 Button::LEFT,
410 Button::RIGHT,
411 Button::UP,
412 Button::DOWN,
413 Button::L,
414 Button::R,
415 ] {
416 if self.controller.is_pressed(button) {
417 bits |= button.bits() as u16;
418 }
419 }
420 bits
421 }
422}
423
424struct ButtonPressFuture<'a> {
426 controller: &'a mut ButtonController,
427 button: Button,
428 waiting_for_release: bool,
429}
430
431impl<'a> ButtonPressFuture<'a> {
432 fn new(controller: &'a mut ButtonController, button: Button) -> Self {
433 let waiting_for_release = controller.is_pressed(button);
434 Self {
435 controller,
436 button,
437 waiting_for_release,
438 }
439 }
440}
441
442impl<'a> Future for ButtonPressFuture<'a> {
443 type Output = ButtonEvent;
444
445 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
446 self.controller.update();
447
448 let is_pressed = self.controller.is_pressed(self.button);
449
450 if self.waiting_for_release {
451 if !is_pressed {
452 self.waiting_for_release = false;
453 return Poll::Ready(ButtonEvent::Released);
454 }
455 } else if is_pressed {
456 return Poll::Ready(ButtonEvent::Pressed);
457 }
458
459 cx.waker().wake_by_ref();
461 Poll::Pending
462 }
463}
464
465struct AnyButtonPressFuture<'a> {
467 controller: &'a mut ButtonController,
468}
469
470impl<'a> AnyButtonPressFuture<'a> {
471 fn new(controller: &'a mut ButtonController) -> Self {
472 Self { controller }
473 }
474}
475
476impl<'a> Future for AnyButtonPressFuture<'a> {
477 type Output = (Button, ButtonEvent);
478
479 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
480 self.controller.update();
481
482 let buttons = [
484 Button::A,
485 Button::B,
486 Button::START,
487 Button::SELECT,
488 Button::LEFT,
489 Button::RIGHT,
490 Button::UP,
491 Button::DOWN,
492 Button::L,
493 Button::R,
494 ];
495
496 for &button in &buttons {
497 if self.controller.is_just_pressed(button) {
498 return Poll::Ready((button, ButtonEvent::Pressed));
499 }
500 if self.controller.is_just_released(button) {
501 return Poll::Ready((button, ButtonEvent::Released));
502 }
503 }
504
505 cx.waker().wake_by_ref();
507 Poll::Pending
508 }
509}