aboutsummaryrefslogtreecommitdiff
path: root/embassy-time/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-time/src')
-rw-r--r--embassy-time/src/driver_mock.rs85
-rw-r--r--embassy-time/src/driver_std.rs121
-rw-r--r--embassy-time/src/driver_wasm.rs80
-rw-r--r--embassy-time/src/lib.rs2
-rw-r--r--embassy-time/src/queue_generic.rs346
5 files changed, 83 insertions, 551 deletions
diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs
index 8587f9172..829eb0437 100644
--- a/embassy-time/src/driver_mock.rs
+++ b/embassy-time/src/driver_mock.rs
@@ -1,7 +1,7 @@
1use core::cell::RefCell; 1use core::cell::RefCell;
2 2
3use critical_section::Mutex as CsMutex; 3use critical_section::Mutex as CsMutex;
4use embassy_time_driver::{AlarmHandle, Driver}; 4use embassy_time_driver::Driver;
5 5
6use crate::{Duration, Instant}; 6use crate::{Duration, Instant};
7 7
@@ -60,15 +60,13 @@ impl MockDriver {
60 60
61 let now = inner.now.as_ticks(); 61 let now = inner.now.as_ticks();
62 62
63 inner 63 if inner.alarm.timestamp <= now {
64 .alarm 64 inner.alarm.timestamp = u64::MAX;
65 .as_mut()
66 .filter(|alarm| alarm.timestamp <= now)
67 .map(|alarm| {
68 alarm.timestamp = u64::MAX;
69 65
70 (alarm.callback, alarm.ctx) 66 Some((inner.alarm.callback, inner.alarm.ctx))
71 }) 67 } else {
68 None
69 }
72 }) 70 })
73 }; 71 };
74 72
@@ -76,68 +74,48 @@ impl MockDriver {
76 (callback)(ctx); 74 (callback)(ctx);
77 } 75 }
78 } 76 }
79}
80
81impl Driver for MockDriver {
82 fn now(&self) -> u64 {
83 critical_section::with(|cs| self.0.borrow_ref(cs).now).as_ticks()
84 }
85
86 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
87 critical_section::with(|cs| {
88 let mut inner = self.0.borrow_ref_mut(cs);
89
90 if inner.alarm.is_some() {
91 None
92 } else {
93 inner.alarm.replace(AlarmState::new());
94
95 Some(AlarmHandle::new(0))
96 }
97 })
98 }
99 77
100 fn set_alarm_callback(&self, _alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { 78 /// Configures a callback to be called when the alarm fires.
79 pub fn set_alarm_callback(&self, callback: fn(*mut ()), ctx: *mut ()) {
101 critical_section::with(|cs| { 80 critical_section::with(|cs| {
102 let mut inner = self.0.borrow_ref_mut(cs); 81 let mut inner = self.0.borrow_ref_mut(cs);
103 82
104 let Some(alarm) = inner.alarm.as_mut() else { 83 inner.alarm.callback = callback;
105 panic!("Alarm not allocated"); 84 inner.alarm.ctx = ctx;
106 };
107
108 alarm.callback = callback;
109 alarm.ctx = ctx;
110 }); 85 });
111 } 86 }
112 87
113 fn set_alarm(&self, _alarm: AlarmHandle, timestamp: u64) -> bool { 88 /// Sets the alarm to fire at the specified timestamp.
89 pub fn set_alarm(&self, timestamp: u64) -> bool {
114 critical_section::with(|cs| { 90 critical_section::with(|cs| {
115 let mut inner = self.0.borrow_ref_mut(cs); 91 let mut inner = self.0.borrow_ref_mut(cs);
116 92
117 if timestamp <= inner.now.as_ticks() { 93 if timestamp <= inner.now.as_ticks() {
118 false 94 false
119 } else { 95 } else {
120 let Some(alarm) = inner.alarm.as_mut() else { 96 inner.alarm.timestamp = timestamp;
121 panic!("Alarm not allocated");
122 };
123
124 alarm.timestamp = timestamp;
125 true 97 true
126 } 98 }
127 }) 99 })
128 } 100 }
129} 101}
130 102
103impl Driver for MockDriver {
104 fn now(&self) -> u64 {
105 critical_section::with(|cs| self.0.borrow_ref(cs).now).as_ticks()
106 }
107}
108
131struct InnerMockDriver { 109struct InnerMockDriver {
132 now: Instant, 110 now: Instant,
133 alarm: Option<AlarmState>, 111 alarm: AlarmState,
134} 112}
135 113
136impl InnerMockDriver { 114impl InnerMockDriver {
137 const fn new() -> Self { 115 const fn new() -> Self {
138 Self { 116 Self {
139 now: Instant::from_ticks(0), 117 now: Instant::from_ticks(0),
140 alarm: None, 118 alarm: AlarmState::new(),
141 } 119 }
142 } 120 }
143} 121}
@@ -189,8 +167,7 @@ mod tests {
189 setup(); 167 setup();
190 168
191 let driver = MockDriver::get(); 169 let driver = MockDriver::get();
192 let alarm = unsafe { AlarmHandle::new(0) }; 170 assert_eq!(false, driver.set_alarm(driver.now()));
193 assert_eq!(false, driver.set_alarm(alarm, driver.now()));
194 } 171 }
195 172
196 #[test] 173 #[test]
@@ -199,23 +176,11 @@ mod tests {
199 setup(); 176 setup();
200 177
201 let driver = MockDriver::get(); 178 let driver = MockDriver::get();
202 let alarm = unsafe { driver.allocate_alarm() }.expect("No alarms available");
203 static mut CALLBACK_CALLED: bool = false; 179 static mut CALLBACK_CALLED: bool = false;
204 let ctx = &mut () as *mut (); 180 driver.set_alarm_callback(|_| unsafe { CALLBACK_CALLED = true }, core::ptr::null_mut());
205 driver.set_alarm_callback(alarm, |_| unsafe { CALLBACK_CALLED = true }, ctx); 181 driver.set_alarm(driver.now() + 1);
206 driver.set_alarm(alarm, driver.now() + 1);
207 assert_eq!(false, unsafe { CALLBACK_CALLED }); 182 assert_eq!(false, unsafe { CALLBACK_CALLED });
208 driver.advance(Duration::from_secs(1)); 183 driver.advance(Duration::from_secs(1));
209 assert_eq!(true, unsafe { CALLBACK_CALLED }); 184 assert_eq!(true, unsafe { CALLBACK_CALLED });
210 } 185 }
211
212 #[test]
213 #[serial]
214 fn test_allocate_alarm() {
215 setup();
216
217 let driver = MockDriver::get();
218 assert!(unsafe { driver.allocate_alarm() }.is_some());
219 assert!(unsafe { driver.allocate_alarm() }.is_none());
220 }
221} 186}
diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs
index cbef7aae1..45467f09b 100644
--- a/embassy-time/src/driver_std.rs
+++ b/embassy-time/src/driver_std.rs
@@ -1,53 +1,38 @@
1use core::sync::atomic::{AtomicU8, Ordering};
2use std::cell::{RefCell, UnsafeCell}; 1use std::cell::{RefCell, UnsafeCell};
3use std::mem::MaybeUninit; 2use std::mem::MaybeUninit;
4use std::sync::{Condvar, Mutex, Once}; 3use std::sync::{Condvar, Mutex, Once};
5use std::time::{Duration as StdDuration, Instant as StdInstant}; 4use std::time::{Duration as StdDuration, Instant as StdInstant};
6use std::{mem, ptr, thread}; 5use std::{ptr, thread};
7 6
8use critical_section::Mutex as CsMutex; 7use critical_section::Mutex as CsMutex;
9use embassy_time_driver::{AlarmHandle, Driver}; 8use embassy_time_driver::Driver;
10 9use embassy_time_queue_driver::GlobalTimerQueue;
11const ALARM_COUNT: usize = 4;
12 10
13struct AlarmState { 11struct AlarmState {
14 timestamp: u64, 12 timestamp: u64,
15
16 // This is really a Option<(fn(*mut ()), *mut ())>
17 // but fn pointers aren't allowed in const yet
18 callback: *const (),
19 ctx: *mut (),
20} 13}
21 14
22unsafe impl Send for AlarmState {} 15unsafe impl Send for AlarmState {}
23 16
24impl AlarmState { 17impl AlarmState {
25 const fn new() -> Self { 18 const fn new() -> Self {
26 Self { 19 Self { timestamp: u64::MAX }
27 timestamp: u64::MAX,
28 callback: ptr::null(),
29 ctx: ptr::null_mut(),
30 }
31 } 20 }
32} 21}
33 22
34struct TimeDriver { 23struct TimeDriver {
35 alarm_count: AtomicU8,
36
37 once: Once, 24 once: Once,
38 // The STD Driver implementation requires the alarms' mutex to be reentrant, which the STD Mutex isn't 25 // The STD Driver implementation requires the alarm's mutex to be reentrant, which the STD Mutex isn't
39 // Fortunately, mutexes based on the `critical-section` crate are reentrant, because the critical sections 26 // Fortunately, mutexes based on the `critical-section` crate are reentrant, because the critical sections
40 // themselves are reentrant 27 // themselves are reentrant
41 alarms: UninitCell<CsMutex<RefCell<[AlarmState; ALARM_COUNT]>>>, 28 alarm: UninitCell<CsMutex<RefCell<AlarmState>>>,
42 zero_instant: UninitCell<StdInstant>, 29 zero_instant: UninitCell<StdInstant>,
43 signaler: UninitCell<Signaler>, 30 signaler: UninitCell<Signaler>,
44} 31}
45 32
46embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { 33embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
47 alarm_count: AtomicU8::new(0),
48
49 once: Once::new(), 34 once: Once::new(),
50 alarms: UninitCell::uninit(), 35 alarm: UninitCell::uninit(),
51 zero_instant: UninitCell::uninit(), 36 zero_instant: UninitCell::uninit(),
52 signaler: UninitCell::uninit(), 37 signaler: UninitCell::uninit(),
53}); 38});
@@ -55,8 +40,8 @@ embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
55impl TimeDriver { 40impl TimeDriver {
56 fn init(&self) { 41 fn init(&self) {
57 self.once.call_once(|| unsafe { 42 self.once.call_once(|| unsafe {
58 self.alarms 43 self.alarm
59 .write(CsMutex::new(RefCell::new([const { AlarmState::new() }; ALARM_COUNT]))); 44 .write(CsMutex::new(RefCell::new(const { AlarmState::new() })));
60 self.zero_instant.write(StdInstant::now()); 45 self.zero_instant.write(StdInstant::now());
61 self.signaler.write(Signaler::new()); 46 self.signaler.write(Signaler::new());
62 47
@@ -70,36 +55,13 @@ impl TimeDriver {
70 let now = DRIVER.now(); 55 let now = DRIVER.now();
71 56
72 let next_alarm = critical_section::with(|cs| { 57 let next_alarm = critical_section::with(|cs| {
73 let alarms = unsafe { DRIVER.alarms.as_ref() }.borrow(cs); 58 let mut alarm = unsafe { DRIVER.alarm.as_ref() }.borrow_ref_mut(cs);
74 loop { 59 if alarm.timestamp <= now {
75 let pending = alarms 60 alarm.timestamp = u64::MAX;
76 .borrow_mut()
77 .iter_mut()
78 .find(|alarm| alarm.timestamp <= now)
79 .map(|alarm| {
80 alarm.timestamp = u64::MAX;
81
82 (alarm.callback, alarm.ctx)
83 });
84
85 if let Some((callback, ctx)) = pending {
86 // safety:
87 // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`.
88 // - other than that we only store valid function pointers into alarm.callback
89 let f: fn(*mut ()) = unsafe { mem::transmute(callback) };
90 f(ctx);
91 } else {
92 // No alarm due
93 break;
94 }
95 }
96 61
97 alarms 62 TIMER_QUEUE_DRIVER.dispatch();
98 .borrow() 63 }
99 .iter() 64 alarm.timestamp
100 .map(|alarm| alarm.timestamp)
101 .min()
102 .unwrap_or(u64::MAX)
103 }); 65 });
104 66
105 // Ensure we don't overflow 67 // Ensure we don't overflow
@@ -110,46 +72,11 @@ impl TimeDriver {
110 unsafe { DRIVER.signaler.as_ref() }.wait_until(until); 72 unsafe { DRIVER.signaler.as_ref() }.wait_until(until);
111 } 73 }
112 } 74 }
113}
114
115impl Driver for TimeDriver {
116 fn now(&self) -> u64 {
117 self.init();
118
119 let zero = unsafe { self.zero_instant.read() };
120 StdInstant::now().duration_since(zero).as_micros() as u64
121 }
122
123 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
124 let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
125 if x < ALARM_COUNT as u8 {
126 Some(x + 1)
127 } else {
128 None
129 }
130 });
131
132 match id {
133 Ok(id) => Some(AlarmHandle::new(id)),
134 Err(_) => None,
135 }
136 }
137
138 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
139 self.init();
140 critical_section::with(|cs| {
141 let mut alarms = unsafe { self.alarms.as_ref() }.borrow_ref_mut(cs);
142 let alarm = &mut alarms[alarm.id() as usize];
143 alarm.callback = callback as *const ();
144 alarm.ctx = ctx;
145 });
146 }
147 75
148 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { 76 fn set_alarm(&self, timestamp: u64) -> bool {
149 self.init(); 77 self.init();
150 critical_section::with(|cs| { 78 critical_section::with(|cs| {
151 let mut alarms = unsafe { self.alarms.as_ref() }.borrow_ref_mut(cs); 79 let mut alarm = unsafe { self.alarm.as_ref() }.borrow_ref_mut(cs);
152 let alarm = &mut alarms[alarm.id() as usize];
153 alarm.timestamp = timestamp; 80 alarm.timestamp = timestamp;
154 unsafe { self.signaler.as_ref() }.signal(); 81 unsafe { self.signaler.as_ref() }.signal();
155 }); 82 });
@@ -158,6 +85,15 @@ impl Driver for TimeDriver {
158 } 85 }
159} 86}
160 87
88impl Driver for TimeDriver {
89 fn now(&self) -> u64 {
90 self.init();
91
92 let zero = unsafe { self.zero_instant.read() };
93 StdInstant::now().duration_since(zero).as_micros() as u64
94 }
95}
96
161struct Signaler { 97struct Signaler {
162 mutex: Mutex<bool>, 98 mutex: Mutex<bool>,
163 condvar: Condvar, 99 condvar: Condvar,
@@ -228,3 +164,8 @@ impl<T: Copy> UninitCell<T> {
228 ptr::read(self.as_mut_ptr()) 164 ptr::read(self.as_mut_ptr())
229 } 165 }
230} 166}
167
168embassy_time_queue_driver::timer_queue_impl!(
169 static TIMER_QUEUE_DRIVER: GlobalTimerQueue
170 = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration))
171);
diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs
index d65629e49..dcc935fde 100644
--- a/embassy-time/src/driver_wasm.rs
+++ b/embassy-time/src/driver_wasm.rs
@@ -1,28 +1,22 @@
1use core::sync::atomic::{AtomicU8, Ordering};
2use std::cell::UnsafeCell; 1use std::cell::UnsafeCell;
3use std::mem::MaybeUninit; 2use std::mem::MaybeUninit;
4use std::ptr; 3use std::ptr;
5use std::sync::{Mutex, Once}; 4use std::sync::{Mutex, Once};
6 5
7use embassy_time_driver::{AlarmHandle, Driver}; 6use embassy_time_driver::Driver;
7use embassy_time_queue_driver::GlobalTimerQueue;
8use wasm_bindgen::prelude::*; 8use wasm_bindgen::prelude::*;
9use wasm_timer::Instant as StdInstant; 9use wasm_timer::Instant as StdInstant;
10 10
11const ALARM_COUNT: usize = 4;
12
13struct AlarmState { 11struct AlarmState {
14 token: Option<f64>, 12 token: Option<f64>,
15 closure: Option<Closure<dyn FnMut() + 'static>>,
16} 13}
17 14
18unsafe impl Send for AlarmState {} 15unsafe impl Send for AlarmState {}
19 16
20impl AlarmState { 17impl AlarmState {
21 const fn new() -> Self { 18 const fn new() -> Self {
22 Self { 19 Self { token: None }
23 token: None,
24 closure: None,
25 }
26 } 20 }
27} 21}
28 22
@@ -33,66 +27,32 @@ extern "C" {
33} 27}
34 28
35struct TimeDriver { 29struct TimeDriver {
36 alarm_count: AtomicU8,
37
38 once: Once, 30 once: Once,
39 alarms: UninitCell<Mutex<[AlarmState; ALARM_COUNT]>>, 31 alarm: UninitCell<Mutex<AlarmState>>,
40 zero_instant: UninitCell<StdInstant>, 32 zero_instant: UninitCell<StdInstant>,
33 closure: UninitCell<Closure<dyn FnMut()>>,
41} 34}
42 35
43embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { 36embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
44 alarm_count: AtomicU8::new(0),
45 once: Once::new(), 37 once: Once::new(),
46 alarms: UninitCell::uninit(), 38 alarm: UninitCell::uninit(),
47 zero_instant: UninitCell::uninit(), 39 zero_instant: UninitCell::uninit(),
40 closure: UninitCell::uninit()
48}); 41});
49 42
50impl TimeDriver { 43impl TimeDriver {
51 fn init(&self) { 44 fn init(&self) {
52 self.once.call_once(|| unsafe { 45 self.once.call_once(|| unsafe {
53 self.alarms 46 self.alarm.write(Mutex::new(const { AlarmState::new() }));
54 .write(Mutex::new([const { AlarmState::new() }; ALARM_COUNT]));
55 self.zero_instant.write(StdInstant::now()); 47 self.zero_instant.write(StdInstant::now());
48 self.closure
49 .write(Closure::new(Box::new(|| TIMER_QUEUE_DRIVER.dispatch())));
56 }); 50 });
57 } 51 }
58}
59
60impl Driver for TimeDriver {
61 fn now(&self) -> u64 {
62 self.init();
63
64 let zero = unsafe { self.zero_instant.read() };
65 StdInstant::now().duration_since(zero).as_micros() as u64
66 }
67
68 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
69 let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
70 if x < ALARM_COUNT as u8 {
71 Some(x + 1)
72 } else {
73 None
74 }
75 });
76
77 match id {
78 Ok(id) => Some(AlarmHandle::new(id)),
79 Err(_) => None,
80 }
81 }
82
83 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
84 self.init();
85 let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
86 let alarm = &mut alarms[alarm.id() as usize];
87 alarm.closure.replace(Closure::new(move || {
88 callback(ctx);
89 }));
90 }
91 52
92 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { 53 fn set_alarm(&self, timestamp: u64) -> bool {
93 self.init(); 54 self.init();
94 let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); 55 let mut alarm = unsafe { self.alarm.as_ref() }.lock().unwrap();
95 let alarm = &mut alarms[alarm.id() as usize];
96 if let Some(token) = alarm.token { 56 if let Some(token) = alarm.token {
97 clearTimeout(token); 57 clearTimeout(token);
98 } 58 }
@@ -102,13 +62,22 @@ impl Driver for TimeDriver {
102 false 62 false
103 } else { 63 } else {
104 let timeout = (timestamp - now) as u32; 64 let timeout = (timestamp - now) as u32;
105 alarm.token = Some(setTimeout(alarm.closure.as_ref().unwrap(), timeout / 1000)); 65 alarm.token = Some(setTimeout(unsafe { self.closure.as_ref() }, timeout / 1000));
106 66
107 true 67 true
108 } 68 }
109 } 69 }
110} 70}
111 71
72impl Driver for TimeDriver {
73 fn now(&self) -> u64 {
74 self.init();
75
76 let zero = unsafe { self.zero_instant.read() };
77 StdInstant::now().duration_since(zero).as_micros() as u64
78 }
79}
80
112pub(crate) struct UninitCell<T>(MaybeUninit<UnsafeCell<T>>); 81pub(crate) struct UninitCell<T>(MaybeUninit<UnsafeCell<T>>);
113unsafe impl<T> Send for UninitCell<T> {} 82unsafe impl<T> Send for UninitCell<T> {}
114unsafe impl<T> Sync for UninitCell<T> {} 83unsafe impl<T> Sync for UninitCell<T> {}
@@ -139,3 +108,8 @@ impl<T: Copy> UninitCell<T> {
139 ptr::read(self.as_mut_ptr()) 108 ptr::read(self.as_mut_ptr())
140 } 109 }
141} 110}
111
112embassy_time_queue_driver::timer_queue_impl!(
113 static TIMER_QUEUE_DRIVER: GlobalTimerQueue
114 = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration))
115);
diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs
index 8d0648ce5..80a359413 100644
--- a/embassy-time/src/lib.rs
+++ b/embassy-time/src/lib.rs
@@ -25,8 +25,6 @@ pub use driver_mock::MockDriver;
25mod driver_std; 25mod driver_std;
26#[cfg(feature = "wasm")] 26#[cfg(feature = "wasm")]
27mod driver_wasm; 27mod driver_wasm;
28#[cfg(feature = "generic-queue")]
29mod queue_generic;
30 28
31pub use delay::{block_for, Delay}; 29pub use delay::{block_for, Delay};
32pub use duration::Duration; 30pub use duration::Duration;
diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs
deleted file mode 100644
index 0068edae8..000000000
--- a/embassy-time/src/queue_generic.rs
+++ /dev/null
@@ -1,346 +0,0 @@
1use core::cell::RefCell;
2use core::cmp::{min, Ordering};
3use core::task::Waker;
4
5use critical_section::Mutex;
6use embassy_time_driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle};
7use embassy_time_queue_driver::TimerQueue;
8use heapless::Vec;
9
10use crate::Instant;
11
12#[cfg(feature = "generic-queue-8")]
13const QUEUE_SIZE: usize = 8;
14#[cfg(feature = "generic-queue-16")]
15const QUEUE_SIZE: usize = 16;
16#[cfg(feature = "generic-queue-32")]
17const QUEUE_SIZE: usize = 32;
18#[cfg(feature = "generic-queue-64")]
19const QUEUE_SIZE: usize = 64;
20#[cfg(feature = "generic-queue-128")]
21const QUEUE_SIZE: usize = 128;
22#[cfg(not(any(
23 feature = "generic-queue-8",
24 feature = "generic-queue-16",
25 feature = "generic-queue-32",
26 feature = "generic-queue-64",
27 feature = "generic-queue-128"
28)))]
29const QUEUE_SIZE: usize = 64;
30
31#[derive(Debug)]
32struct Timer {
33 at: Instant,
34 waker: Waker,
35}
36
37impl PartialEq for Timer {
38 fn eq(&self, other: &Self) -> bool {
39 self.at == other.at
40 }
41}
42
43impl Eq for Timer {}
44
45impl PartialOrd for Timer {
46 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
47 self.at.partial_cmp(&other.at)
48 }
49}
50
51impl Ord for Timer {
52 fn cmp(&self, other: &Self) -> Ordering {
53 self.at.cmp(&other.at)
54 }
55}
56
57struct InnerQueue {
58 queue: Vec<Timer, QUEUE_SIZE>,
59 alarm: AlarmHandle,
60}
61
62impl InnerQueue {
63 fn schedule_wake(&mut self, at: Instant, waker: &Waker) {
64 self.queue
65 .iter_mut()
66 .find(|timer| timer.waker.will_wake(waker))
67 .map(|timer| {
68 timer.at = min(timer.at, at);
69 })
70 .unwrap_or_else(|| {
71 let mut timer = Timer {
72 waker: waker.clone(),
73 at,
74 };
75
76 loop {
77 match self.queue.push(timer) {
78 Ok(()) => break,
79 Err(e) => timer = e,
80 }
81
82 self.queue.pop().unwrap().waker.wake();
83 }
84 });
85
86 // Don't wait for the alarm callback to trigger and directly
87 // dispatch all timers that are already due
88 //
89 // Then update the alarm if necessary
90 self.dispatch();
91 }
92
93 fn dispatch(&mut self) {
94 loop {
95 let now = Instant::now();
96
97 let mut next_alarm = Instant::MAX;
98
99 let mut i = 0;
100 while i < self.queue.len() {
101 let timer = &self.queue[i];
102 if timer.at <= now {
103 let timer = self.queue.swap_remove(i);
104 timer.waker.wake();
105 } else {
106 next_alarm = min(next_alarm, timer.at);
107 i += 1;
108 }
109 }
110
111 if self.update_alarm(next_alarm) {
112 break;
113 }
114 }
115 }
116
117 fn update_alarm(&mut self, next_alarm: Instant) -> bool {
118 if next_alarm == Instant::MAX {
119 true
120 } else {
121 set_alarm(self.alarm, next_alarm.as_ticks())
122 }
123 }
124
125 fn handle_alarm(&mut self) {
126 self.dispatch();
127 }
128}
129
130struct Queue {
131 inner: Mutex<RefCell<Option<InnerQueue>>>,
132}
133
134impl Queue {
135 const fn new() -> Self {
136 Self {
137 inner: Mutex::new(RefCell::new(None)),
138 }
139 }
140
141 fn schedule_wake(&'static self, at: Instant, waker: &Waker) {
142 critical_section::with(|cs| {
143 let mut inner = self.inner.borrow_ref_mut(cs);
144
145 inner
146 .get_or_insert_with(|| {
147 let handle = unsafe { allocate_alarm() }.unwrap();
148 set_alarm_callback(handle, Self::handle_alarm_callback, self as *const _ as _);
149 InnerQueue {
150 queue: Vec::new(),
151 alarm: handle,
152 }
153 })
154 .schedule_wake(at, waker)
155 });
156 }
157
158 fn handle_alarm(&self) {
159 critical_section::with(|cs| self.inner.borrow_ref_mut(cs).as_mut().unwrap().handle_alarm())
160 }
161
162 fn handle_alarm_callback(ctx: *mut ()) {
163 unsafe { (ctx as *const Self).as_ref().unwrap() }.handle_alarm();
164 }
165}
166
167impl TimerQueue for Queue {
168 fn schedule_wake(&'static self, at: u64, waker: &Waker) {
169 Queue::schedule_wake(self, Instant::from_ticks(at), waker);
170 }
171}
172
173embassy_time_queue_driver::timer_queue_impl!(static QUEUE: Queue = Queue::new());
174
175#[cfg(test)]
176#[cfg(feature = "mock-driver")]
177mod tests {
178 use core::sync::atomic::{AtomicBool, Ordering};
179 use core::task::Waker;
180 use std::sync::Arc;
181 use std::task::Wake;
182
183 use serial_test::serial;
184
185 use crate::driver_mock::MockDriver;
186 use crate::queue_generic::QUEUE;
187 use crate::{Duration, Instant};
188
189 struct TestWaker {
190 pub awoken: AtomicBool,
191 }
192
193 impl Wake for TestWaker {
194 fn wake(self: Arc<Self>) {
195 self.awoken.store(true, Ordering::Relaxed);
196 }
197
198 fn wake_by_ref(self: &Arc<Self>) {
199 self.awoken.store(true, Ordering::Relaxed);
200 }
201 }
202
203 fn test_waker() -> (Arc<TestWaker>, Waker) {
204 let arc = Arc::new(TestWaker {
205 awoken: AtomicBool::new(false),
206 });
207 let waker = Waker::from(arc.clone());
208
209 (arc, waker)
210 }
211
212 fn setup() {
213 MockDriver::get().reset();
214 critical_section::with(|cs| *QUEUE.inner.borrow_ref_mut(cs) = None);
215 }
216
217 fn queue_len() -> usize {
218 critical_section::with(|cs| {
219 QUEUE
220 .inner
221 .borrow_ref(cs)
222 .as_ref()
223 .map(|inner| inner.queue.iter().count())
224 .unwrap_or(0)
225 })
226 }
227
228 #[test]
229 #[serial]
230 fn test_schedule() {
231 setup();
232
233 assert_eq!(queue_len(), 0);
234
235 let (flag, waker) = test_waker();
236
237 QUEUE.schedule_wake(Instant::from_secs(1), &waker);
238
239 assert!(!flag.awoken.load(Ordering::Relaxed));
240 assert_eq!(queue_len(), 1);
241 }
242
243 #[test]
244 #[serial]
245 fn test_schedule_same() {
246 setup();
247
248 let (_flag, waker) = test_waker();
249
250 QUEUE.schedule_wake(Instant::from_secs(1), &waker);
251
252 assert_eq!(queue_len(), 1);
253
254 QUEUE.schedule_wake(Instant::from_secs(1), &waker);
255
256 assert_eq!(queue_len(), 1);
257
258 QUEUE.schedule_wake(Instant::from_secs(100), &waker);
259
260 assert_eq!(queue_len(), 1);
261
262 let (_flag2, waker2) = test_waker();
263
264 QUEUE.schedule_wake(Instant::from_secs(100), &waker2);
265
266 assert_eq!(queue_len(), 2);
267 }
268
269 #[test]
270 #[serial]
271 fn test_trigger() {
272 setup();
273
274 let (flag, waker) = test_waker();
275
276 QUEUE.schedule_wake(Instant::from_secs(100), &waker);
277
278 assert!(!flag.awoken.load(Ordering::Relaxed));
279
280 MockDriver::get().advance(Duration::from_secs(99));
281
282 assert!(!flag.awoken.load(Ordering::Relaxed));
283
284 assert_eq!(queue_len(), 1);
285
286 MockDriver::get().advance(Duration::from_secs(1));
287
288 assert!(flag.awoken.load(Ordering::Relaxed));
289
290 assert_eq!(queue_len(), 0);
291 }
292
293 #[test]
294 #[serial]
295 fn test_immediate_trigger() {
296 setup();
297
298 let (flag, waker) = test_waker();
299
300 QUEUE.schedule_wake(Instant::from_secs(100), &waker);
301
302 MockDriver::get().advance(Duration::from_secs(50));
303
304 let (flag2, waker2) = test_waker();
305
306 QUEUE.schedule_wake(Instant::from_secs(40), &waker2);
307
308 assert!(!flag.awoken.load(Ordering::Relaxed));
309 assert!(flag2.awoken.load(Ordering::Relaxed));
310 assert_eq!(queue_len(), 1);
311 }
312
313 #[test]
314 #[serial]
315 fn test_queue_overflow() {
316 setup();
317
318 for i in 1..super::QUEUE_SIZE {
319 let (flag, waker) = test_waker();
320
321 QUEUE.schedule_wake(Instant::from_secs(310), &waker);
322
323 assert_eq!(queue_len(), i);
324 assert!(!flag.awoken.load(Ordering::Relaxed));
325 }
326
327 let (flag, waker) = test_waker();
328
329 QUEUE.schedule_wake(Instant::from_secs(300), &waker);
330
331 assert_eq!(queue_len(), super::QUEUE_SIZE);
332 assert!(!flag.awoken.load(Ordering::Relaxed));
333
334 let (flag2, waker2) = test_waker();
335
336 QUEUE.schedule_wake(Instant::from_secs(305), &waker2);
337
338 assert_eq!(queue_len(), super::QUEUE_SIZE);
339 assert!(flag.awoken.load(Ordering::Relaxed));
340
341 let (_flag3, waker3) = test_waker();
342 QUEUE.schedule_wake(Instant::from_secs(320), &waker3);
343 assert_eq!(queue_len(), super::QUEUE_SIZE);
344 assert!(flag2.awoken.load(Ordering::Relaxed));
345 }
346}