esp_wifi/compat/
timer_compat.rs
1use alloc::boxed::Box;
2
3use esp_hal::sync::Locked;
4
5use crate::binary::{
6 c_types,
7 include::{esp_timer_create_args_t, ets_timer},
8};
9
10#[derive(Clone, Copy, Debug)]
11pub(crate) struct TimerCallback {
12 f: unsafe extern "C" fn(*mut c_types::c_void),
13 args: *mut c_types::c_void,
14}
15
16impl TimerCallback {
17 fn new(f: unsafe extern "C" fn(*mut c_types::c_void), args: *mut c_types::c_void) -> Self {
18 Self { f, args }
19 }
20
21 pub(crate) fn call(self) {
22 unsafe { (self.f)(self.args) };
23 }
24}
25
26impl From<&esp_timer_create_args_t> for TimerCallback {
27 fn from(args: &esp_timer_create_args_t) -> Self {
28 Self::new(unwrap!(args.callback), args.arg)
29 }
30}
31
32#[repr(C)]
33#[derive(Debug, Clone)]
34pub(crate) struct Timer {
35 pub ets_timer: *mut ets_timer,
36 pub started: u64,
37 pub timeout: u64,
38 pub active: bool,
39 pub periodic: bool,
40 pub callback: TimerCallback,
41
42 next: Option<Box<Timer>>,
43}
44
45impl Timer {
46 pub(crate) fn id(&self) -> usize {
47 self.ets_timer as usize
48 }
49}
50
51pub(crate) struct TimerQueue {
52 head: Option<Box<Timer>>,
53}
54
55impl TimerQueue {
56 const fn new() -> Self {
57 Self { head: None }
58 }
59
60 fn find(&mut self, ets_timer: *mut ets_timer) -> Option<&mut Box<Timer>> {
61 let mut current = self.head.as_mut();
62 while let Some(timer) = current {
63 if core::ptr::eq(timer.ets_timer, ets_timer) {
64 return Some(timer);
65 }
66 current = timer.next.as_mut();
67 }
68
69 None
70 }
71
72 pub(crate) unsafe fn find_next_due(
73 &mut self,
74 current_timestamp: u64,
75 ) -> Option<&mut Box<Timer>> {
76 let mut current = self.head.as_mut();
77 while let Some(timer) = current {
78 if timer.active
79 && crate::time::time_diff(timer.started, current_timestamp) >= timer.timeout
80 {
81 return Some(timer);
82 }
83 current = timer.next.as_mut();
84 }
85
86 None
87 }
88
89 fn remove(&mut self, ets_timer: *mut ets_timer) {
90 if let Some(head) = self.head.as_mut() {
91 if core::ptr::eq(head.ets_timer, ets_timer) {
92 self.head = head.next.take();
93 return;
94 }
95 }
96
97 let timer = self.find(ets_timer);
98 if let Some(to_remove) = timer {
99 let tail = to_remove.next.take();
100
101 let mut current = self.head.as_mut();
102 let before = {
103 let mut found = None;
104 while let Some(before) = current {
105 if core::ptr::eq(before.next.as_mut().unwrap().ets_timer, ets_timer) {
106 found = Some(before);
107 break;
108 }
109 current = before.next.as_mut();
110 }
111 found
112 };
113
114 if let Some(before) = before {
115 let to_remove = before.next.take().unwrap();
116 let to_remove = Box::into_raw(to_remove);
117 unsafe {
118 crate::compat::malloc::free(to_remove as *mut _);
119 }
120 before.next = tail;
121 }
122 }
123 }
124
125 fn push(&mut self, to_add: Box<Timer>) -> Result<(), ()> {
126 if self.head.is_none() {
127 self.head = Some(to_add);
128 return Ok(());
129 }
130
131 let mut current = self.head.as_mut();
132 while let Some(timer) = current {
133 if timer.next.is_none() {
134 timer.next = Some(to_add);
135 break;
136 }
137 current = timer.next.as_mut();
138 }
139 Ok(())
140 }
141}
142
143unsafe impl Send for TimerQueue {}
144
145pub(crate) static TIMERS: Locked<TimerQueue> = Locked::new(TimerQueue::new());
146
147pub(crate) fn compat_timer_arm(ets_timer: *mut ets_timer, tmout: u32, repeat: bool) {
148 compat_timer_arm_us(ets_timer, tmout * 1000, repeat);
149}
150
151pub(crate) fn compat_timer_arm_us(ets_timer: *mut ets_timer, us: u32, repeat: bool) {
152 let systick = crate::time::systimer_count();
153 let ticks = crate::time::micros_to_ticks(us as u64);
154
155 trace!(
156 "timer_arm_us {:x} current: {} ticks: {} repeat: {}",
157 ets_timer as usize, systick, ticks, repeat
158 );
159
160 TIMERS.with(|timers| {
161 if let Some(timer) = timers.find(ets_timer) {
162 timer.started = systick;
163 timer.timeout = ticks;
164 timer.active = true;
165 timer.periodic = repeat;
166 } else {
167 trace!("timer_arm_us {:x} not found", ets_timer as usize);
168 }
169 })
170}
171
172pub fn compat_timer_disarm(ets_timer: *mut ets_timer) {
173 trace!("timer disarm");
174 TIMERS.with(|timers| {
175 if let Some(timer) = timers.find(ets_timer) {
176 trace!("timer_disarm {:x}", timer.id());
177 timer.active = false;
178 } else {
179 trace!("timer_disarm {:x} not found", ets_timer as usize);
180 }
181 })
182}
183
184pub fn compat_timer_done(ets_timer: *mut ets_timer) {
185 trace!("timer done");
186 TIMERS.with(|timers| {
187 if let Some(timer) = timers.find(ets_timer) {
188 trace!("timer_done {:x}", timer.id());
189 timer.active = false;
190
191 unsafe {
192 (*ets_timer).priv_ = core::ptr::null_mut();
193 (*ets_timer).expire = 0;
194 }
195
196 timers.remove(ets_timer);
197 } else {
198 trace!("timer_done {:x} not found", ets_timer as usize);
199 }
200 })
201}
202
203pub(crate) fn compat_timer_setfn(
204 ets_timer: *mut ets_timer,
205 pfunction: unsafe extern "C" fn(*mut c_types::c_void),
206 parg: *mut c_types::c_void,
207) {
208 trace!(
209 "timer_setfn {:x} {:?} {:?}",
210 ets_timer as usize, pfunction, parg
211 );
212 let set = TIMERS.with(|timers| unsafe {
213 if let Some(timer) = timers.find(ets_timer) {
214 timer.callback = TimerCallback::new(pfunction, parg);
215 timer.active = false;
216
217 (*ets_timer).expire = 0;
218
219 true
220 } else {
221 (*ets_timer).next = core::ptr::null_mut();
222 (*ets_timer).period = 0;
223 (*ets_timer).func = None;
224 (*ets_timer).priv_ = core::ptr::null_mut();
225
226 let timer =
227 crate::compat::malloc::calloc(1, core::mem::size_of::<Timer>()) as *mut Timer;
228 (*timer).next = None;
229 (*timer).ets_timer = ets_timer;
230 (*timer).started = 0;
231 (*timer).timeout = 0;
232 (*timer).active = false;
233 (*timer).periodic = false;
234 (*timer).callback = TimerCallback::new(pfunction, parg);
235
236 timers.push(Box::from_raw(timer)).is_ok()
237 }
238 });
239
240 if !set {
241 warn!("Failed to set timer function {:x}", ets_timer as usize);
242 }
243}