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}