1use crate::Monotonic;
2use core::cmp::Ordering;
3use heapless::sorted_linked_list::{LinkedIndexU16, Min, SortedLinkedList};
4
5pub struct TimerQueue<Mono, Task, const N: usize>(
6 pub SortedLinkedList<NotReady<Mono, Task>, LinkedIndexU16, Min, N>,
7)
8where
9 Mono: Monotonic,
10 Task: Copy;
11
12impl<Mono, Task, const N: usize> TimerQueue<Mono, Task, N>
13where
14 Mono: Monotonic,
15 Task: Copy,
16{
17 #[inline]
24 pub unsafe fn enqueue_unchecked<F1, F2>(
25 &mut self,
26 nr: NotReady<Mono, Task>,
27 enable_interrupt: F1,
28 pend_handler: F2,
29 mono: Option<&mut Mono>,
30 ) where
31 F1: FnOnce(),
32 F2: FnOnce(),
33 {
34 let if_heap_max_greater_than_nr =
37 self.0.peek().map_or(true, |head| nr.instant < head.instant);
38
39 if if_heap_max_greater_than_nr {
40 if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE && self.0.is_empty() {
41 if let Some(mono) = mono {
42 mono.enable_timer();
43 }
44 enable_interrupt();
45 }
46
47 pend_handler();
48 }
49
50 self.0.push_unchecked(nr);
51 }
52
53 #[inline]
55 pub fn is_empty(&self) -> bool {
56 self.0.is_empty()
57 }
58
59 pub fn cancel_marker(&mut self, marker: u32) -> Option<(Task, u8)> {
61 if let Some(val) = self.0.find_mut(|nr| nr.marker == marker) {
62 let nr = val.pop();
63
64 Some((nr.task, nr.index))
65 } else {
66 None
67 }
68 }
69
70 #[allow(clippy::result_unit_err)]
72 pub fn update_marker<F: FnOnce()>(
73 &mut self,
74 marker: u32,
75 new_marker: u32,
76 instant: Mono::Instant,
77 pend_handler: F,
78 ) -> Result<(), ()> {
79 if let Some(mut val) = self.0.find_mut(|nr| nr.marker == marker) {
80 val.instant = instant;
81 val.marker = new_marker;
82
83 pend_handler();
85
86 Ok(())
87 } else {
88 Err(())
89 }
90 }
91
92 pub fn dequeue<F>(&mut self, disable_interrupt: F, mono: &mut Mono) -> Option<(Task, u8)>
94 where
95 F: FnOnce(),
96 {
97 mono.clear_compare_flag();
98
99 if let Some(instant) = self.0.peek().map(|p| p.instant) {
100 if instant <= mono.now() {
101 let nr = unsafe { self.0.pop_unchecked() };
103
104 Some((nr.task, nr.index))
105 } else {
106 mono.set_compare(instant);
108
109 if instant <= mono.now() {
114 let nr = unsafe { self.0.pop_unchecked() };
115
116 Some((nr.task, nr.index))
117 } else {
118 None
119 }
120 }
121 } else {
122 if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
124 disable_interrupt();
125 mono.disable_timer();
126 }
127
128 None
129 }
130 }
131}
132
133pub struct NotReady<Mono, Task>
134where
135 Task: Copy,
136 Mono: Monotonic,
137{
138 pub index: u8,
139 pub instant: Mono::Instant,
140 pub task: Task,
141 pub marker: u32,
142}
143
144impl<Mono, Task> Eq for NotReady<Mono, Task>
145where
146 Task: Copy,
147 Mono: Monotonic,
148{
149}
150
151impl<Mono, Task> Ord for NotReady<Mono, Task>
152where
153 Task: Copy,
154 Mono: Monotonic,
155{
156 fn cmp(&self, other: &Self) -> Ordering {
157 self.instant.cmp(&other.instant)
158 }
159}
160
161impl<Mono, Task> PartialEq for NotReady<Mono, Task>
162where
163 Task: Copy,
164 Mono: Monotonic,
165{
166 fn eq(&self, other: &Self) -> bool {
167 self.instant == other.instant
168 }
169}
170
171impl<Mono, Task> PartialOrd for NotReady<Mono, Task>
172where
173 Task: Copy,
174 Mono: Monotonic,
175{
176 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
177 Some(self.cmp(other))
178 }
179}