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