1use crate::InterruptContext;
2use crate::base::*;
3use crate::base_type::v1::*;
4use crate::shim::*;
5use crate::units::*;
6
7unsafe impl Send for Timer {}
8unsafe impl Sync for Timer {}
9
10pub struct Timer {
16 handle: FreeRtosTimerHandle,
17}
18
19pub struct TimerBuilder<D: DurationTicks> {
21 name: String,
22 period: D,
23 auto_reload: bool,
24}
25
26impl<D: DurationTicks> TimerBuilder<D> {
27 pub fn set_name(&mut self, name: &str) -> &mut Self {
29 self.name = name.into();
30 self
31 }
32
33 pub fn set_period(&mut self, period: D) -> &mut Self {
35 self.period = period;
36 self
37 }
38
39 pub fn set_auto_reload(&mut self, auto_reload: bool) -> &mut Self {
41 self.auto_reload = auto_reload;
42 self
43 }
44
45 pub fn create<F>(&self, callback: F) -> Result<Timer, FreeRtosError>
49 where
50 F: Fn(&Timer) -> (),
51 F: Send + 'static,
52 {
53 Timer::spawn(
54 self.name.as_str(),
55 self.period.to_ticks(),
56 self.auto_reload,
57 callback,
58 )
59 }
60}
61
62impl Timer {
63 pub fn new<D: DurationTicks>(period: D) -> TimerBuilder<D> {
65 TimerBuilder {
66 name: "timer".into(),
67 period: period,
68 auto_reload: true,
69 }
70 }
71
72 #[inline]
78 pub unsafe fn from_raw_handle(handle: FreeRtosTimerHandle) -> Self {
79 Self { handle }
80 }
81 #[inline]
82 pub fn raw_handle(&self) -> FreeRtosTimerHandle {
83 self.handle
84 }
85
86 unsafe fn spawn_inner<'a>(
87 name: &str,
88 period_ticks: FreeRtosTickType,
89 auto_reload: bool,
90 callback: Box<dyn Fn(&Timer) + Send + 'a>,
91 ) -> Result<Timer, FreeRtosError> {
92 let f = Box::new(callback);
93 let param_ptr = &*f as *const _ as *mut _;
94
95 let (success, timer_handle) = {
96 let name = name.as_bytes();
97 let name_len = name.len();
98
99 let ret = unsafe {
100 freertos_rs_timer_create(
101 name.as_ptr(),
102 name_len as u8,
103 period_ticks,
104 if auto_reload { 1 } else { 0 },
105 param_ptr,
106 timer_callback,
107 )
108 };
109
110 ((ret as usize) != 0, ret)
111 };
112
113 if success {
114 mem::forget(f);
115 } else {
116 return Err(FreeRtosError::OutOfMemory);
117 }
118
119 extern "C" fn timer_callback(handle: FreeRtosTimerHandle) -> () {
120 unsafe {
121 {
122 let timer = Timer { handle };
123 if let Ok(callback_ptr) = timer.get_id() {
124 let b = Box::from_raw(callback_ptr as *mut Box<dyn Fn(&Timer)>);
125 b(&timer);
126 let _ = Box::into_raw(b);
127 }
128 mem::forget(timer);
129 }
130 }
131 }
132
133 Ok(Timer {
134 handle: timer_handle as *const _,
135 })
136 }
137
138 fn spawn<F>(
139 name: &str,
140 period_tick: FreeRtosTickType,
141 auto_reload: bool,
142 callback: F,
143 ) -> Result<Timer, FreeRtosError>
144 where
145 F: Fn(&Timer) -> (),
146 F: Send + 'static,
147 {
148 unsafe { Timer::spawn_inner(name, period_tick, auto_reload, Box::new(callback)) }
149 }
150
151 pub fn start<D: DurationTicks>(&self, block_time: D) -> Result<(), FreeRtosError> {
153 unsafe {
154 if freertos_rs_timer_start(self.handle, block_time.to_ticks()) == 0 {
155 Ok(())
156 } else {
157 Err(FreeRtosError::Timeout)
158 }
159 }
160 }
161
162 pub fn start_from_isr(&self, context: &mut InterruptContext) -> Result<(), FreeRtosError> {
164 unsafe {
165 if freertos_rs_timer_start_from_isr(self.handle, context.get_task_field_mut()) == 0 {
166 Ok(())
167 } else {
168 Err(FreeRtosError::QueueSendTimeout)
169 }
170 }
171 }
172
173 pub fn stop<D: DurationTicks>(&self, block_time: D) -> Result<(), FreeRtosError> {
175 unsafe {
176 if freertos_rs_timer_stop(self.handle, block_time.to_ticks()) == 0 {
177 Ok(())
178 } else {
179 Err(FreeRtosError::Timeout)
180 }
181 }
182 }
183
184 pub fn change_period<D: DurationTicks>(
186 &self,
187 block_time: D,
188 new_period: D,
189 ) -> Result<(), FreeRtosError> {
190 unsafe {
191 if freertos_rs_timer_change_period(
192 self.handle,
193 block_time.to_ticks(),
194 new_period.to_ticks(),
195 ) == 0
196 {
197 Ok(())
198 } else {
199 Err(FreeRtosError::Timeout)
200 }
201 }
202 }
203
204 pub fn detach(self) {
211 mem::forget(self);
212 }
213
214 fn get_id(&self) -> Result<FreeRtosVoidPtr, FreeRtosError> {
215 unsafe { Ok(freertos_rs_timer_get_id(self.handle)) }
216 }
217}
218
219impl Drop for Timer {
220 #[allow(unused_must_use)]
221 fn drop(&mut self) {
222 unsafe {
223 if let Ok(callback_ptr) = self.get_id() {
224 Box::from_raw(callback_ptr as *mut Box<dyn Fn(Timer)>);
226 }
227
228 freertos_rs_timer_delete(self.handle, Duration::ms(1000).to_ticks());
230 }
231 }
232}