aboutsummaryrefslogtreecommitdiff
path: root/embassy-time/src/driver_wasm.rs
diff options
context:
space:
mode:
authorDániel Buga <[email protected]>2024-11-26 23:54:21 +0100
committerDániel Buga <[email protected]>2024-12-10 21:31:42 +0100
commit5a5495aac43d75610735f2ca80fb6c8e8f31ed71 (patch)
tree7a4336917894730692589359e9d1a285ec5a0a05 /embassy-time/src/driver_wasm.rs
parent406d377b7564d16e12b7fae4f42c0c709bf4f243 (diff)
Refactor integrated-timers
Diffstat (limited to 'embassy-time/src/driver_wasm.rs')
-rw-r--r--embassy-time/src/driver_wasm.rs80
1 files changed, 27 insertions, 53 deletions
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);