use crate::{time::Instant, Monotonic}; use core::cmp::Ordering; use heapless::{binary_heap::Min, ArrayLength, BinaryHeap}; pub struct TimerQueue(pub BinaryHeap, N, Min>) where M: Monotonic, N: ArrayLength>, T: Copy; impl TimerQueue where M: Monotonic, N: ArrayLength>, T: Copy, { /// # Safety /// /// Writing to memory with a transmute in order to enable /// interrupts of the SysTick timer /// /// Enqueue a task without checking if it is full #[inline] pub unsafe fn enqueue_unchecked( &mut self, nr: NotReady, enable_interrupt: F1, pend_handler: F2, ) where F1: FnOnce(), F2: FnOnce(), { let mut is_empty = true; // Check if the top contains a non-empty element and if that element is // greater than nr let if_heap_max_greater_than_nr = self .0 .peek() .map(|head| { is_empty = false; nr.instant < head.instant }) .unwrap_or(true); if if_heap_max_greater_than_nr { if is_empty { // mem::transmute::<_, SYST>(()).enable_interrupt(); enable_interrupt(); } // Set SysTick pending // SCB::set_pendst(); pend_handler(); } self.0.push_unchecked(nr); } /// Check if the timer queue is empty. #[inline] pub fn is_empty(&self) -> bool { self.0.is_empty() } /// Dequeue a task from the TimerQueue #[inline] pub fn dequeue(&mut self, disable_interrupt: F) -> Option<(T, u8)> where F: FnOnce(), { unsafe { M::clear_compare(); if let Some(instant) = self.0.peek().map(|p| p.instant) { let now = M::now(); match instant.checked_duration_since(&now) { None => { // instant < now // task became ready let nr = self.0.pop_unchecked(); Some((nr.task, nr.index)) } Some(_) => { // TODO: Fix this hack... // Extract the compare time let new_instant = *instant.duration_since_epoch().integer(); M::set_compare(new_instant); // Start counting down from the new reload // mem::transmute::<_, SYST>(()).clear_current(); None } } } else { // The queue is empty // mem::transmute::<_, SYST>(()).disable_interrupt(); disable_interrupt(); None } } } } pub struct NotReady where T: Copy, M: Monotonic, { pub index: u8, pub instant: Instant, pub task: T, } impl Eq for NotReady where T: Copy, M: Monotonic, { } impl Ord for NotReady where T: Copy, M: Monotonic, { fn cmp(&self, other: &Self) -> Ordering { self.instant.cmp(&other.instant) } } impl PartialEq for NotReady where T: Copy, M: Monotonic, { fn eq(&self, other: &Self) -> bool { self.instant == other.instant } } impl PartialOrd for NotReady where T: Copy, M: Monotonic, { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(&other)) } }