use core::any::Any;
use core::cell::Cell;
use crate::hal::generic::callback::IsrCallback;
use crate::hal::generic::port::{InterruptMode, Pin, PinIsrCallback, PinMode};
use crate::{isr_cb_invoke, panic_if_none};
use crate::util::OwnOrBorrowMut;
pub struct Debouncer<P>
where
P: 'static + Pin
{
pin: OwnOrBorrowMut<'static,P>,
last_event_state: Cell<Option<bool>>,
handler: Cell<PinIsrCallback<Self>>
}
impl<P> Debouncer<P>
where
P: 'static + Pin
{
pub fn using<OP: Into<OwnOrBorrowMut<'static, P>>>(pin: OP) -> Self {
let pin : OwnOrBorrowMut<P> = pin.into();
Debouncer {
pin,
last_event_state: Cell::new(Option::None),
handler: Cell::new(IsrCallback::Nop(()))
}
}
pub fn with_pin(pin: &'static mut P) -> Self {
Self::using(pin)
}
}
impl<P> Pin for Debouncer<P>
where
P: 'static + Pin
{
fn set_mode(&self, mode: PinMode) {
self.pin.set_mode(mode)
}
fn toggle(&self) {
self.pin.toggle()
}
fn set_high(&self) {
self.pin.set_high()
}
fn set_low(&self) {
self.pin.set_low()
}
fn set(&self, high: bool) {
self.pin.set(high)
}
fn get(&self) -> bool {
let mut state : u8 = 0b10101010;
while (state != 0x00) && (state != 0xff) {
state <<= 1;
state |= match self.pin.get() { false => 0, true => 1};
}
match state {
0xff => true,
0x00 => false,
_ => panic!()
}
}
fn set_interrupt_mode(&self, mode: InterruptMode) {
self.pin.set_interrupt_mode(mode)
}
fn listen(&'static self, handler: PinIsrCallback<Self>) {
self.handler.replace(handler);
if self.last_event_state.get().is_none() {
self.last_event_state.replace(Some(self.get()));
}
self.pin.listen(IsrCallback::WithData(|_source,id,_state,udata|{
let myself = unsafe { &*(panic_if_none!(udata) as *const Self) };
let old_state = panic_if_none!(myself.last_event_state.get());
let new_state = myself.get();
if old_state != new_state {
myself.last_event_state.replace(Some(new_state));
isr_cb_invoke!(myself.handler.get(), myself, id, new_state);
}
}, self as &dyn Any));
}
}