1use crate::InterruptContext;
2use crate::base::*;
3use crate::prelude::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 = freertos_rs_timer_create(
100 name.as_ptr(),
101 name_len as u8,
102 period_ticks,
103 if auto_reload { 1 } else { 0 },
104 param_ptr,
105 timer_callback,
106 );
107
108 ((ret as usize) != 0, ret)
109 };
110
111 if success {
112 mem::forget(f);
113 } else {
114 return Err(FreeRtosError::OutOfMemory);
115 }
116
117 extern "C" fn timer_callback(handle: FreeRtosTimerHandle) -> () {
118 unsafe {
119 {
120 let timer = Timer { handle };
121 if let Ok(callback_ptr) = timer.get_id() {
122 let b = Box::from_raw(callback_ptr as *mut Box<dyn Fn(&Timer)>);
123 b(&timer);
124 let _ = Box::into_raw(b);
125 }
126 mem::forget(timer);
127 }
128 }
129 }
130
131 Ok(Timer {
132 handle: timer_handle as *const _,
133 })
134 }
135
136 fn spawn<F>(
137 name: &str,
138 period_tick: FreeRtosTickType,
139 auto_reload: bool,
140 callback: F,
141 ) -> Result<Timer, FreeRtosError>
142 where
143 F: Fn(&Timer) -> (),
144 F: Send + 'static,
145 {
146 unsafe { Timer::spawn_inner(name, period_tick, auto_reload, Box::new(callback)) }
147 }
148
149 pub fn start<D: DurationTicks>(&self, block_time: D) -> Result<(), FreeRtosError> {
151 unsafe {
152 if freertos_rs_timer_start(self.handle, block_time.to_ticks()) == 0 {
153 Ok(())
154 } else {
155 Err(FreeRtosError::Timeout)
156 }
157 }
158 }
159
160 pub fn start_from_isr(&self, context: &mut InterruptContext) -> Result<(), FreeRtosError> {
162 unsafe {
163 if freertos_rs_timer_start_from_isr(self.handle, context.get_task_field_mut()) == 0 {
164 Ok(())
165 } else {
166 Err(FreeRtosError::QueueSendTimeout)
167 }
168 }
169 }
170
171 pub fn stop<D: DurationTicks>(&self, block_time: D) -> Result<(), FreeRtosError> {
173 unsafe {
174 if freertos_rs_timer_stop(self.handle, block_time.to_ticks()) == 0 {
175 Ok(())
176 } else {
177 Err(FreeRtosError::Timeout)
178 }
179 }
180 }
181
182 pub fn change_period<D: DurationTicks>(
184 &self,
185 block_time: D,
186 new_period: D,
187 ) -> Result<(), FreeRtosError> {
188 unsafe {
189 if freertos_rs_timer_change_period(
190 self.handle,
191 block_time.to_ticks(),
192 new_period.to_ticks(),
193 ) == 0
194 {
195 Ok(())
196 } else {
197 Err(FreeRtosError::Timeout)
198 }
199 }
200 }
201
202 pub fn detach(self) {
209 mem::forget(self);
210 }
211
212 fn get_id(&self) -> Result<FreeRtosVoidPtr, FreeRtosError> {
213 unsafe { Ok(freertos_rs_timer_get_id(self.handle)) }
214 }
215}
216
217impl Drop for Timer {
218 #[allow(unused_must_use)]
219 fn drop(&mut self) {
220 unsafe {
221 if let Ok(callback_ptr) = self.get_id() {
222 Box::from_raw(callback_ptr as *mut Box<dyn Fn(Timer)>);
224 }
225
226 freertos_rs_timer_delete(self.handle, Duration::ms(1000).to_ticks());
228 }
229 }
230}