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