use avr_oxide::hal::generic::timer::{TimerControl, TimerIdentity, TimerIsrCallback};
use avr_oxide::hal::generic::timer::TimerMode::Periodic;
use avr_oxide::event::{EventSink, EventSource, OxideEvent, OxideEventEnvelope};
use avr_oxide::devices::internal::StaticShareable;
use avr_oxide::deviceconsts::clock::{ MASTER_CLOCK_PRESCALER, MASTER_CLOCK_HZ, MASTER_TICK_FREQ_HZ };
use core::marker::PhantomData;
use core::ops::DerefMut;
use core::cell::RefCell;
use avr_oxide::alloc::boxed::Box;
use avr_oxide::panic_if_none;
use avr_oxide::util::OwnOrBorrowMut;
use avr_oxide::time::Duration;
pub trait TickCallback = FnMut(TimerIdentity,Duration) -> ();
pub trait DelayCallback = FnMut(TimerIdentity) -> ();
pub struct MasterClock<'mc,T,S>
where
T: 'static + TimerControl,
S: EventSink
{
freq_hz: u16,
timer: OwnOrBorrowMut<'static,T>,
phantom: PhantomData<S>,
on_tick: RefCell<Option<Box<dyn TickCallback + 'mc>>>
}
impl<'mc,T,S> StaticShareable for MasterClock<'mc,T,S>
where
T: 'static + TimerControl,
S: EventSink
{}
pub trait TickEvents<'c> {
fn on_tick(&self, bf: Box<dyn TickCallback + 'c>);
}
pub trait DelayEvents<'c> {
fn after_delay(&self, delay: Duration, bf: Box<dyn DelayCallback + 'c>);
}
impl<T, S> MasterClock<'_, T, S>
where
T: 'static + TimerControl,
S: EventSink
{
pub fn using<OT: Into<OwnOrBorrowMut<'static,T>>, const FREQ_HZ: u16>(timer: OT) -> Self {
const CYCLES_PER_TICK: u16 = (MASTER_CLOCK_HZ as u32/(2u32 * MASTER_CLOCK_PRESCALER as u32 * MASTER_TICK_FREQ_HZ as u32)) as u16;
debug_assert!(FREQ_HZ < MASTER_TICK_FREQ_HZ);
debug_assert!(FREQ_HZ > 0);
let mut timer : OwnOrBorrowMut<T> = timer.into();
timer.set_mode(Periodic);
timer.set_count_max(CYCLES_PER_TICK);
timer.set_interrupt_period((MASTER_TICK_FREQ_HZ/FREQ_HZ) as u16);
Self {
timer,
freq_hz: FREQ_HZ,
phantom: PhantomData::default(),
on_tick: RefCell::new(None)
}
}
pub fn static_using<OT: Into<OwnOrBorrowMut<'static,T>>, const FREQ_HZ: u16>(timer: OT) -> &'static mut Self {
Box::leak(Box::new(Self::using::<_,FREQ_HZ>(timer)))
}
pub fn with_timer<const FREQ_HZ: u16>(timer: &'static mut T) -> Self {
Self::using::<_, FREQ_HZ>(timer)
}
pub fn static_with_timer<const FREQ_HZ: u16>(timer: &'static mut T) -> &'static mut Self {
Box::leak(Box::new(Self::with_timer::<FREQ_HZ>(timer)))
}
}
impl<'mc, T, S> TickEvents<'mc> for MasterClock<'mc, T, S>
where
T: 'static + TimerControl,
S: EventSink
{
fn on_tick(&self, bf: Box<dyn TickCallback + 'mc>) {
self.on_tick.replace(Some(bf));
}
}
impl<T,S> EventSource for MasterClock<'_,T,S>
where
T: 'static + TimerControl,
S: EventSink
{
#[optimize(speed)]
fn listen(&'static self) {
self.timer.start(TimerIsrCallback::WithData(|source, ticks, udata| {
S::event(OxideEventEnvelope::to(unsafe { &*(panic_if_none!(udata) as *const MasterClock<T,S> as *const dyn EventSource) },
OxideEvent::ClockTick(source, ticks)));
true
}, self as *const dyn core::any::Any ));
}
#[optimize(speed)]
fn process_event(&self, evt: OxideEvent) {
match (self.on_tick.borrow_mut().deref_mut(), evt) {
(Some(f), OxideEvent::ClockTick(source, ticks)) => {
(*f)(source,Duration::from_millis((ticks as u32 * self.freq_hz as u32) / 1000u32))
},
_ => {}
}
}
}