Skip to main content

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