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