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