use anyhow::{anyhow, Result};
use esp_idf_hal::gpio::{InputMode, InputPin, PinDriver};
use std::sync::{Arc, Mutex};
use crate::{
infra::{Poller, State, Switch},
message::{Notifier, Trigger},
time::{sleep, yield_now},
};
pub struct Button<'a, T, MODE, TR>
where
T: InputPin,
MODE: InputMode,
TR: Trigger,
{
notifier: Notifier<TR>,
trigger: &'static TR,
pin: PinDriver<'a, T, MODE>,
state: Arc<Mutex<State>>,
}
impl<'a, T, MODE, TR> Button<'a, T, MODE, TR>
where
T: InputPin,
MODE: InputMode,
TR: Trigger,
{
pub fn new(
notifier: Notifier<TR>,
trigger: &'static TR,
pin: PinDriver<'a, T, MODE>,
state: Arc<Mutex<State>>,
) -> Result<Self> {
Ok(Self {
notifier,
trigger,
pin,
state,
})
}
fn pressed(&self) -> bool {
self.pin.is_low()
}
}
impl<T, MODE, TR> Poller for Button<'_, T, MODE, TR>
where
T: InputPin,
MODE: InputMode,
TR: Trigger,
{
fn poll(&mut self) -> Result<!> {
loop {
if self.pressed() {
self.notifier.notify(self.trigger)?;
self.toggle()?;
sleep(500);
}
yield_now();
}
}
}
impl<T, MODE, TR> Switch for Button<'_, T, MODE, TR>
where
T: InputPin,
MODE: InputMode,
TR: Trigger,
{
fn toggle(&mut self) -> Result<()> {
let mut state = self
.state
.lock()
.map_err(|e| anyhow!("Mutex lock error: {:?}", e))?;
state.toggle();
Ok(())
}
}