use esp_hal::gpio::AnyPin;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ButtonId {
Left,
Center,
Right,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ButtonAction {
Short(usize),
Long,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ButtonEvent {
pub id: ButtonId,
pub action: ButtonAction,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ButtonTiming {
pub long_press_ms: u64,
pub multi_tap_ms: u64,
}
impl ButtonTiming {
pub const fn multi_tap() -> Self {
Self { long_press_ms: 500, multi_tap_ms: 300 }
}
pub const fn immediate_single_press() -> Self {
Self { long_press_ms: Self::multi_tap().long_press_ms, multi_tap_ms: 0 }
}
}
impl Default for ButtonTiming {
fn default() -> Self {
Self::multi_tap()
}
}
pub struct ButtonResources<'a> {
pub left: AnyPin<'a>,
pub center: AnyPin<'a>,
pub right: AnyPin<'a>,
}
#[cfg(feature = "buttons")]
mod physical {
use async_button::{Button, ButtonConfig, ButtonEvent as AsyncButtonEvent, Mode};
use embassy_futures::select::{Either3, select3};
use embassy_time_04::Duration;
use esp_hal::gpio::{Input, InputConfig, Pull};
use super::{ButtonAction, ButtonEvent, ButtonId, ButtonResources, ButtonTiming};
fn config_from_timing(timing: ButtonTiming) -> ButtonConfig {
ButtonConfig {
double_click: Duration::from_millis(timing.multi_tap_ms),
long_press: Duration::from_millis(timing.long_press_ms),
mode: Mode::PullUp,
..ButtonConfig::default()
}
}
impl ButtonResources<'static> {
pub fn into_buttons(self) -> Buttons<'static> {
self.make_buttons(ButtonConfig::default())
}
pub fn into_buttons_with_timing(self, timing: ButtonTiming) -> Buttons<'static> {
self.make_buttons(config_from_timing(timing))
}
fn make_buttons(self, config: ButtonConfig) -> Buttons<'static> {
let make = |pin| {
Button::new(
Input::new(pin, InputConfig::default().with_pull(Pull::Up)),
config,
)
};
Buttons {
left: make(self.left),
center: make(self.center),
right: make(self.right),
}
}
}
pub struct Buttons<'a> {
left: Button<Input<'a>>,
center: Button<Input<'a>>,
right: Button<Input<'a>>,
}
impl Buttons<'_> {
pub async fn next_event(&mut self) -> ButtonEvent {
let (id, event) = match select3(
self.left.update(),
self.center.update(),
self.right.update(),
)
.await
{
Either3::First(e) => (ButtonId::Left, e),
Either3::Second(e) => (ButtonId::Center, e),
Either3::Third(e) => (ButtonId::Right, e),
};
let action = match event {
AsyncButtonEvent::ShortPress { count } => ButtonAction::Short(count),
AsyncButtonEvent::LongPress => ButtonAction::Long,
};
ButtonEvent { id, action }
}
}
}
#[cfg(feature = "buttons")]
pub use physical::Buttons;