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