autd_timer/
timer.rs

1/*
2 * File: timer.rs
3 * Project: src
4 * Created Date: 23/05/2020
5 * Author: Shun Suzuki
6 * -----
7 * Last Modified: 31/12/2020
8 * Modified By: Shun Suzuki (suzuki@hapis.k.u-tokyo.ac.jp)
9 * -----
10 * Copyright (c) 2020 Hapis Lab. All rights reserved.
11 *
12 */
13
14use crate::NativeTimerWrapper;
15
16#[cfg(target_os = "windows")]
17use winapi::shared::basetsd::DWORD_PTR;
18
19#[cfg(target_os = "linux")]
20use libc::{c_int, c_void, siginfo_t};
21
22#[cfg(target_os = "macos")]
23use libc::c_void;
24
25pub struct Timer {
26    native_timer: NativeTimerWrapper,
27    cb: Option<Box<dyn FnMut() + Send>>,
28}
29
30impl Timer {
31    pub fn new() -> Self {
32        Self {
33            native_timer: NativeTimerWrapper::new(),
34            cb: None,
35        }
36    }
37
38    pub fn start<F>(&mut self, cb: F, period_ns: u32)
39    where
40        F: 'static + FnMut() + Send,
41    {
42        self.cb = Some(Box::new(cb));
43        let ptr = self as *mut Self;
44        self.native_timer
45            .start(Some(Self::rt_thread), period_ns, ptr);
46    }
47
48    pub fn close(&mut self) {
49        self.native_timer.close();
50    }
51
52    #[cfg(target_os = "windows")]
53    unsafe extern "system" fn rt_thread(
54        _u_timer_id: u32,
55        _u_msg: u32,
56        dw_user: DWORD_PTR,
57        _dw1: DWORD_PTR,
58        _dw2: DWORD_PTR,
59    ) {
60        let ptr = dw_user as *mut Self;
61        if let Some(cb) = &mut (*ptr).cb {
62            cb();
63        }
64    }
65
66    #[cfg(target_os = "linux")]
67    unsafe extern "C" fn rt_thread(_sig: c_int, si: *mut siginfo_t, _uc: *mut c_void) {
68        let ptr = Self::get_ptr(si);
69        let ptr = ptr as *mut Self;
70        if let Some(cb) = &mut (*ptr).cb {
71            cb();
72        }
73    }
74
75    #[cfg(target_os = "linux")]
76    #[allow(deprecated)]
77    unsafe extern "C" fn get_ptr(si: *mut siginfo_t) -> u64 {
78        // TODO: This depends on the deprecated field of libc crate, and may only work on a specific platforms.
79        let ptr_lsb = (*si)._pad[3];
80        let ptr_msb = (*si)._pad[4];
81        ((ptr_msb as u64) << 32) | (ptr_lsb as u64 & 0xFFFF_FFFF)
82    }
83
84    #[cfg(target_os = "macos")]
85    unsafe extern "C" fn rt_thread(ptr: *const c_void) {
86        let ptr = ptr as *mut Self;
87        if let Some(cb) = &mut (*ptr).cb {
88            cb();
89        }
90    }
91}
92
93impl Default for Timer {
94    fn default() -> Self {
95        Self::new()
96    }
97}