/src/timer.rs
use core::cmp::Ordering;
use cortex_m::interrupt;
use cortex_m::peripheral::SYST;
use cortex_m_rt::exception;
use atsam3xa_hal::timer::Ms;
use embedded_hal::timer::CountDown;
type TimeValue = u32;
#[derive(Clone, Copy, Eq)]
struct TimerCallback {
tt: TimeValue,
f: fn(),
}
impl Ord for TimerCallback {
fn cmp(&self, other: &Self) -> Ordering {
self.tt.cmp(&other.tt)
}
}
impl PartialOrd for TimerCallback {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for TimerCallback {
fn eq(&self, other: &Self) -> bool {
self.tt == other.tt
}
}
struct Timer {
systick: atsam3xa_hal::timer::Timer<SYST>,
t: TimeValue,
callbacks: [Option<TimerCallback>; 10],
}
impl Timer {
fn new(mut systick: atsam3xa_hal::timer::Timer<SYST>) -> Timer {
systick.enable_interrupt();
Timer {
systick,
t: 0,
callbacks: [None; 10],
}
}
fn add_callback(&mut self, dt: TimeValue, f: fn()) {
let new_index = match self.callbacks.iter().position(|&x| x.is_none()) {
Some(i) => i,
None => panic!("Cannot schedule timer callback; too many callbacks in flight"),
};
let tt = self.t + dt;
self.callbacks[new_index] = Some(TimerCallback { tt, f });
self.recalculate();
}
fn recalculate(&mut self) {
self.callbacks.sort_by(|&a, &b| {
match (a, b) {
(Some(i), Some(j)) => i.cmp(&j),
(Some(_), None) => Ordering::Less,
(None, Some(_)) => Ordering::Greater,
(None, None) => Ordering::Equal,
}
});
if let Some(_) = self.callbacks[0] {
self.systick.start(1 as Ms);
} else {
self.systick.stop();
self.t = 0;
}
}
fn tick(&mut self) {
self.t += 1;
if !self.callbacks[0].is_none() {
let timer_expired = {
let tc = self.callbacks[0].as_ref().unwrap();
tc.tt <= self.t
};
if timer_expired {
let tc = self.callbacks[0].take().unwrap();
(tc.f)();
self.recalculate();
}
}
}
}
static mut TIMER: Option<Timer> = None;
pub fn start(systick: atsam3xa_hal::timer::Timer<SYST>) {
interrupt::free(|_| unsafe {
TIMER = Some(Timer::new(systick));
});
}
pub fn schedule(d: TimeValue, f: fn()) {
interrupt::free(|_| unsafe {
let timer = TIMER.as_mut().expect("Timer not yet initialized");
timer.add_callback(d, f);
});
}
#[exception]
fn SysTick() {
interrupt::free(|_| unsafe {
let timer = TIMER.as_mut().expect("Timer not yet initialized");
timer.tick();
});
}