osal_rs/freertos/
timer.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2023/2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 ***************************************************************************/
19
20use core::any::Any;
21use core::fmt::{Debug, Display};
22use core::ops::Deref;
23use core::ptr::null_mut;
24
25use alloc::boxed::Box;
26use alloc::string::{String, ToString};
27use alloc::sync::Arc;
28
29use crate::freertos::ffi::pdPASS;
30use crate::to_c_str;
31use crate::traits::{ToTick, TimerParam, TimerFn, TimerFnPtr};
32use crate::utils::{OsalRsBool, Result, Error};
33use super::ffi::{TimerHandle, pvTimerGetTimerID, xTimerCreate, osal_rs_timer_start, osal_rs_timer_change_period, osal_rs_timer_delete, osal_rs_timer_reset, osal_rs_timer_stop};
34use super::types::{TickType};
35
36#[derive(Clone)]
37pub struct Timer {
38    pub handle: TimerHandle,
39    name: String, 
40    callback: Option<Arc<TimerFnPtr>>,
41    param: Option<TimerParam>, 
42}
43
44unsafe impl Send for Timer {}
45unsafe impl Sync for Timer {}
46
47impl Timer {
48    #[inline]
49    pub fn new_with_to_tick<F>(name: &str, timer_period_in_ticks: impl ToTick, auto_reload: bool, param: Option<TimerParam>, callback: F) -> Result<Self>
50    where
51        F: Fn(Box<dyn TimerFn>, Option<TimerParam>) -> Result<TimerParam> + Send + Sync + Clone + 'static {
52            Self::new(name, timer_period_in_ticks.to_ticks(), auto_reload, param, callback)
53        }
54
55    #[inline]
56    pub fn start_with_to_tick(&self, ticks_to_wait: impl ToTick) -> OsalRsBool {
57        self.start(ticks_to_wait.to_ticks())
58    }
59
60    #[inline]
61    pub fn stop_with_to_tick(&self, ticks_to_wait: impl ToTick)  -> OsalRsBool {
62        self.stop(ticks_to_wait.to_ticks())
63    }
64
65    #[inline]
66    pub fn reset_with_to_tick(&self, ticks_to_wait: impl ToTick) -> OsalRsBool {
67        self.reset(ticks_to_wait.to_ticks())
68    }
69
70    #[inline]
71    pub fn change_period_with_to_tick(&self, new_period_in_ticks: impl ToTick, new_period_ticks: impl ToTick) -> OsalRsBool {
72        self.change_period(new_period_in_ticks.to_ticks(), new_period_ticks.to_ticks())
73    }
74
75    #[inline]
76    pub fn delete_with_to_tick(&mut self, ticks_to_wait: impl ToTick) -> OsalRsBool {
77        self.delete(ticks_to_wait.to_ticks())
78    }
79}
80
81extern "C" fn callback_c_wrapper(handle: TimerHandle) {
82
83    if handle.is_null() {
84        return;
85    }
86
87    let param_ptr = unsafe {
88        pvTimerGetTimerID(handle) 
89    };
90    
91    let mut timer_instance: Box<Timer> = unsafe { Box::from_raw(param_ptr as *mut _) };
92
93    timer_instance.as_mut().handle = handle;
94
95    let param_arc: Option<Arc<dyn Any + Send + Sync>> = timer_instance
96        .param
97        .clone();
98
99    if let Some(callback) = &timer_instance.callback.clone() {
100        let _ = callback(timer_instance, param_arc);
101    }
102}
103
104impl TimerFn for Timer {
105    fn new<F>(name: &str, timer_period_in_ticks: TickType, auto_reload: bool, param: Option<TimerParam>, callback: F) -> Result<Self>
106    where
107        F: Fn(Box<dyn TimerFn>, Option<TimerParam>) -> Result<TimerParam> + Send + Sync + Clone + 'static {
108
109            let mut boxed_timer = Box::new(Self {
110                handle: core::ptr::null_mut(),
111                name: name.to_string(),
112                callback: Some(Arc::new(callback.clone())),
113                param: param.clone(),
114            });
115
116            let handle = unsafe {
117                xTimerCreate( to_c_str!(name), 
118                    timer_period_in_ticks, 
119                    if auto_reload { 1 } else { 0 }, 
120                    Box::into_raw(boxed_timer.clone()) as *mut _, 
121                    Some(super::timer::callback_c_wrapper)
122                )
123            };
124
125            if handle.is_null() {
126                Err(Error::NullPtr)
127            } else {
128                boxed_timer.as_mut().handle = handle;
129                Ok(*boxed_timer)
130            }
131
132    }
133
134    fn start(&self, ticks_to_wait: TickType) -> OsalRsBool {
135        if unsafe {
136            osal_rs_timer_start(self.handle, ticks_to_wait)
137        } != pdPASS {
138            OsalRsBool::False
139        } else {
140            OsalRsBool::True
141        }
142    }
143
144    fn stop(&self, ticks_to_wait: TickType)  -> OsalRsBool {
145        if unsafe {
146            osal_rs_timer_stop(self.handle, ticks_to_wait)
147        } != pdPASS {
148            OsalRsBool::False
149        } else {
150            OsalRsBool::True
151        }
152    }
153
154    fn reset(&self, ticks_to_wait: TickType) -> OsalRsBool {
155        if unsafe {
156            osal_rs_timer_reset(self.handle, ticks_to_wait)
157        } != pdPASS {
158            OsalRsBool::False
159        } else {
160            OsalRsBool::True
161        }
162    }
163
164    fn change_period(&self, new_period_in_ticks: TickType, new_period_ticks: TickType) -> OsalRsBool {
165        if unsafe {
166            osal_rs_timer_change_period(self.handle, new_period_in_ticks, new_period_ticks)
167        } != pdPASS {
168            OsalRsBool::False
169        } else {
170            OsalRsBool::True
171        }
172    }
173
174    fn delete(&mut self, ticks_to_wait: TickType) -> OsalRsBool {
175        if unsafe {
176            osal_rs_timer_delete(self.handle, ticks_to_wait)
177        } != pdPASS {
178            self.handle = null_mut();
179            OsalRsBool::False
180        } else {
181            self.handle = null_mut();
182            OsalRsBool::True
183        }
184    }
185}
186
187impl Drop for Timer {
188    fn drop(&mut self) {
189        self.delete(0);
190    }
191}
192
193impl Deref for Timer {
194    type Target = TimerHandle;
195
196    fn deref(&self) -> &Self::Target {
197        &self.handle
198    }
199}
200
201impl Debug for Timer {
202    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
203        f.debug_struct("Timer")
204            .field("handle", &self.handle)
205            .field("name", &self.name)
206            .finish()
207    }
208}
209
210impl Display for Timer {
211    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
212        write!(f, "Timer {{ name: {}, handle: {:?} }}", self.name, self.handle)
213    }
214}