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