A step sequencer for Adafruit's RP2040-based macropad
1use core::future::IntoFuture;
2
3use embassy_futures::select::{Either, select};
4use embassy_time::{Duration, Timer};
5
6use crate::debounced_button::DebouncedButton;
7
8pub struct ToggleWithHold<'a> {
9 button: DebouncedButton<'a>,
10 pub is_held: bool,
11 pub is_pressed: bool,
12 hold_threshold: Duration,
13 timer: Option<Timer>,
14}
15
16impl<'a> ToggleWithHold<'a> {
17 pub fn new(button: DebouncedButton<'a>, hold_threshold: Duration) -> Self {
18 ToggleWithHold {
19 button,
20 is_pressed: false,
21 is_held: false,
22 hold_threshold,
23 timer: None,
24 }
25 }
26
27 pub async fn on_change(&mut self) {
28 let button_future = self.button.on_change();
29 let timer_future = if let Some(timer) = self.timer.as_mut() {
30 &mut timer.into_future()
31 } else {
32 &mut Timer::after_secs(31536000) // one year, arbitrarily large
33 };
34
35 self.is_pressed = match select(button_future, timer_future).await {
36 Either::First(pressed) => {
37 self.timer = if pressed {
38 Some(Timer::after(self.hold_threshold))
39 } else {
40 None
41 };
42
43 if !pressed {
44 self.is_held = false;
45 }
46
47 pressed
48 }
49 Either::Second(_) => {
50 self.is_held = true;
51 self.timer = None;
52 true
53 }
54 };
55 }
56}