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::concurrency::interrupt;
use avr_oxide::{halt_if_none, thread};
use avr_oxide::private::delayq::{DelayQueue, SimpleDelayQueue};
use avr_oxide::sync::EventWait;
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>,
delay_events: RefCell<SimpleDelayQueue<Duration,DelayResponder<'mc>>>,
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> {
type DelayHandle;
fn after_delay(&self, delay: Duration, bf: Box<dyn DelayCallback + 'c>) -> Self::DelayHandle;
fn cancel_delay(&self, handle: Self::DelayHandle) -> bool;
}
pub(crate) enum DelayResponder<'mc> {
WaitingThread(EventWait),
HandlerCallback(Box<dyn DelayCallback + 'mc>)
}
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;
if FREQ_HZ > MASTER_TICK_FREQ_HZ {
avr_oxide::oserror::halt(avr_oxide::oserror::OsError::BadParams);
}
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),
delay_events: RefCell::new(SimpleDelayQueue::new())
}
}
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)))
}
pub fn wait(&self, delay: Duration){
interrupt::isolated(|isotoken|{
let mut waiter = EventWait::new();
waiter.add_to_waitlist(isotoken);
self.delay_events.borrow_mut().insert_at(delay.saturating_add(Duration::MILLISECOND),
DelayResponder::WaitingThread(waiter));
});
thread::yield_now();
}
}
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<'mc,T,S> DelayEvents<'mc> for MasterClock<'mc,T,S>
where
T: 'static + TimerControl,
S: EventSink
{
type DelayHandle = avr_oxide::private::delayq::DelayQueueHandle;
fn after_delay(&self, delay: Duration, bf: Box<dyn DelayCallback + 'mc>) -> Self::DelayHandle {
self.delay_events.borrow_mut().insert_at(delay.saturating_add(Duration::MILLISECOND), DelayResponder::HandlerCallback(bf))
}
fn cancel_delay(&self, handle: Self::DelayHandle) -> bool {
self.delay_events.borrow_mut().remove(handle)
}
}
impl<T,S> EventSource for MasterClock<'_,T,S>
where
T: 'static + TimerControl,
S: EventSink
{
fn listen(&'static self) {
self.timer.start(TimerIsrCallback::WithData(|isotoken, source, _ticks, udata| {
S::event(isotoken, OxideEventEnvelope::to(unsafe { &*(halt_if_none!(udata, avr_oxide::oserror::OsError::InternalError) as *const MasterClock<T,S> as *const dyn EventSource) },
OxideEvent::ClockTick(source, 1)));
true
}, self as *const dyn core::any::Any ));
}
fn process_event(&self, evt: OxideEvent) {
match (self.on_tick.borrow_mut().deref_mut(), evt) {
(Some(f), OxideEvent::ClockTick(source, ticks)) => {
let time_passed = Duration::from_millis((1000u32 / self.freq_hz as u32) * ticks as u32);
self.delay_events.borrow_mut().decrement(time_passed);
while let Some(mut handler) = self.delay_events.borrow_mut().consume_next_ready() {
match &mut handler {
DelayResponder::WaitingThread(eventwait) => {
eventwait.release_all()
},
DelayResponder::HandlerCallback(handler) => {
(*handler)(source)
}
}
}
(*f)(source,time_passed);
},
_ => {}
}
}
}
unsafe impl<T,S> Send for MasterClock<'_,T,S>
where
T: 'static + TimerControl,
S: EventSink
{}
unsafe impl<T,S> Sync for MasterClock<'_,T,S>
where
T: 'static + TimerControl,
S: EventSink
{}