use super::{Timer, TimerOverflow};
use drone_core::thread::{RoutineFuture, RoutineStreamUnit};
use reg::prelude::*;
use reg::stk;
use thread::irq::IrqSysTick;
use thread::prelude::*;
pub struct SysTick<T: Thread, I: IrqSysTick> {
tokens: SysTickTokens<T, I, Ftt>,
}
#[allow(missing_docs)]
pub struct SysTickTokens<T: Thread, I: IrqSysTick, R: RegTag> {
pub sys_tick: ThreadToken<T, I>,
pub stk_ctrl: stk::Ctrl<R>,
pub stk_load: stk::Load<Stt>,
pub stk_val: stk::Val<Stt>,
}
#[macro_export]
macro_rules! peripheral_sys_tick {
($thrd:ident, $regs:ident) => {
$crate::peripherals::timer::SysTick::new(
$crate::peripherals::timer::SysTickTokens {
sys_tick: $thrd.sys_tick,
stk_ctrl: $regs.stk_ctrl,
stk_load: $regs.stk_load,
stk_val: $regs.stk_val,
}
)
}
}
#[allow(missing_docs)]
impl<T: Thread, I: IrqSysTick> SysTick<T, I> {
#[inline(always)]
pub fn irq(&self) -> ThreadToken<T, I> {
self.tokens.sys_tick
}
#[inline(always)]
pub fn ctrl(&self) -> &stk::Ctrl<Ftt> {
&self.tokens.stk_ctrl
}
#[inline(always)]
pub fn load(&self) -> &stk::Load<Stt> {
&self.tokens.stk_load
}
#[inline(always)]
pub fn val(&self) -> &stk::Val<Stt> {
&self.tokens.stk_val
}
fn interval_stream<F, S>(
&mut self,
duration: u32,
mut ctrl_val: stk::ctrl::Val,
f: F,
) -> S
where
F: FnOnce(ThreadToken<T, I>) -> S,
S: Stream,
{
ctrl_val = disable(&mut self.tokens.stk_ctrl.hold(ctrl_val)).val();
self.tokens.stk_ctrl.store_val(ctrl_val);
schedule(&self.tokens.stk_load, &self.tokens.stk_val, duration);
let stream = f(self.tokens.sys_tick);
ctrl_val = enable(&mut self.tokens.stk_ctrl.hold(ctrl_val)).val();
self.tokens.stk_ctrl.store_val(ctrl_val);
stream
}
}
impl<T: Thread, I: IrqSysTick> From<SysTick<T, I>>
for SysTickTokens<T, I, Ftt> {
#[inline(always)]
fn from(sys_tick: SysTick<T, I>) -> Self {
sys_tick.tokens
}
}
impl<T: Thread, I: IrqSysTick> Timer for SysTick<T, I> {
type InputTokens = SysTickTokens<T, I, Stt>;
type Tokens = SysTickTokens<T, I, Ftt>;
type Duration = u32;
type Ctrl = stk::Ctrl<Ftt>;
#[inline(always)]
fn new(tokens: SysTickTokens<T, I, Stt>) -> Self {
Self {
tokens: SysTickTokens {
sys_tick: tokens.sys_tick,
stk_ctrl: tokens.stk_ctrl.into(),
stk_load: tokens.stk_load,
stk_val: tokens.stk_val,
},
}
}
fn sleep(
&mut self,
duration: Self::Duration,
mut ctrl_val: <Self::Ctrl as Reg<Ftt>>::Val,
) -> RoutineFuture<(), !> {
ctrl_val = disable(&mut self.tokens.stk_ctrl.hold(ctrl_val)).val();
self.tokens.stk_ctrl.store_val(ctrl_val);
schedule(&self.tokens.stk_load, &self.tokens.stk_val, duration);
let ctrl = self.tokens.stk_ctrl.fork();
let future = self.tokens.sys_tick.future_fn(move || {
ctrl.store_val(ctrl_val);
Ok(())
});
ctrl_val = enable(&mut self.tokens.stk_ctrl.hold(ctrl_val)).val();
self.tokens.stk_ctrl.store_val(ctrl_val);
future
}
fn interval(
&mut self,
duration: Self::Duration,
ctrl_val: <Self::Ctrl as Reg<Ftt>>::Val,
) -> RoutineStreamUnit<TimerOverflow> {
self.interval_stream(duration, ctrl_val, |thread| {
thread.stream(
|| Err(TimerOverflow),
|| loop {
yield Some(());
},
)
})
}
fn interval_skip(
&mut self,
duration: Self::Duration,
ctrl_val: <Self::Ctrl as Reg<Ftt>>::Val,
) -> RoutineStreamUnit<!> {
self.interval_stream(duration, ctrl_val, |thread| {
thread.stream_skip(|| loop {
yield Some(());
})
})
}
#[inline(always)]
fn stop(&mut self, mut ctrl_val: <Self::Ctrl as Reg<Ftt>>::Val) {
ctrl_val = disable(&mut self.tokens.stk_ctrl.hold(ctrl_val)).val();
self.tokens.stk_ctrl.store_val(ctrl_val);
}
}
#[inline(always)]
fn schedule(stk_load: &stk::Load<Stt>, stk_val: &stk::Val<Stt>, duration: u32) {
stk_load.reset(|r| r.write_reload(duration));
stk_val.reset(|r| r.write_current(0));
}
#[inline(always)]
fn enable<'a, 'b>(
ctrl: &'a mut stk::ctrl::Hold<'b, Ftt>,
) -> &'a mut stk::ctrl::Hold<'b, Ftt> {
ctrl.set_enable().set_tickint()
}
#[inline(always)]
fn disable<'a, 'b>(
ctrl: &'a mut stk::ctrl::Hold<'b, Ftt>,
) -> &'a mut stk::ctrl::Hold<'b, Ftt> {
ctrl.clear_enable().clear_tickint()
}