aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-08-25 18:50:05 +0200
committerDario Nieuwenhuis <[email protected]>2021-08-25 21:06:27 +0200
commit7c0990ad1e8d1a455818740973ca0267bb3f5854 (patch)
treea7acf5be11f48adb18c10369477cd1cbc80798d3
parent55b2d7b5248cb81e80e8c207ab03e6b4b52ce2f9 (diff)
time: allow storing state inside the driver struct.
-rw-r--r--embassy-nrf/src/time_driver.rs55
-rw-r--r--embassy-rp/src/timer.rs124
-rw-r--r--embassy-stm32/src/time_driver.rs62
-rw-r--r--embassy/src/executor/arch/std.rs67
-rw-r--r--embassy/src/time/driver.rs99
5 files changed, 214 insertions, 193 deletions
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index 30461633a..f93ebb54a 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -82,7 +82,7 @@ impl AlarmState {
82 82
83const ALARM_COUNT: usize = 3; 83const ALARM_COUNT: usize = 3;
84 84
85struct State { 85struct RtcDriver {
86 /// Number of 2^23 periods elapsed since boot. 86 /// Number of 2^23 periods elapsed since boot.
87 period: AtomicU32, 87 period: AtomicU32,
88 alarm_count: AtomicU8, 88 alarm_count: AtomicU8,
@@ -91,13 +91,13 @@ struct State {
91} 91}
92 92
93const ALARM_STATE_NEW: AlarmState = AlarmState::new(); 93const ALARM_STATE_NEW: AlarmState = AlarmState::new();
94static STATE: State = State { 94embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
95 period: AtomicU32::new(0), 95 period: AtomicU32::new(0),
96 alarm_count: AtomicU8::new(0), 96 alarm_count: AtomicU8::new(0),
97 alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]), 97 alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]),
98}; 98});
99 99
100impl State { 100impl RtcDriver {
101 fn init(&'static self, irq_prio: crate::interrupt::Priority) { 101 fn init(&'static self, irq_prio: crate::interrupt::Priority) {
102 let r = rtc(); 102 let r = rtc();
103 r.cc[3].write(|w| unsafe { w.bits(0x800000) }); 103 r.cc[3].write(|w| unsafe { w.bits(0x800000) });
@@ -159,14 +159,6 @@ impl State {
159 }) 159 })
160 } 160 }
161 161
162 fn now(&self) -> u64 {
163 // `period` MUST be read before `counter`, see comment at the top for details.
164 let period = self.period.load(Ordering::Relaxed);
165 compiler_fence(Ordering::Acquire);
166 let counter = rtc().counter.read().bits();
167 calc_now(period, counter)
168 }
169
170 fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState { 162 fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState {
171 // safety: we're allowed to assume the AlarmState is created by us, and 163 // safety: we're allowed to assume the AlarmState is created by us, and
172 // we never create one that's out of bounds. 164 // we never create one that's out of bounds.
@@ -188,8 +180,18 @@ impl State {
188 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) }; 180 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
189 f(alarm.ctx.get()); 181 f(alarm.ctx.get());
190 } 182 }
183}
191 184
192 fn allocate_alarm(&self) -> Option<AlarmHandle> { 185impl Driver for RtcDriver {
186 fn now(&self) -> u64 {
187 // `period` MUST be read before `counter`, see comment at the top for details.
188 let period = self.period.load(Ordering::Relaxed);
189 compiler_fence(Ordering::Acquire);
190 let counter = rtc().counter.read().bits();
191 calc_now(period, counter)
192 }
193
194 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
193 let id = self 195 let id = self
194 .alarm_count 196 .alarm_count
195 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { 197 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
@@ -201,7 +203,7 @@ impl State {
201 }); 203 });
202 204
203 match id { 205 match id {
204 Ok(id) => Some(unsafe { AlarmHandle::new(id) }), 206 Ok(id) => Some(AlarmHandle::new(id)),
205 Err(_) => None, 207 Err(_) => None,
206 } 208 }
207 } 209 }
@@ -263,32 +265,11 @@ impl State {
263 } 265 }
264} 266}
265 267
266struct RtcDriver;
267embassy::time_driver_impl!(RtcDriver);
268
269impl Driver for RtcDriver {
270 fn now() -> u64 {
271 STATE.now()
272 }
273
274 unsafe fn allocate_alarm() -> Option<AlarmHandle> {
275 STATE.allocate_alarm()
276 }
277
278 fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
279 STATE.set_alarm_callback(alarm, callback, ctx)
280 }
281
282 fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
283 STATE.set_alarm(alarm, timestamp)
284 }
285}
286
287#[interrupt] 268#[interrupt]
288fn RTC1() { 269fn RTC1() {
289 STATE.on_interrupt() 270 DRIVER.on_interrupt()
290} 271}
291 272
292pub(crate) fn init(irq_prio: crate::interrupt::Priority) { 273pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
293 STATE.init(irq_prio) 274 DRIVER.init(irq_prio)
294} 275}
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs
index 71c59ec8d..ed265c47f 100644
--- a/embassy-rp/src/timer.rs
+++ b/embassy-rp/src/timer.rs
@@ -19,38 +19,40 @@ const DUMMY_ALARM: AlarmState = AlarmState {
19 callback: Cell::new(None), 19 callback: Cell::new(None),
20}; 20};
21 21
22static ALARMS: Mutex<[AlarmState; ALARM_COUNT]> = Mutex::new([DUMMY_ALARM; ALARM_COUNT]); 22struct TimerDriver {
23static NEXT_ALARM: AtomicU8 = AtomicU8::new(0); 23 alarms: Mutex<[AlarmState; ALARM_COUNT]>,
24 24 next_alarm: AtomicU8,
25fn now() -> u64 {
26 loop {
27 unsafe {
28 let hi = pac::TIMER.timerawh().read();
29 let lo = pac::TIMER.timerawl().read();
30 let hi2 = pac::TIMER.timerawh().read();
31 if hi == hi2 {
32 return (hi as u64) << 32 | (lo as u64);
33 }
34 }
35 }
36} 25}
37 26
38struct TimerDriver; 27embassy::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
39embassy::time_driver_impl!(TimerDriver); 28 alarms: Mutex::new([DUMMY_ALARM; ALARM_COUNT]),
29 next_alarm: AtomicU8::new(0),
30});
40 31
41impl Driver for TimerDriver { 32impl Driver for TimerDriver {
42 fn now() -> u64 { 33 fn now(&self) -> u64 {
43 now() 34 loop {
35 unsafe {
36 let hi = pac::TIMER.timerawh().read();
37 let lo = pac::TIMER.timerawl().read();
38 let hi2 = pac::TIMER.timerawh().read();
39 if hi == hi2 {
40 return (hi as u64) << 32 | (lo as u64);
41 }
42 }
43 }
44 } 44 }
45 45
46 unsafe fn allocate_alarm() -> Option<AlarmHandle> { 46 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
47 let id = NEXT_ALARM.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { 47 let id = self
48 if x < ALARM_COUNT as u8 { 48 .next_alarm
49 Some(x + 1) 49 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
50 } else { 50 if x < ALARM_COUNT as u8 {
51 None 51 Some(x + 1)
52 } 52 } else {
53 }); 53 None
54 }
55 });
54 56
55 match id { 57 match id {
56 Ok(id) => Some(AlarmHandle::new(id)), 58 Ok(id) => Some(AlarmHandle::new(id)),
@@ -58,18 +60,18 @@ impl Driver for TimerDriver {
58 } 60 }
59 } 61 }
60 62
61 fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { 63 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
62 let n = alarm.id() as usize; 64 let n = alarm.id() as usize;
63 critical_section::with(|cs| { 65 critical_section::with(|cs| {
64 let alarm = &ALARMS.borrow(cs)[n]; 66 let alarm = &self.alarms.borrow(cs)[n];
65 alarm.callback.set(Some((callback, ctx))); 67 alarm.callback.set(Some((callback, ctx)));
66 }) 68 })
67 } 69 }
68 70
69 fn set_alarm(alarm: AlarmHandle, timestamp: u64) { 71 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
70 let n = alarm.id() as usize; 72 let n = alarm.id() as usize;
71 critical_section::with(|cs| { 73 critical_section::with(|cs| {
72 let alarm = &ALARMS.borrow(cs)[n]; 74 let alarm = &self.alarms.borrow(cs)[n];
73 alarm.timestamp.set(timestamp); 75 alarm.timestamp.set(timestamp);
74 76
75 // Arm it. 77 // Arm it.
@@ -78,44 +80,46 @@ impl Driver for TimerDriver {
78 // it is checked if the alarm time has passed. 80 // it is checked if the alarm time has passed.
79 unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; 81 unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) };
80 82
81 let now = now(); 83 let now = self.now();
82 84
83 // If alarm timestamp has passed, trigger it instantly. 85 // If alarm timestamp has passed, trigger it instantly.
84 // This disarms it. 86 // This disarms it.
85 if timestamp <= now { 87 if timestamp <= now {
86 trigger_alarm(n, cs); 88 self.trigger_alarm(n, cs);
87 } 89 }
88 }) 90 })
89 } 91 }
90} 92}
91 93
92fn check_alarm(n: usize) { 94impl TimerDriver {
93 critical_section::with(|cs| { 95 fn check_alarm(&self, n: usize) {
94 let alarm = &ALARMS.borrow(cs)[n]; 96 critical_section::with(|cs| {
95 let timestamp = alarm.timestamp.get(); 97 let alarm = &self.alarms.borrow(cs)[n];
96 if timestamp <= now() { 98 let timestamp = alarm.timestamp.get();
97 trigger_alarm(n, cs) 99 if timestamp <= self.now() {
98 } else { 100 self.trigger_alarm(n, cs)
99 // Not elapsed, arm it again. 101 } else {
100 // This can happen if it was set more than 2^32 us in the future. 102 // Not elapsed, arm it again.
101 unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; 103 // This can happen if it was set more than 2^32 us in the future.
102 } 104 unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) };
103 }); 105 }
106 });
104 107
105 // clear the irq 108 // clear the irq
106 unsafe { pac::TIMER.intr().write(|w| w.set_alarm(n, true)) } 109 unsafe { pac::TIMER.intr().write(|w| w.set_alarm(n, true)) }
107} 110 }
108 111
109fn trigger_alarm(n: usize, cs: CriticalSection) { 112 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
110 // disarm 113 // disarm
111 unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } 114 unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) }
112 115
113 let alarm = &ALARMS.borrow(cs)[n]; 116 let alarm = &self.alarms.borrow(cs)[n];
114 alarm.timestamp.set(u64::MAX); 117 alarm.timestamp.set(u64::MAX);
115 118
116 // Call after clearing alarm, so the callback can set another alarm. 119 // Call after clearing alarm, so the callback can set another alarm.
117 if let Some((f, ctx)) = alarm.callback.get() { 120 if let Some((f, ctx)) = alarm.callback.get() {
118 f(ctx); 121 f(ctx);
122 }
119 } 123 }
120} 124}
121 125
@@ -123,7 +127,7 @@ fn trigger_alarm(n: usize, cs: CriticalSection) {
123pub unsafe fn init() { 127pub unsafe fn init() {
124 // init alarms 128 // init alarms
125 critical_section::with(|cs| { 129 critical_section::with(|cs| {
126 let alarms = ALARMS.borrow(cs); 130 let alarms = DRIVER.alarms.borrow(cs);
127 for a in alarms { 131 for a in alarms {
128 a.timestamp.set(u64::MAX); 132 a.timestamp.set(u64::MAX);
129 } 133 }
@@ -144,20 +148,20 @@ pub unsafe fn init() {
144 148
145#[interrupt] 149#[interrupt]
146unsafe fn TIMER_IRQ_0() { 150unsafe fn TIMER_IRQ_0() {
147 check_alarm(0) 151 DRIVER.check_alarm(0)
148} 152}
149 153
150#[interrupt] 154#[interrupt]
151unsafe fn TIMER_IRQ_1() { 155unsafe fn TIMER_IRQ_1() {
152 check_alarm(1) 156 DRIVER.check_alarm(1)
153} 157}
154 158
155#[interrupt] 159#[interrupt]
156unsafe fn TIMER_IRQ_2() { 160unsafe fn TIMER_IRQ_2() {
157 check_alarm(2) 161 DRIVER.check_alarm(2)
158} 162}
159 163
160#[interrupt] 164#[interrupt]
161unsafe fn TIMER_IRQ_3() { 165unsafe fn TIMER_IRQ_3() {
162 check_alarm(3) 166 DRIVER.check_alarm(3)
163} 167}
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 91b8525ae..4e1eb7aaa 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -26,12 +26,12 @@ type T = peripherals::TIM3;
26#[cfg(feature = "time-driver-tim2")] 26#[cfg(feature = "time-driver-tim2")]
27#[interrupt] 27#[interrupt]
28fn TIM2() { 28fn TIM2() {
29 STATE.on_interrupt() 29 DRIVER.on_interrupt()
30} 30}
31#[cfg(feature = "time-driver-tim3")] 31#[cfg(feature = "time-driver-tim3")]
32#[interrupt] 32#[interrupt]
33fn TIM3() { 33fn TIM3() {
34 STATE.on_interrupt() 34 DRIVER.on_interrupt()
35} 35}
36 36
37// Clock timekeeping works with something we call "periods", which are time intervals 37// Clock timekeeping works with something we call "periods", which are time intervals
@@ -76,7 +76,7 @@ impl AlarmState {
76 } 76 }
77} 77}
78 78
79struct State { 79struct RtcDriver {
80 /// Number of 2^15 periods elapsed since boot. 80 /// Number of 2^15 periods elapsed since boot.
81 period: AtomicU32, 81 period: AtomicU32,
82 alarm_count: AtomicU8, 82 alarm_count: AtomicU8,
@@ -85,13 +85,14 @@ struct State {
85} 85}
86 86
87const ALARM_STATE_NEW: AlarmState = AlarmState::new(); 87const ALARM_STATE_NEW: AlarmState = AlarmState::new();
88static STATE: State = State { 88
89embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
89 period: AtomicU32::new(0), 90 period: AtomicU32::new(0),
90 alarm_count: AtomicU8::new(0), 91 alarm_count: AtomicU8::new(0),
91 alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]), 92 alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]),
92}; 93});
93 94
94impl State { 95impl RtcDriver {
95 fn init(&'static self) { 96 fn init(&'static self) {
96 let r = T::regs(); 97 let r = T::regs();
97 98
@@ -185,16 +186,6 @@ impl State {
185 }) 186 })
186 } 187 }
187 188
188 fn now(&self) -> u64 {
189 let r = T::regs();
190
191 let period = self.period.load(Ordering::Relaxed);
192 compiler_fence(Ordering::Acquire);
193 // NOTE(unsafe) Atomic read with no side-effects
194 let counter = unsafe { r.cnt().read().cnt() };
195 calc_now(period, counter)
196 }
197
198 fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState { 189 fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState {
199 // safety: we're allowed to assume the AlarmState is created by us, and 190 // safety: we're allowed to assume the AlarmState is created by us, and
200 // we never create one that's out of bounds. 191 // we never create one that's out of bounds.
@@ -213,8 +204,20 @@ impl State {
213 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) }; 204 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
214 f(alarm.ctx.get()); 205 f(alarm.ctx.get());
215 } 206 }
207}
208
209impl Driver for RtcDriver {
210 fn now(&self) -> u64 {
211 let r = T::regs();
212
213 let period = self.period.load(Ordering::Relaxed);
214 compiler_fence(Ordering::Acquire);
215 // NOTE(unsafe) Atomic read with no side-effects
216 let counter = unsafe { r.cnt().read().cnt() };
217 calc_now(period, counter)
218 }
216 219
217 fn allocate_alarm(&self) -> Option<AlarmHandle> { 220 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
218 let id = self 221 let id = self
219 .alarm_count 222 .alarm_count
220 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { 223 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
@@ -226,7 +229,7 @@ impl State {
226 }); 229 });
227 230
228 match id { 231 match id {
229 Ok(id) => Some(unsafe { AlarmHandle::new(id) }), 232 Ok(id) => Some(AlarmHandle::new(id)),
230 Err(_) => None, 233 Err(_) => None,
231 } 234 }
232 } 235 }
@@ -269,29 +272,8 @@ impl State {
269 } 272 }
270} 273}
271 274
272struct RtcDriver;
273embassy::time_driver_impl!(RtcDriver);
274
275impl Driver for RtcDriver {
276 fn now() -> u64 {
277 STATE.now()
278 }
279
280 unsafe fn allocate_alarm() -> Option<AlarmHandle> {
281 STATE.allocate_alarm()
282 }
283
284 fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
285 STATE.set_alarm_callback(alarm, callback, ctx)
286 }
287
288 fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
289 STATE.set_alarm(alarm, timestamp)
290 }
291}
292
293pub(crate) fn init() { 275pub(crate) fn init() {
294 STATE.init() 276 DRIVER.init()
295} 277}
296 278
297// ------------------------------------------------------ 279// ------------------------------------------------------
diff --git a/embassy/src/executor/arch/std.rs b/embassy/src/executor/arch/std.rs
new file mode 100644
index 000000000..fb7880542
--- /dev/null
+++ b/embassy/src/executor/arch/std.rs
@@ -0,0 +1,67 @@
1use std::marker::PhantomData;
2use std::sync::{Condvar, Mutex};
3
4use super::{raw, Spawner};
5
6pub struct Executor {
7 inner: raw::Executor,
8 not_send: PhantomData<*mut ()>,
9 signaler: &'static Signaler,
10}
11
12impl Executor {
13 pub fn new() -> Self {
14 let signaler = &*Box::leak(Box::new(Signaler::new()));
15 Self {
16 inner: raw::Executor::new(
17 |p| unsafe {
18 let s = &*(p as *const () as *const Signaler);
19 s.signal()
20 },
21 signaler as *const _ as _,
22 ),
23 not_send: PhantomData,
24 signaler,
25 }
26 }
27
28 /// Runs the executor.
29 ///
30 /// This function never returns.
31 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
32 init(unsafe { self.inner.spawner() });
33
34 loop {
35 unsafe { self.inner.run_queued() };
36 self.signaler.wait()
37 }
38 }
39}
40
41struct Signaler {
42 mutex: Mutex<bool>,
43 condvar: Condvar,
44}
45
46impl Signaler {
47 fn new() -> Self {
48 Self {
49 mutex: Mutex::new(false),
50 condvar: Condvar::new(),
51 }
52 }
53
54 fn wait(&self) {
55 let mut signaled = self.mutex.lock().unwrap();
56 while !*signaled {
57 signaled = self.condvar.wait(signaled).unwrap();
58 }
59 *signaled = false;
60 }
61
62 fn signal(&self) {
63 let mut signaled = self.mutex.lock().unwrap();
64 *signaled = true;
65 self.condvar.notify_one();
66 }
67}
diff --git a/embassy/src/time/driver.rs b/embassy/src/time/driver.rs
index 21817b92f..1b8949ae1 100644
--- a/embassy/src/time/driver.rs
+++ b/embassy/src/time/driver.rs
@@ -26,32 +26,34 @@
26//! This method has a few key advantages for something as foundational as timekeeping: 26//! This method has a few key advantages for something as foundational as timekeeping:
27//! 27//!
28//! - The time driver is available everywhere easily, without having to thread the implementation 28//! - The time driver is available everywhere easily, without having to thread the implementation
29//~ through generic parameters. This is especially helpful for libraries. 29//! through generic parameters. This is especially helpful for libraries.
30//! - It means comparing `Instant`s will always make sense: if there were multiple drivers 30//! - It means comparing `Instant`s will always make sense: if there were multiple drivers
31//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which 31//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which
32//! would yield incorrect results. 32//! would yield incorrect results.
33//! 33//!
34/// # Example 34//! # Example
35/// 35//!
36/// ``` 36//! ```
37/// struct MyDriver; // not public! 37//! use embassy::time::driver::{Driver, AlarmHandle};
38/// embassy::time_driver_impl!(MyDriver); 38//!
39/// 39//! struct MyDriver{}; // not public!
40/// unsafe impl embassy::time::driver::Driver for MyDriver { 40//! embassy::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
41/// fn now() -> u64 { 41//!
42/// todo!() 42//! impl Driver for MyDriver {
43/// } 43//! fn now(&self) -> u64 {
44/// unsafe fn allocate_alarm() -> Option<AlarmHandle> { 44//! todo!()
45/// todo!() 45//! }
46/// } 46//! unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
47/// fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { 47//! todo!()
48/// todo!() 48//! }
49/// } 49//! fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
50/// fn set_alarm(alarm: AlarmHandle, timestamp: u64) { 50//! todo!()
51/// todo!() 51//! }
52/// } 52//! fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
53/// } 53//! todo!()
54/// ``` 54//! }
55//! }
56//! ```
55 57
56/// Alarm handle, assigned by the driver. 58/// Alarm handle, assigned by the driver.
57#[derive(Clone, Copy)] 59#[derive(Clone, Copy)]
@@ -76,22 +78,22 @@ impl AlarmHandle {
76} 78}
77 79
78/// Time driver 80/// Time driver
79pub trait Driver { 81pub trait Driver: Send + Sync + 'static {
80 /// Return the current timestamp in ticks. 82 /// Return the current timestamp in ticks.
81 /// This is guaranteed to be monotonic, i.e. a call to now() will always return 83 /// This is guaranteed to be monotonic, i.e. a call to now() will always return
82 /// a greater or equal value than earler calls. 84 /// a greater or equal value than earler calls.
83 fn now() -> u64; 85 fn now(&self) -> u64;
84 86
85 /// Try allocating an alarm handle. Returns None if no alarms left. 87 /// Try allocating an alarm handle. Returns None if no alarms left.
86 /// Initially the alarm has no callback set, and a null `ctx` pointer. 88 /// Initially the alarm has no callback set, and a null `ctx` pointer.
87 /// 89 ///
88 /// # Safety 90 /// # Safety
89 /// It is UB to make the alarm fire before setting a callback. 91 /// It is UB to make the alarm fire before setting a callback.
90 unsafe fn allocate_alarm() -> Option<AlarmHandle>; 92 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>;
91 93
92 /// Sets the callback function to be called when the alarm triggers. 94 /// Sets the callback function to be called when the alarm triggers.
93 /// The callback may be called from any context (interrupt or thread mode). 95 /// The callback may be called from any context (interrupt or thread mode).
94 fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); 96 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ());
95 97
96 /// Sets an alarm at the given timestamp. When the current timestamp reaches that 98 /// Sets an alarm at the given timestamp. When the current timestamp reaches that
97 /// timestamp, the provided callback funcion will be called. 99 /// timestamp, the provided callback funcion will be called.
@@ -99,7 +101,7 @@ pub trait Driver {
99 /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. 101 /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp.
100 /// 102 ///
101 /// Only one alarm can be active at a time. This overwrites any previously-set alarm if any. 103 /// Only one alarm can be active at a time. This overwrites any previously-set alarm if any.
102 fn set_alarm(alarm: AlarmHandle, timestamp: u64); 104 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64);
103} 105}
104 106
105extern "Rust" { 107extern "Rust" {
@@ -125,49 +127,34 @@ pub(crate) fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
125 127
126/// Set the time Driver implementation. 128/// Set the time Driver implementation.
127/// 129///
128/// # Example 130/// See the module documentation for an example.
129///
130/// ```
131/// struct MyDriver; // not public!
132/// embassy::time_driver_impl!(MyDriver);
133///
134/// unsafe impl embassy::time::driver::Driver for MyDriver {
135/// fn now() -> u64 {
136/// todo!()
137/// }
138/// unsafe fn allocate_alarm() -> Option<AlarmHandle> {
139/// todo!()
140/// }
141/// fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
142/// todo!()
143/// }
144/// fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
145/// todo!()
146/// }
147/// }
148/// ```
149#[macro_export] 131#[macro_export]
150macro_rules! time_driver_impl { 132macro_rules! time_driver_impl {
151 ($t: ty) => { 133 (static $name:ident: $t: ty = $val:expr) => {
134 static $name: $t = $val;
135
152 #[no_mangle] 136 #[no_mangle]
153 fn _embassy_time_now() -> u64 { 137 fn _embassy_time_now() -> u64 {
154 <$t as $crate::time::driver::Driver>::now() 138 <$t as $crate::time::driver::Driver>::now(&$name)
155 } 139 }
140
156 #[no_mangle] 141 #[no_mangle]
157 unsafe fn _embassy_time_allocate_alarm() -> Option<AlarmHandle> { 142 unsafe fn _embassy_time_allocate_alarm() -> Option<$crate::time::driver::AlarmHandle> {
158 <$t as $crate::time::driver::Driver>::allocate_alarm() 143 <$t as $crate::time::driver::Driver>::allocate_alarm(&$name)
159 } 144 }
145
160 #[no_mangle] 146 #[no_mangle]
161 fn _embassy_time_set_alarm_callback( 147 fn _embassy_time_set_alarm_callback(
162 alarm: AlarmHandle, 148 alarm: $crate::time::driver::AlarmHandle,
163 callback: fn(*mut ()), 149 callback: fn(*mut ()),
164 ctx: *mut (), 150 ctx: *mut (),
165 ) { 151 ) {
166 <$t as $crate::time::driver::Driver>::set_alarm_callback(alarm, callback, ctx) 152 <$t as $crate::time::driver::Driver>::set_alarm_callback(&$name, alarm, callback, ctx)
167 } 153 }
154
168 #[no_mangle] 155 #[no_mangle]
169 fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64) { 156 fn _embassy_time_set_alarm(alarm: $crate::time::driver::AlarmHandle, timestamp: u64) {
170 <$t as $crate::time::driver::Driver>::set_alarm(alarm, timestamp) 157 <$t as $crate::time::driver::Driver>::set_alarm(&$name, alarm, timestamp)
171 } 158 }
172 }; 159 };
173} 160}