use core::any::Any;
use core::cell::Cell;
use avr_oxide::alloc::boxed::Box;
use avr_oxide::hal::generic::callback::IsrCallback;
use avr_oxide::hal::generic::port::{InterruptMode, Pin, PinIsrCallback, PinMode};
use avr_oxide::{isr_cb_invoke, halt_if_none};
use avr_oxide::devices::UsesPin;
use avr_oxide::util::OwnOrBorrow;
use avr_oxide::devices::internal::StaticShareable;
pub struct Inverter {
pin: OwnOrBorrow<'static,dyn Pin>,
handler: Cell<PinIsrCallback>
}
impl StaticShareable for Inverter {}
impl Into<OwnOrBorrow<'static, dyn Pin + 'static>> for Inverter {
fn into(self) -> OwnOrBorrow<'static, dyn Pin> {
OwnOrBorrow::Own(Box::new(self))
}
}
impl UsesPin for Inverter {
fn using<OP: Into<OwnOrBorrow<'static, dyn Pin>>>(pin: OP) -> Self {
let pin : OwnOrBorrow<dyn Pin> = pin.into();
Inverter {
pin,
handler: Cell::new(IsrCallback::Nop(()))
}
}
}
impl Pin for Inverter {
fn set_mode(&self, mode: PinMode) {
self.pin.set_mode(mode)
}
fn toggle(&self) {
self.pin.toggle()
}
fn set_high(&self) {
self.pin.set_low()
}
fn set_low(&self) {
self.pin.set_high()
}
fn set(&self, high: bool) {
self.pin.set(!high)
}
fn get(&self) -> bool {
!self.pin.get()
}
fn set_interrupt_mode(&self, mode: InterruptMode) {
self.pin.set_interrupt_mode(mode)
}
fn listen(&'static self, handler: PinIsrCallback) {
self.handler.replace(handler);
self.pin.listen(IsrCallback::WithData(|isotoken,_source,id,state,udata|{
let myself = unsafe { &*(halt_if_none!(udata, avr_oxide::oserror::OsError::InternalError) as *const Self) };
isr_cb_invoke!(isotoken, myself.handler.get(), myself, id, !state);
}, self as &dyn Any));
}
}