osal_rs/freertos/thread.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
20//! Thread management and synchronization for FreeRTOS.
21//!
22//! This module provides a safe Rust interface for creating and managing FreeRTOS tasks.
23//! It supports thread creation with callbacks, priority management, and thread notifications.
24
25use core::any::Any;
26use core::ffi::{c_char, c_void};
27use core::fmt::{Debug, Display, Formatter};
28use core::ops::Deref;
29use core::ptr::null_mut;
30
31use alloc::boxed::Box;
32use alloc::ffi::CString;
33use alloc::string::{String, ToString};
34use alloc::sync::Arc;
35
36use super::ffi::{INVALID, TaskStatus, ThreadHandle, pdPASS, pdTRUE, vTaskDelete, vTaskGetInfo, vTaskResume, vTaskSuspend, xTaskCreate, xTaskGetCurrentTaskHandle};
37use super::types::{StackType, UBaseType, BaseType, TickType};
38use super::thread::ThreadState::*;
39use crate::os::ThreadSimpleFnPtr;
40use crate::traits::{ThreadFn, ThreadParam, ThreadFnPtr, ThreadNotification, ToTick, ToPriority};
41use crate::utils::{Result, Error, DoublePtr};
42use crate::{from_c_str, xTaskNotify, xTaskNotifyFromISR, xTaskNotifyWait};
43
44/// Represents the possible states of a FreeRTOS task/thread.
45///
46/// # Examples
47///
48/// ```ignore
49/// use osal_rs::os::{Thread, ThreadState};
50///
51/// let thread = Thread::current();
52/// let metadata = thread.metadata().unwrap();
53///
54/// match metadata.state {
55/// ThreadState::Running => println!("Thread is currently executing"),
56/// ThreadState::Ready => println!("Thread is ready to run"),
57/// ThreadState::Blocked => println!("Thread is waiting for an event"),
58/// ThreadState::Suspended => println!("Thread is suspended"),
59/// _ => println!("Unknown state"),
60/// }
61/// ```
62#[derive(Copy, Clone, Debug, PartialEq)]
63#[repr(u8)]
64pub enum ThreadState {
65 /// Thread is currently executing on a CPU
66 Running = 0,
67 /// Thread is ready to run but not currently executing
68 Ready = 1,
69 /// Thread is blocked waiting for an event (e.g., semaphore, queue)
70 Blocked = 2,
71 /// Thread has been explicitly suspended
72 Suspended = 3,
73 /// Thread has been deleted
74 Deleted = 4,
75 /// Invalid or unknown state
76 Invalid,
77}
78
79/// Metadata and runtime information about a thread.
80///
81/// Contains detailed information about a thread's state, priorities, stack usage,
82/// and runtime statistics.
83///
84/// # Examples
85///
86/// ```ignore
87/// use osal_rs::os::Thread;
88///
89/// let thread = Thread::current();
90/// let metadata = thread.metadata().unwrap();
91///
92/// println!("Thread: {}", metadata.name);
93/// println!("Priority: {}", metadata.priority);
94/// println!("Stack high water mark: {}", metadata.stack_high_water_mark);
95/// ```
96#[derive(Clone, Debug)]
97pub struct ThreadMetadata {
98 /// FreeRTOS task handle
99 pub thread: ThreadHandle,
100 /// Thread name
101 pub name: String,
102 /// Original stack depth allocated for this thread
103 pub stack_depth: StackType,
104 /// Thread priority
105 pub priority: UBaseType,
106 /// Unique thread number assigned by FreeRTOS
107 pub thread_number: UBaseType,
108 /// Current execution state
109 pub state: ThreadState,
110 /// Current priority (may differ from base priority due to priority inheritance)
111 pub current_priority: UBaseType,
112 /// Base priority without inheritance
113 pub base_priority: UBaseType,
114 /// Total runtime counter (requires configGENERATE_RUN_TIME_STATS)
115 pub run_time_counter: UBaseType,
116 /// Minimum remaining stack space ever recorded (lower values indicate higher stack usage)
117 pub stack_high_water_mark: StackType,
118}
119
120unsafe impl Send for ThreadMetadata {}
121unsafe impl Sync for ThreadMetadata {}
122
123impl From<(ThreadHandle,TaskStatus)> for ThreadMetadata {
124 fn from(status: (ThreadHandle, TaskStatus)) -> Self {
125 let state = match status.1.eCurrentState {
126 0 => Running,
127 1 => Ready,
128 2 => Blocked,
129 3 => Suspended,
130 4 => Deleted,
131 _ => Invalid,
132 };
133
134 ThreadMetadata {
135 thread: status.0,
136 name: from_c_str!(status.1.pcTaskName),
137 // Avoid dereferencing pxStackBase, which may be null or otherwise invalid.
138 // Use 0 as a safe default for unknown stack depth.
139 stack_depth: 0,
140 priority: status.1.uxBasePriority,
141 thread_number: status.1.xTaskNumber,
142 state,
143 current_priority: status.1.uxCurrentPriority,
144 base_priority: status.1.uxBasePriority,
145 run_time_counter: status.1.ulRunTimeCounter,
146 stack_high_water_mark: status.1.usStackHighWaterMark,
147 }
148 }
149}
150
151impl Default for ThreadMetadata {
152 fn default() -> Self {
153 ThreadMetadata {
154 thread: null_mut(),
155 name: String::new(),
156 stack_depth: 0,
157 priority: 0,
158 thread_number: 0,
159 state: Invalid,
160 current_priority: 0,
161 base_priority: 0,
162 run_time_counter: 0,
163 stack_high_water_mark: 0,
164 }
165 }
166}
167
168/// A FreeRTOS task/thread wrapper.
169///
170/// Provides a safe Rust interface for creating and managing FreeRTOS tasks.
171/// Threads can be created with closures or function pointers and support
172/// various synchronization primitives.
173///
174/// # Examples
175///
176/// ## Creating a simple thread
177///
178/// ```ignore
179/// use osal_rs::os::{Thread, ThreadPriority};
180/// use core::time::Duration;
181///
182/// let thread = Thread::new(
183/// "worker",
184/// 2048, // stack size in words
185/// ThreadPriority::Normal,
186/// || {
187/// loop {
188/// println!("Working...");
189/// Duration::from_secs(1).sleep();
190/// }
191/// }
192/// ).unwrap();
193///
194/// thread.start().unwrap();
195/// ```
196///
197/// ## Using thread notifications
198///
199/// ```ignore
200/// use osal_rs::os::{Thread, ThreadNotification};
201/// use core::time::Duration;
202///
203/// let thread = Thread::new("notified", 2048, 5, || {
204/// loop {
205/// if let Some(value) = Thread::current().wait_notification(Duration::from_secs(1)) {
206/// println!("Received notification: {}", value);
207/// }
208/// }
209/// }).unwrap();
210///
211/// thread.start().unwrap();
212/// thread.notify(42).unwrap(); // Send notification
213/// ```
214#[derive(Clone)]
215pub struct Thread {
216 handle: ThreadHandle,
217 name: String,
218 stack_depth: StackType,
219 priority: UBaseType,
220 callback: Option<Arc<ThreadFnPtr>>,
221 param: Option<ThreadParam>
222}
223
224unsafe impl Send for Thread {}
225unsafe impl Sync for Thread {}
226
227impl Thread {
228
229 /// Creates a new thread with a priority that implements `ToPriority`.
230 ///
231 /// This is a convenience constructor that allows using various priority types.
232 ///
233 /// # Parameters
234 ///
235 /// * `name` - Thread name for debugging
236 /// * `stack_depth` - Stack size in words (not bytes)
237 /// * `priority` - Thread priority (any type implementing `ToPriority`)
238 ///
239 /// # Examples
240 ///
241 /// ```ignore
242 /// use osal_rs::os::Thread;
243 ///
244 /// let thread = Thread::new_with_to_priority("worker", 2048, 5);
245 /// ```
246 pub fn new_with_to_priority(name: &str, stack_depth: StackType, priority: impl ToPriority) -> Self
247 {
248 Self {
249 handle: null_mut(),
250 name: name.to_string(),
251 stack_depth,
252 priority: priority.to_priority(),
253 callback: None,
254 param: None
255 }
256 }
257
258 /// Creates a thread from an existing FreeRTOS task handle.
259 ///
260 /// # Parameters
261 ///
262 /// * `handle` - Valid FreeRTOS task handle
263 /// * `name` - Thread name
264 /// * `stack_depth` - Stack size
265 /// * `priority` - Thread priority
266 ///
267 /// # Returns
268 ///
269 /// * `Err(Error::NullPtr)` if handle is null
270 ///
271 /// # Examples
272 ///
273 /// ```ignore
274 /// use osal_rs::os::Thread;
275 ///
276 /// // Get current task handle from FreeRTOS
277 /// let handle = get_task_handle();
278 /// let thread = Thread::new_with_handle_and_to_priority(handle, "existing", 2048, 5).unwrap();
279 /// ```
280 pub fn new_with_handle_and_to_priority(handle: ThreadHandle, name: &str, stack_depth: StackType, priority: impl ToPriority) -> Result<Self> {
281 if handle.is_null() {
282 return Err(Error::NullPtr);
283 }
284 Ok(Self {
285 handle,
286 name: name.to_string(),
287 stack_depth,
288 priority: priority.to_priority(),
289 callback: None,
290 param: None
291 })
292 }
293
294 /// Retrieves metadata for a thread from its handle.
295 ///
296 /// # Parameters
297 ///
298 /// * `handle` - FreeRTOS task handle
299 ///
300 /// # Returns
301 ///
302 /// Thread metadata including state, priority, stack usage, etc.
303 ///
304 /// # Examples
305 ///
306 /// ```ignore
307 /// use osal_rs::os::Thread;
308 ///
309 /// let handle = get_some_task_handle();
310 /// let metadata = Thread::get_metadata_from_handle(handle);
311 /// println!("Thread '{}' state: {:?}", metadata.name, metadata.state);
312 /// ```
313 pub fn get_metadata_from_handle(handle: ThreadHandle) -> ThreadMetadata {
314 let mut status = TaskStatus::default();
315 unsafe {
316 vTaskGetInfo(handle, &mut status, pdTRUE, INVALID);
317 }
318 ThreadMetadata::from((handle, status))
319 }
320
321 /// Retrieves metadata for a thread object.
322 ///
323 /// # Parameters
324 ///
325 /// * `thread` - Thread reference
326 ///
327 /// # Returns
328 ///
329 /// Thread metadata or default if handle is null
330 ///
331 /// # Examples
332 ///
333 /// ```ignore
334 /// use osal_rs::os::Thread;
335 ///
336 /// let thread = Thread::new("worker", 2048, 5);
337 /// let metadata = Thread::get_metadata(&thread);
338 /// println!("Stack high water mark: {}", metadata.stack_high_water_mark);
339 /// ```
340 pub fn get_metadata(thread: &Thread) -> ThreadMetadata {
341 if thread.handle.is_null() {
342 return ThreadMetadata::default();
343 }
344 Self::get_metadata_from_handle(thread.handle)
345 }
346
347 /// Waits for a thread notification with a timeout that implements `ToTick`.
348 ///
349 /// Convenience method that accepts `Duration` or other tick-convertible types.
350 ///
351 /// # Parameters
352 ///
353 /// * `bits_to_clear_on_entry` - Bits to clear before waiting
354 /// * `bits_to_clear_on_exit` - Bits to clear after receiving notification
355 /// * `timeout_ticks` - Maximum time to wait (convertible to ticks)
356 ///
357 /// # Returns
358 ///
359 /// * `Ok(u32)` - Notification value received
360 /// * `Err(Error::NullPtr)` - Thread handle is null
361 /// * `Err(Error::Timeout)` - No notification received within timeout
362 ///
363 /// # Examples
364 ///
365 /// ```ignore
366 /// use osal_rs::os::{Thread, ThreadFn};
367 /// use core::time::Duration;
368 ///
369 /// let thread = Thread::current();
370 /// match thread.wait_notification_with_to_tick(0, 0xFF, Duration::from_secs(1)) {
371 /// Ok(value) => println!("Received: {}", value),
372 /// Err(_) => println!("Timeout"),
373 /// }
374 /// ```
375 #[inline]
376 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> {
377 if self.handle.is_null() {
378 return Err(Error::NullPtr);
379 }
380 self.wait_notification(bits_to_clear_on_entry, bits_to_clear_on_exit, timeout_ticks.to_ticks())
381 }
382
383}
384
385unsafe extern "C" fn callback_c_wrapper(param_ptr: *mut c_void) {
386 if param_ptr.is_null() {
387 return;
388 }
389
390 let mut thread_instance: Box<Thread> = unsafe { Box::from_raw(param_ptr as *mut _) };
391
392 thread_instance.as_mut().handle = unsafe { xTaskGetCurrentTaskHandle() };
393
394 let thread = *thread_instance.clone();
395
396 let param_arc: Option<ThreadParam> = thread_instance
397 .param
398 .clone();
399
400 if let Some(callback) = &thread_instance.callback.clone() {
401 let _ = callback(thread_instance, param_arc);
402 }
403
404 thread.delete();
405}
406
407unsafe extern "C" fn simple_callback_wrapper(param_ptr: *mut c_void) {
408 if param_ptr.is_null() {
409 return;
410 }
411
412 let func: Box<Arc<ThreadSimpleFnPtr>> = unsafe { Box::from_raw(param_ptr as *mut _) };
413 func();
414
415 unsafe { vTaskDelete( xTaskGetCurrentTaskHandle()); }
416}
417
418
419
420impl ThreadFn for Thread {
421 /// Creates a new uninitialized thread.
422 ///
423 /// The thread must be started with `spawn()` or `spawn_simple()`.
424 ///
425 /// # Examples
426 ///
427 /// ```ignore
428 /// use osal_rs::os::{Thread, ThreadFn};
429 ///
430 /// let thread = Thread::new("worker", 4096, 5);
431 /// ```
432 fn new(name: &str, stack_depth: StackType, priority: UBaseType) -> Self
433 {
434 Self {
435 handle: null_mut(),
436 name: name.to_string(),
437 stack_depth,
438 priority,
439 callback: None,
440 param: None
441 }
442 }
443
444 /// Creates a thread from an existing task handle.
445 ///
446 /// # Returns
447 ///
448 /// * `Err(Error::NullPtr)` if handle is null
449 fn new_with_handle(handle: ThreadHandle, name: &str, stack_depth: StackType, priority: UBaseType) -> Result<Self> {
450 if handle.is_null() {
451 return Err(Error::NullPtr);
452 }
453 Ok(Self {
454 handle,
455 name: name.to_string(),
456 stack_depth,
457 priority,
458 callback: None,
459 param: None
460 })
461 }
462
463 /// Spawns a new thread with a callback.
464 ///
465 /// # Important
466 /// The callback must be `'static`, which means it cannot borrow local variables.
467 /// Use `move` in the closure to transfer ownership of any captured values:
468 ///
469 /// ```ignore
470 /// let data = Arc::new(Mutex::new(0));
471 /// let thread = Thread::new("my_thread", 4096, 3, move |_thread, _param| {
472 /// // Use 'move' to capture 'data' by value
473 /// let mut guard = data.lock().unwrap();
474 /// *guard += 1;
475 /// Ok(Arc::new(()))
476 /// });
477 /// ``
478 fn spawn<F>(&mut self, param: Option<ThreadParam>, callback: F) -> Result<Self>
479 where
480 F: Fn(Box<dyn ThreadFn>, Option<ThreadParam>) -> Result<ThreadParam>,
481 F: Send + Sync + 'static {
482
483 let mut handle: ThreadHandle = null_mut();
484
485 let func: Arc<ThreadFnPtr> = Arc::new(callback);
486
487 self.callback = Some(func);
488 self.param = param.clone();
489
490 let boxed_thread = Box::new(self.clone());
491
492 // Convert name to CString to ensure null termination and proper lifetime
493 let c_name = CString::new(self.name.as_str())
494 .map_err(|_| Error::Unhandled("Failed to convert thread name to CString"))?;
495
496 let ret = unsafe {
497 xTaskCreate(
498 Some(super::thread::callback_c_wrapper),
499 c_name.as_ptr(),
500 self.stack_depth,
501 Box::into_raw(boxed_thread) as *mut _,
502 self.priority,
503 &mut handle,
504 )
505 };
506
507 if ret != pdPASS {
508 return Err(Error::OutOfMemory)
509 }
510
511 Ok(Self {
512 handle,
513 callback: self.callback.clone(),
514 param,
515 ..self.clone()
516 })
517 }
518
519 /// Spawns a new thread with a simple closure, similar to `std::thread::spawn`.
520 /// This is the recommended way to create threads for most use cases.
521 ///
522 /// # Example
523 /// ```ignore
524 /// let counter = Arc::new(Mutex::new(0));
525 /// let counter_clone = Arc::clone(&counter);
526 ///
527 /// let handle = Thread::spawn_simple("worker", 4096, 3, move || {
528 /// let mut num = counter_clone.lock().unwrap();
529 /// *num += 1;
530 /// }).unwrap();
531 ///
532 /// handle.join(core::ptr::null_mut());
533 /// ```
534 fn spawn_simple<F>(&mut self, callback: F) -> Result<Self>
535 where
536 F: Fn() + Send + Sync + 'static,
537 {
538 let func: Arc<ThreadSimpleFnPtr> = Arc::new(callback);
539 let boxed_func = Box::new(func);
540
541 let mut handle: ThreadHandle = null_mut();
542
543 // Convert name to CString to ensure null termination and proper lifetime
544 let c_name = CString::new(self.name.as_str())
545 .map_err(|_| Error::Unhandled("Failed to convert thread name to CString"))?;
546
547 let ret = unsafe {
548 xTaskCreate(
549 Some(simple_callback_wrapper),
550 c_name.as_ptr(),
551 self.stack_depth,
552 Box::into_raw(boxed_func) as *mut _,
553 self.priority,
554 &mut handle,
555 )
556 };
557
558 if ret != pdPASS {
559 return Err(Error::OutOfMemory);
560 }
561
562 Ok(Self {
563 handle,
564 ..self.clone()
565 })
566 }
567
568 /// Deletes the thread and frees its resources.
569 ///
570 /// # Safety
571 ///
572 /// After calling this, the thread handle becomes invalid.
573 ///
574 /// # Examples
575 ///
576 /// ```ignore
577 /// use osal_rs::os::{Thread, ThreadFn};
578 ///
579 /// let thread = Thread::new("temp", 2048, 5);
580 /// thread.delete();
581 /// ```
582 fn delete(&self) {
583 if !self.handle.is_null() {
584 unsafe { vTaskDelete( self.handle ); }
585 }
586 }
587
588 /// Suspends the thread execution.
589 ///
590 /// The thread remains suspended until `resume()` is called.
591 ///
592 /// # Examples
593 ///
594 /// ```ignore
595 /// use osal_rs::os::{Thread, ThreadFn};
596 /// use core::time::Duration;
597 ///
598 /// let thread = get_some_thread();
599 /// thread.suspend();
600 /// Duration::from_secs(1).sleep();
601 /// thread.resume();
602 /// ```
603 fn suspend(&self) {
604 if !self.handle.is_null() {
605 unsafe { vTaskSuspend( self.handle ); }
606 }
607 }
608
609 /// Resumes a previously suspended thread.
610 ///
611 /// # Examples
612 ///
613 /// ```ignore
614 /// thread.resume();
615 /// ```
616 fn resume(&self) {
617 if !self.handle.is_null() {
618 unsafe { vTaskResume( self.handle ); }
619 }
620 }
621
622 /// Waits for the thread to complete (currently deletes the thread).
623 ///
624 /// # Returns
625 ///
626 /// Always returns `Ok(0)`
627 fn join(&self, _retval: DoublePtr) -> Result<i32> {
628 if !self.handle.is_null() {
629 unsafe { vTaskDelete( self.handle ); }
630 }
631 Ok(0)
632 }
633
634 /// Retrieves this thread's metadata.
635 ///
636 /// # Examples
637 ///
638 /// ```ignore
639 /// use osal_rs::os::{Thread, ThreadFn};
640 ///
641 /// let thread = Thread::current();
642 /// let meta = thread.get_metadata();
643 /// println!("Running thread: {}", meta.name);
644 /// ```
645 fn get_metadata(&self) -> ThreadMetadata {
646 let mut status = TaskStatus::default();
647 unsafe {
648 vTaskGetInfo(self.handle, &mut status, pdTRUE, INVALID);
649 }
650 ThreadMetadata::from((self.handle, status))
651 }
652
653 /// Returns a Thread object representing the currently executing thread.
654 ///
655 /// # Examples
656 ///
657 /// ```ignore
658 /// use osal_rs::os::{Thread, ThreadFn};
659 ///
660 /// let current = Thread::get_current();
661 /// println!("Current thread: {}", current.get_metadata().name);
662 /// ```
663 fn get_current() -> Self {
664 let handle = unsafe { xTaskGetCurrentTaskHandle() };
665 let metadata = Self::get_metadata_from_handle(handle);
666 Self {
667 handle,
668 name: metadata.name,
669 stack_depth: metadata.stack_depth,
670 priority: metadata.priority,
671 callback: None,
672 param: None,
673 }
674 }
675
676 /// Sends a notification to this thread.
677 ///
678 /// # Parameters
679 ///
680 /// * `notification` - Type of notification action to perform
681 ///
682 /// # Returns
683 ///
684 /// * `Ok(())` - Notification sent successfully
685 /// * `Err(Error::NullPtr)` - Thread handle is null
686 /// * `Err(Error::QueueFull)` - Notification failed
687 ///
688 /// # Examples
689 ///
690 /// ```ignore
691 /// use osal_rs::os::{Thread, ThreadFn, ThreadNotification};
692 ///
693 /// let thread = get_worker_thread();
694 /// thread.notify(ThreadNotification::SetValueWithOverwrite(42)).unwrap();
695 /// ```
696 fn notify(&self, notification: ThreadNotification) -> Result<()> {
697 if self.handle.is_null() {
698 return Err(Error::NullPtr);
699 }
700
701 let (action, value) = notification.into();
702
703 let ret = xTaskNotify!(
704 self.handle,
705 value,
706 action
707 );
708
709 if ret != pdPASS {
710 Err(Error::QueueFull)
711 } else {
712 Ok(())
713 }
714
715 }
716
717 /// Sends a notification to this thread from an ISR.
718 ///
719 /// # Parameters
720 ///
721 /// * `notification` - Type of notification action
722 /// * `higher_priority_task_woken` - Set to pdTRUE if a higher priority task was woken
723 ///
724 /// # Returns
725 ///
726 /// * `Ok(())` - Notification sent successfully
727 /// * `Err(Error::NullPtr)` - Thread handle is null
728 /// * `Err(Error::QueueFull)` - Notification failed
729 ///
730 /// # Examples
731 ///
732 /// ```ignore
733 /// // In ISR context:
734 /// let mut woken = pdFALSE;
735 /// thread.notify_from_isr(ThreadNotification::Increment, &mut woken).ok();
736 /// ```
737 fn notify_from_isr(&self, notification: ThreadNotification, higher_priority_task_woken: &mut BaseType) -> Result<()> {
738 if self.handle.is_null() {
739 return Err(Error::NullPtr);
740 }
741
742 let (action, value) = notification.into();
743
744 let ret = xTaskNotifyFromISR!(
745 self.handle,
746 value,
747 action,
748 higher_priority_task_woken
749 );
750
751 if ret != pdPASS {
752 Err(Error::QueueFull)
753 } else {
754 Ok(())
755 }
756 }
757
758 /// Waits for a thread notification.
759 ///
760 /// # Parameters
761 ///
762 /// * `bits_to_clear_on_entry` - Bits to clear in notification value before waiting
763 /// * `bits_to_clear_on_exit` - Bits to clear after receiving notification
764 /// * `timeout_ticks` - Maximum ticks to wait
765 ///
766 /// # Returns
767 ///
768 /// * `Ok(u32)` - Notification value received
769 /// * `Err(Error::NullPtr)` - Thread handle is null
770 /// * `Err(Error::Timeout)` - No notification within timeout
771 ///
772 /// # Examples
773 ///
774 /// ```ignore
775 /// use osal_rs::os::{Thread, ThreadFn};
776 ///
777 /// let thread = Thread::current();
778 /// match thread.wait_notification(0, 0xFFFFFFFF, 1000) {
779 /// Ok(value) => println!("Received notification: {}", value),
780 /// Err(_) => println!("Timeout waiting for notification"),
781 /// }
782 /// ```
783 fn wait_notification(&self, bits_to_clear_on_entry: u32, bits_to_clear_on_exit: u32 , timeout_ticks: TickType) -> Result<u32> {
784 if self.handle.is_null() {
785 return Err(Error::NullPtr);
786 }
787
788 let mut notification_value: u32 = 0;
789
790 let ret = xTaskNotifyWait!(
791 bits_to_clear_on_entry,
792 bits_to_clear_on_exit,
793 &mut notification_value,
794 timeout_ticks
795 );
796
797
798 if ret == pdTRUE {
799 Ok(notification_value)
800 } else {
801 Err(Error::Timeout)
802 }
803 }
804
805}
806
807
808// impl Drop for Thread {
809// fn drop(&mut self) {
810// if !self.handle.is_null() {
811// unsafe { vTaskDelete( self.handle ); }
812// }
813// }
814// }
815
816impl Deref for Thread {
817 type Target = ThreadHandle;
818
819 fn deref(&self) -> &Self::Target {
820 &self.handle
821 }
822}
823
824impl Debug for Thread {
825 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
826 f.debug_struct("Thread")
827 .field("handle", &self.handle)
828 .field("name", &self.name)
829 .field("stack_depth", &self.stack_depth)
830 .field("priority", &self.priority)
831 .field("callback", &self.callback.as_ref().map(|_| "Some(...)"))
832 .field("param", &self.param)
833 .finish()
834 }
835}
836
837impl Display for Thread {
838 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
839 write!(f, "Thread {{ handle: {:?}, name: {}, priority: {}, stack_depth: {} }}", self.handle, self.name, self.priority, self.stack_depth)
840 }
841}
842
843