use core::cmp::Ordering; use core::marker::Unsize; use core::ptr; use cortex_m::peripheral::{DWT, SCB, SYST}; use heapless::binary_heap::{BinaryHeap, Min}; pub use heapless::ring_buffer::{Consumer, Producer, RingBuffer}; use untagged_option::UntaggedOption; #[derive(Clone, Copy)] pub struct Message { // relative to the TimerQueue baseline pub deadline: u32, pub task: T, pub payload: usize, } impl Message { fn new

(dl: u32, task: T, payload: Payload

) -> Self { Message { deadline: dl, task, payload: payload.erase(), } } } impl PartialEq for Message { fn eq(&self, other: &Self) -> bool { self.deadline.eq(&other.deadline) } } impl Eq for Message {} impl PartialOrd for Message { fn partial_cmp(&self, other: &Self) -> Option { self.deadline.partial_cmp(&other.deadline) } } impl Ord for Message { fn cmp(&self, other: &Self) -> Ordering { self.deadline.cmp(&other.deadline) } } pub struct TimerQueue where A: Unsize<[Message]>, { pub syst: SYST, pub baseline: u32, pub queue: BinaryHeap, A, Min>, } impl TimerQueue where A: Unsize<[Message]>, { pub fn new(syst: SYST) -> Self { TimerQueue { baseline: 0, queue: BinaryHeap::new(), syst, } } pub fn insert

( &mut self, bl: u32, after: u32, task: T, payload: P, slot: Slot

, ) -> Result<(), (P, Slot

)> { if self.queue.len() == self.queue.capacity() { Err((payload, slot)) } else { if self.queue.is_empty() { self.baseline = bl; } let dl = bl.wrapping_add(after).wrapping_sub(self.baseline); if self.queue.peek().map(|m| dl < m.deadline).unwrap_or(true) { // the new message is the most urgent; set a new timeout let now = DWT::get_cycle_count(); if let Some(timeout) = dl.wrapping_add(self.baseline).checked_sub(now) { self.syst.disable_counter(); self.syst.set_reload(timeout); self.syst.clear_current(); self.syst.enable_counter(); } else { // message already expired, pend immediately // NOTE(unsafe) atomic write to a stateless (from the programmer PoV) register unsafe { (*SCB::ptr()).icsr.write(1 << 26) } } } self.queue .push(Message::new(dl, task, slot.write(payload))) .unwrap_or_else(|_| unreachable!()); Ok(()) } } } pub struct Node where T: 'static, { data: UntaggedOption, next: Option<&'static mut Node>, } impl Node { pub const fn new() -> Self { Node { data: UntaggedOption::none(), next: None, } } } pub struct Payload where T: 'static, { node: &'static mut Node, } impl Payload { pub unsafe fn from(ptr: usize) -> Self { Payload { node: &mut *(ptr as *mut _), } } pub fn erase(self) -> usize { self.node as *mut _ as usize } pub fn read(self) -> (T, Slot) { unsafe { let payload = ptr::read(&self.node.data.some); (payload, Slot::new(self.node)) } } } pub struct Slot where T: 'static, { node: &'static mut Node, } impl Slot { pub fn new(node: &'static mut Node) -> Self { Slot { node } } pub fn write(self, data: T) -> Payload { unsafe { ptr::write(&mut self.node.data.some, data); Payload { node: self.node } } } } pub struct FreeList where T: 'static, { head: Option>, } impl FreeList { pub const fn new() -> Self { FreeList { head: None } } pub fn is_empty(&self) -> bool { self.head.is_none() } pub fn pop(&mut self) -> Option> { self.head.take().map(|head| { self.head = head.node.next.take().map(Slot::new); head }) } pub fn push(&mut self, free: Slot) { free.node.next = self.head.take().map(|slot| slot.node); self.head = Some(Slot::new(free.node)); } }