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::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