use core::marker::PhantomData;
use embedded_hal::digital::InputPin;
use embedded_time::duration::Milliseconds;
use embedded_time::{Clock, Instant};
pub trait Switch<C: Clock> {
fn reset(&mut self);
fn poll(&mut self, now: Instant<C>);
fn has_changed(&self) -> bool;
fn is_pressed(&self) -> bool;
fn is_released(&self) -> bool;
fn pressed_for(&self) -> Option<Milliseconds<C::T>>;
fn released_for(&self) -> Option<Milliseconds<C::T>>;
fn prev_state_lasted_for(&self) -> Milliseconds<C::T>;
fn current_state(&self, now: Instant<C>) -> Milliseconds<C::T>;
fn wait(&mut self, clock: &C);
}
pub mod switch_state {
use embedded_hal::digital::InputPin;
pub trait PressedState {
fn get_pressed_state<P: InputPin>(pin: &mut P) -> bool;
}
pub struct PressedOnHigh {}
pub struct PressedOnLow {}
impl PressedState for PressedOnHigh {
fn get_pressed_state<P: InputPin>(pin: &mut P) -> bool {
pin.is_high().unwrap()
}
}
impl PressedState for PressedOnLow {
fn get_pressed_state<P: InputPin>(pin: &mut P) -> bool {
pin.is_low().unwrap()
}
}
}
pub struct PinSwitch<P: InputPin, S: switch_state::PressedState, C: Clock> {
pin: P,
is_pressed: bool,
has_changed: bool,
last_change_at: Instant<C>,
prev_state_lasted: Milliseconds<C::T>,
pressed_state: PhantomData<S>,
}
impl<P: InputPin, S: switch_state::PressedState, C: Clock> PinSwitch<P, S, C> {
pub fn new(pin: P) -> Self {
Self {
pin,
is_pressed: false,
has_changed: false,
last_change_at: Instant::<C>::new(C::T::from(0)),
prev_state_lasted: Milliseconds::<C::T>::new(C::T::from(0)),
pressed_state: Default::default(),
}
}
}
impl<P: InputPin, S: switch_state::PressedState, C: Clock> Switch<C> for PinSwitch<P, S, C> {
fn poll(&mut self, now: Instant<C>) {
let new_state = S::get_pressed_state(&mut self.pin);
if new_state == self.is_pressed {
self.has_changed = false;
return;
}
self.is_pressed = new_state;
self.has_changed = true;
self.prev_state_lasted = self.current_state(now);
self.last_change_at = now;
}
fn has_changed(&self) -> bool {
self.has_changed
}
fn is_pressed(&self) -> bool {
self.is_pressed
}
fn is_released(&self) -> bool {
!self.is_pressed
}
fn pressed_for(&self) -> Option<Milliseconds<C::T>> {
if !self.is_pressed {
return Some(self.prev_state_lasted);
}
None
}
fn released_for(&self) -> Option<Milliseconds<C::T>> {
if self.is_pressed {
return Some(self.prev_state_lasted);
}
None
}
fn wait(&mut self, clock: &C) {
loop {
self.poll(clock.try_now().unwrap());
if self.has_changed {
break;
}
}
}
fn reset(&mut self) {
self.last_change_at = Instant::<C>::new(C::T::from(0));
self.prev_state_lasted = Milliseconds::<C::T>::new(C::T::from(0));
self.has_changed = false;
self.is_pressed = false;
}
fn prev_state_lasted_for(&self) -> Milliseconds<<C as Clock>::T> {
self.prev_state_lasted
}
fn current_state(&self, now: Instant<C>) -> Milliseconds<<C as Clock>::T> {
now
.checked_duration_since(&self.last_change_at)
.unwrap()
.try_into()
.unwrap()
}
}