systick_timer/
embassy_driver.rs1use core::cell::RefCell;
4use cortex_m::{
5 interrupt::{self, Mutex},
6 peripheral::SYST,
7};
8
9struct Wakeup {
10 wakeup_at: u64,
11 waker: core::task::Waker,
12}
13
14fn schedule_wake_into_slots<const N: usize>(
17 slots: &mut [Option<Wakeup>; N],
18 at: u64,
19 waker: &core::task::Waker,
20) -> bool {
21 let mut empty_idx: Option<usize> = None;
22
23 for (i, slot) in slots.iter().enumerate() {
25 if let Some(wakeup) = slot {
26 if wakeup.waker.will_wake(waker) && wakeup.wakeup_at == at {
27 return true;
29 }
30 } else if empty_idx.is_none() {
31 empty_idx = Some(i);
32 }
33 }
34
35 if let Some(i) = empty_idx {
37 slots[i] = Some(Wakeup {
38 wakeup_at: at,
39 waker: waker.clone(),
40 });
41 true
42 } else {
43 false
44 }
45}
46
47pub struct SystickDriver<const N: usize> {
59 wakeup_at: Mutex<RefCell<[Option<Wakeup>; N]>>,
60 timer: crate::Timer,
61}
62
63impl<const N: usize> SystickDriver<N> {
64 pub const fn new(systick_freq: u64, reload_value: u32) -> Self {
74 let timer = crate::Timer::new(embassy_time_driver::TICK_HZ, reload_value, systick_freq);
75 Self {
76 wakeup_at: Mutex::new(RefCell::new([const { None }; N])),
77 timer: timer,
78 }
79 }
80
81 pub const fn new_default(systick_freq: u64) -> Self {
91 let reload = (systick_freq / embassy_time_driver::TICK_HZ) - 1;
92 Self::new(systick_freq, reload as u32)
93 }
94
95 fn maybe_wake(&self) {
96 interrupt::free(|cs| {
97 let mutex_borrow = &self.wakeup_at.borrow(cs);
98 for slot in mutex_borrow.borrow_mut().iter_mut() {
99 let mut cleared = false;
100 if let Some(wakeup) = slot {
101 if self.timer.now() >= wakeup.wakeup_at {
102 wakeup.waker.wake_by_ref();
103 cleared = true;
104 }
105 }
106 if cleared {
107 *slot = None;
108 }
109 }
110 })
111 }
112
113 pub fn start(&self, syst: &mut SYST) {
114 self.timer.start(syst);
115 }
116
117 pub fn systick_interrupt(&self) {
119 self.timer.systick_handler();
120 self.maybe_wake();
121 }
122}
123
124impl<const N: usize> embassy_time_driver::Driver for SystickDriver<N> {
125 fn now(&self) -> u64 {
126 self.timer.now()
127 }
128
129 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
130 interrupt::free(|cs| {
131 let mutex_borrow = self.wakeup_at.borrow(cs);
132 let mut wakeups = mutex_borrow.borrow_mut();
133 if !schedule_wake_into_slots(&mut *wakeups, at, waker) {
134 panic!("No free wakeup slots");
135 }
136 })
137 }
138}
139
140#[cfg(feature = "embassy-defaults")]
141embassy_time_driver::time_driver_impl!(static DRIVER: SystickDriver<4> = SystickDriver::new(8_000_000, 7_999));
142
143#[cfg(feature = "embassy-defaults")]
144#[cortex_m_rt::exception]
145fn SysTick() {
146 DRIVER.systick_interrupt();
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use std::sync::Arc;
153 use std::task::Wake;
154
155 struct TestWake;
157
158 impl Wake for TestWake {
159 fn wake(self: Arc<Self>) {}
160 }
161
162 fn make_waker() -> core::task::Waker {
163 Arc::new(TestWake).into()
164 }
165
166 fn make_distinct_waker() -> core::task::Waker {
167 Arc::new(TestWake).into()
169 }
170
171 fn count_occupied<const N: usize>(slots: &[Option<Wakeup>; N]) -> usize {
172 slots.iter().filter(|s| s.is_some()).count()
173 }
174
175 #[test]
176 fn test_basic_insert() {
177 let mut slots: [Option<Wakeup>; 4] = [const { None }; 4];
178 let waker = make_waker();
179
180 let result = schedule_wake_into_slots(&mut slots, 100, &waker);
181 assert!(result);
182 assert_eq!(count_occupied(&slots), 1);
183 }
184
185 #[test]
186 fn test_duplicate_detection_same_waker_same_time() {
187 let mut slots: [Option<Wakeup>; 4] = [const { None }; 4];
188 let waker = make_waker();
189
190 assert!(schedule_wake_into_slots(&mut slots, 100, &waker));
192 assert_eq!(count_occupied(&slots), 1);
193
194 assert!(schedule_wake_into_slots(&mut slots, 100, &waker));
196 assert_eq!(count_occupied(&slots), 1); }
198
199 #[test]
200 fn test_different_times_same_waker_creates_separate_slots() {
201 let mut slots: [Option<Wakeup>; 4] = [const { None }; 4];
202 let waker = make_waker();
203
204 schedule_wake_into_slots(&mut slots, 100, &waker);
205 schedule_wake_into_slots(&mut slots, 200, &waker);
206
207 assert_eq!(count_occupied(&slots), 2);
208 }
209
210 #[test]
211 fn test_different_wakers_same_time_creates_separate_slots() {
212 let mut slots: [Option<Wakeup>; 4] = [const { None }; 4];
213 let waker1 = make_distinct_waker();
214 let waker2 = make_distinct_waker();
215
216 schedule_wake_into_slots(&mut slots, 100, &waker1);
217 schedule_wake_into_slots(&mut slots, 100, &waker2);
218
219 assert_eq!(count_occupied(&slots), 2);
220 }
221
222 #[test]
226 fn test_duplicate_detection_with_hole_before_existing() {
227 let mut slots: [Option<Wakeup>; 4] = [const { None }; 4];
228 let waker = make_waker();
229
230 slots[1] = Some(Wakeup {
232 wakeup_at: 100,
233 waker: waker.clone(),
234 });
235 assert_eq!(count_occupied(&slots), 1);
236
237 let result = schedule_wake_into_slots(&mut slots, 100, &waker);
239 assert!(result); assert_eq!(count_occupied(&slots), 1); assert!(slots[0].is_none());
244 }
245
246 #[test]
248 fn test_duplicate_detection_with_multiple_holes() {
249 let mut slots: [Option<Wakeup>; 4] = [const { None }; 4];
250 let waker = make_waker();
251
252 slots[3] = Some(Wakeup {
254 wakeup_at: 100,
255 waker: waker.clone(),
256 });
257
258 let result = schedule_wake_into_slots(&mut slots, 100, &waker);
259 assert!(result);
260 assert_eq!(count_occupied(&slots), 1);
261 }
262
263 #[test]
265 fn test_fills_first_available_hole() {
266 let mut slots: [Option<Wakeup>; 4] = [const { None }; 4];
267 let waker1 = make_distinct_waker();
268 let waker2 = make_distinct_waker();
269
270 slots[1] = Some(Wakeup {
272 wakeup_at: 100,
273 waker: waker1.clone(),
274 });
275
276 let result = schedule_wake_into_slots(&mut slots, 100, &waker2);
278 assert!(result);
279 assert_eq!(count_occupied(&slots), 2);
280 assert!(slots[0].is_some()); }
282
283 #[test]
284 fn test_returns_false_when_full() {
285 let mut slots: [Option<Wakeup>; 2] = [const { None }; 2];
286 let waker1 = make_distinct_waker();
287 let waker2 = make_distinct_waker();
288 let waker3 = make_distinct_waker();
289
290 assert!(schedule_wake_into_slots(&mut slots, 100, &waker1));
291 assert!(schedule_wake_into_slots(&mut slots, 100, &waker2));
292 assert!(!schedule_wake_into_slots(&mut slots, 100, &waker3)); }
294
295 #[test]
297 fn test_repeated_polling_scenario() {
298 let mut slots: [Option<Wakeup>; 4] = [const { None }; 4];
299 let waker = make_waker();
300
301 for _ in 0..100 {
303 schedule_wake_into_slots(&mut slots, 1000, &waker);
304 }
305
306 assert_eq!(count_occupied(&slots), 1);
308 }
309}