1use core::any::Any;
21use core::ffi::{c_char, c_void};
22use core::fmt::{Debug, Display, Formatter};
23use core::ops::Deref;
24use core::ptr::null_mut;
25
26use alloc::boxed::Box;
27use alloc::string::{String, ToString};
28use alloc::sync::Arc;
29
30use super::ffi::{INVALID, TaskStatus, ThreadHandle, pdPASS, pdTRUE, vTaskDelete, vTaskGetInfo, vTaskResume, vTaskSuspend, xTaskCreate, xTaskGetCurrentTaskHandle};
31use super::types::{StackType, UBaseType, BaseType, TickType};
32use super::thread::ThreadState::*;
33use crate::os::ThreadSimpleFnPtr;
34use crate::traits::{ThreadFn, ThreadParam, ThreadFnPtr, ThreadNotification, ToTick, ToPriority};
35use crate::utils::{Result, Error, DoublePtr};
36use crate::{from_c_str, xTaskNotify, xTaskNotifyFromISR, xTaskNotifyWait};
37
38#[derive(Copy, Clone, Debug, PartialEq)]
39#[repr(u8)]
40pub enum ThreadState {
41 Running = 0,
42 Ready = 1,
43 Blocked = 2,
44 Suspended = 3,
45 Deleted = 4,
46 Invalid,
47}
48
49#[derive(Clone, Debug)]
50pub struct ThreadMetadata {
51 pub thread: ThreadHandle,
52 pub name: String,
53 pub stack_depth: StackType,
54 pub priority: UBaseType,
55 pub thread_number: UBaseType,
56 pub state: ThreadState,
57 pub current_priority: UBaseType,
58 pub base_priority: UBaseType,
59 pub run_time_counter: UBaseType,
60 pub stack_high_water_mark: StackType,
61}
62
63unsafe impl Send for ThreadMetadata {}
64unsafe impl Sync for ThreadMetadata {}
65
66impl From<(ThreadHandle,TaskStatus)> for ThreadMetadata {
67 fn from(status: (ThreadHandle, TaskStatus)) -> Self {
68 let state = match status.1.eCurrentState {
69 0 => Running,
70 1 => Ready,
71 2 => Blocked,
72 3 => Suspended,
73 4 => Deleted,
74 _ => Invalid,
75 };
76
77 ThreadMetadata {
78 thread: status.0,
79 name: from_c_str!(status.1.pcTaskName),
80 stack_depth: 0,
83 priority: status.1.uxBasePriority,
84 thread_number: status.1.xTaskNumber,
85 state,
86 current_priority: status.1.uxCurrentPriority,
87 base_priority: status.1.uxBasePriority,
88 run_time_counter: status.1.ulRunTimeCounter,
89 stack_high_water_mark: status.1.usStackHighWaterMark,
90 }
91 }
92}
93
94impl Default for ThreadMetadata {
95 fn default() -> Self {
96 ThreadMetadata {
97 thread: null_mut(),
98 name: String::new(),
99 stack_depth: 0,
100 priority: 0,
101 thread_number: 0,
102 state: Invalid,
103 current_priority: 0,
104 base_priority: 0,
105 run_time_counter: 0,
106 stack_high_water_mark: 0,
107 }
108 }
109}
110
111#[derive(Clone)]
112pub struct Thread {
113 handle: ThreadHandle,
114 name: String,
115 stack_depth: StackType,
116 priority: UBaseType,
117 callback: Option<Arc<ThreadFnPtr>>,
118 param: Option<ThreadParam>
119}
120
121unsafe impl Send for Thread {}
122unsafe impl Sync for Thread {}
123
124impl Thread {
125
126 pub fn new_with_to_priority(name: &str, stack_depth: StackType, priority: impl ToPriority) -> Self
127 {
128 Self {
129 handle: null_mut(),
130 name: name.to_string(),
131 stack_depth,
132 priority: priority.to_priority(),
133 callback: None,
134 param: None
135 }
136 }
137
138 pub fn new_with_handle_and_to_priority(handle: ThreadHandle, name: &str, stack_depth: StackType, priority: impl ToPriority) -> Result<Self> {
139 if handle.is_null() {
140 return Err(Error::NullPtr);
141 }
142 Ok(Self {
143 handle,
144 name: name.to_string(),
145 stack_depth,
146 priority: priority.to_priority(),
147 callback: None,
148 param: None
149 })
150 }
151
152 pub fn get_metadata_from_handle(handle: ThreadHandle) -> ThreadMetadata {
153 let mut status = TaskStatus::default();
154 unsafe {
155 vTaskGetInfo(handle, &mut status, pdTRUE, INVALID);
156 }
157 ThreadMetadata::from((handle, status))
158 }
159
160 pub fn get_metadata(thread: &Thread) -> ThreadMetadata {
161 if thread.handle.is_null() {
162 return ThreadMetadata::default();
163 }
164 Self::get_metadata_from_handle(thread.handle)
165 }
166
167 #[inline]
168 pub fn wait_notification_with_to_tick(&self, bits_to_clear_on_entry: u32, bits_to_clear_on_exit: u32 , timeout_ticks: impl ToTick) -> Result<u32> {
169 if self.handle.is_null() {
170 return Err(Error::NullPtr);
171 }
172 self.wait_notification(bits_to_clear_on_entry, bits_to_clear_on_exit, timeout_ticks.to_ticks())
173 }
174
175}
176
177unsafe extern "C" fn callback_c_wrapper(param_ptr: *mut c_void) {
178 if param_ptr.is_null() {
179 return;
180 }
181
182 let mut thread_instance: Box<Thread> = unsafe { Box::from_raw(param_ptr as *mut _) };
183
184 thread_instance.as_mut().handle = unsafe { xTaskGetCurrentTaskHandle() };
185
186 let thread = *thread_instance.clone();
187
188 let param_arc: Option<ThreadParam> = thread_instance
189 .param
190 .clone();
191
192 if let Some(callback) = &thread_instance.callback.clone() {
193 let _ = callback(thread_instance, param_arc);
194 }
195
196 thread.delete();
197}
198
199unsafe extern "C" fn simple_callback_wrapper(param_ptr: *mut c_void) {
200 if param_ptr.is_null() {
201 return;
202 }
203
204 let func: Box<Arc<ThreadSimpleFnPtr>> = unsafe { Box::from_raw(param_ptr as *mut _) };
205 func();
206
207 unsafe { vTaskDelete( xTaskGetCurrentTaskHandle()); }
208}
209
210
211
212impl ThreadFn for Thread {
213 fn new(name: &str, stack_depth: StackType, priority: UBaseType) -> Self
214 {
215 Self {
216 handle: null_mut(),
217 name: name.to_string(),
218 stack_depth,
219 priority,
220 callback: None,
221 param: None
222 }
223 }
224
225 fn new_with_handle(handle: ThreadHandle, name: &str, stack_depth: StackType, priority: UBaseType) -> Result<Self> {
226 if handle.is_null() {
227 return Err(Error::NullPtr);
228 }
229 Ok(Self {
230 handle,
231 name: name.to_string(),
232 stack_depth,
233 priority,
234 callback: None,
235 param: None
236 })
237 }
238
239 fn spawn<F>(&mut self, param: Option<ThreadParam>, callback: F) -> Result<Self>
255 where
256 F: Fn(Box<dyn ThreadFn>, Option<ThreadParam>) -> Result<ThreadParam>,
257 F: Send + Sync + 'static {
258
259 let mut handle: ThreadHandle = null_mut();
260
261 let func: Arc<ThreadFnPtr> = Arc::new(callback);
262
263 self.callback = Some(func);
264 self.param = param.clone();
265
266 let boxed_thread = Box::new(self.clone());
267
268 let ret = unsafe {
269 xTaskCreate(
270 Some(super::thread::callback_c_wrapper),
271 self.name.clone().as_ptr() as *const c_char,
272 self.stack_depth,
273 Box::into_raw(boxed_thread) as *mut _,
274 self.priority,
275 &mut handle,
276 )
277 };
278
279 if ret != pdPASS {
280 return Err(Error::OutOfMemory)
281 }
282
283 Ok(Self {
284 handle,
285 callback: self.callback.clone(),
286 param,
287 ..self.clone()
288 })
289 }
290
291 fn spawn_simple<F>(&mut self, callback: F) -> Result<Self>
307 where
308 F: Fn() + Send + Sync + 'static,
309 {
310 let func: Arc<ThreadSimpleFnPtr> = Arc::new(callback);
311 let boxed_func = Box::new(func);
312
313 let mut handle: ThreadHandle = null_mut();
314
315
316 let ret = unsafe {
317 xTaskCreate(
318 Some(simple_callback_wrapper),
319 self.name.clone().as_ptr() as *const c_char,
320 self.stack_depth,
321 Box::into_raw(boxed_func) as *mut _,
322 self.priority,
323 &mut handle,
324 )
325 };
326
327 if ret != pdPASS {
328 return Err(Error::OutOfMemory);
329 }
330
331 Ok(Self {
332 handle,
333 ..self.clone()
334 })
335 }
336
337 fn delete(&self) {
338 if !self.handle.is_null() {
339 unsafe { vTaskDelete( self.handle ); }
340 }
341 }
342
343 fn suspend(&self) {
344 if !self.handle.is_null() {
345 unsafe { vTaskSuspend( self.handle ); }
346 }
347 }
348
349 fn resume(&self) {
350 if !self.handle.is_null() {
351 unsafe { vTaskResume( self.handle ); }
352 }
353 }
354
355 fn join(&self, _retval: DoublePtr) -> Result<i32> {
356 if !self.handle.is_null() {
357 unsafe { vTaskDelete( self.handle ); }
358 }
359 Ok(0)
360 }
361
362 fn get_metadata(&self) -> ThreadMetadata {
363 let mut status = TaskStatus::default();
364 unsafe {
365 vTaskGetInfo(self.handle, &mut status, pdTRUE, INVALID);
366 }
367 ThreadMetadata::from((self.handle, status))
368 }
369
370 fn get_current() -> Self {
371 let handle = unsafe { xTaskGetCurrentTaskHandle() };
372 let metadata = Self::get_metadata_from_handle(handle);
373 Self {
374 handle,
375 name: metadata.name,
376 stack_depth: metadata.stack_depth,
377 priority: metadata.priority,
378 callback: None,
379 param: None,
380 }
381 }
382
383 fn notify(&self, notification: ThreadNotification) -> Result<()> {
384 if self.handle.is_null() {
385 return Err(Error::NullPtr);
386 }
387
388 let (action, value) = notification.into();
389
390 let ret = xTaskNotify!(
391 self.handle,
392 value,
393 action
394 );
395
396 if ret != pdPASS {
397 Err(Error::QueueFull)
398 } else {
399 Ok(())
400 }
401
402 }
403
404 fn notify_from_isr(&self, notification: ThreadNotification, higher_priority_task_woken: &mut BaseType) -> Result<()> {
405 if self.handle.is_null() {
406 return Err(Error::NullPtr);
407 }
408
409 let (action, value) = notification.into();
410
411 let ret = xTaskNotifyFromISR!(
412 self.handle,
413 value,
414 action,
415 higher_priority_task_woken
416 );
417
418 if ret != pdPASS {
419 Err(Error::QueueFull)
420 } else {
421 Ok(())
422 }
423 }
424
425 fn wait_notification(&self, bits_to_clear_on_entry: u32, bits_to_clear_on_exit: u32 , timeout_ticks: TickType) -> Result<u32> {
426 if self.handle.is_null() {
427 return Err(Error::NullPtr);
428 }
429
430 let mut notification_value: u32 = 0;
431
432 let ret = xTaskNotifyWait!(
433 bits_to_clear_on_entry,
434 bits_to_clear_on_exit,
435 &mut notification_value,
436 timeout_ticks
437 );
438
439
440 if ret == pdTRUE {
441 Ok(notification_value)
442 } else {
443 Err(Error::Timeout)
444 }
445 }
446
447}
448
449
450impl Deref for Thread {
459 type Target = ThreadHandle;
460
461 fn deref(&self) -> &Self::Target {
462 &self.handle
463 }
464}
465
466impl Debug for Thread {
467 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
468 f.debug_struct("Thread")
469 .field("handle", &self.handle)
470 .field("name", &self.name)
471 .field("stack_depth", &self.stack_depth)
472 .field("priority", &self.priority)
473 .field("callback", &self.callback.as_ref().map(|_| "Some(...)"))
474 .field("param", &self.param)
475 .finish()
476 }
477}
478
479impl Display for Thread {
480 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
481 write!(f, "Thread {{ handle: {:?}, name: {}, priority: {}, stack_depth: {} }}", self.handle, self.name, self.priority, self.stack_depth)
482 }
483}
484
485