osal_rs/freertos/system.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//! System-level functions and utilities for FreeRTOS.
22//!
23//! This module provides access to system-wide functionality including:
24//! - Scheduler control (start, stop, suspend, resume)
25//! - System time and delay functions
26//! - Thread enumeration and state inspection
27//! - Critical sections
28//! - Heap memory information
29
30use core::fmt::Debug;
31use core::ops::Deref;
32use core::time::Duration;
33
34use alloc::vec::Vec;
35
36use super::ffi::{
37 BLOCKED, DELETED, READY, RUNNING, SUSPENDED, TaskStatus, eTaskGetState, osal_rs_critical_section_enter, osal_rs_critical_section_exit, osal_rs_port_end_switching_isr, osal_rs_port_yield_from_isr, uxTaskGetNumberOfTasks, uxTaskGetSystemState, vTaskDelay, vTaskEndScheduler, vTaskStartScheduler, vTaskSuspendAll, xPortGetFreeHeapSize, xTaskDelayUntil, xTaskGetCurrentTaskHandle, xTaskGetTickCount, xTaskResumeAll, osal_rs_task_enter_critical, osal_rs_task_enter_critical_from_isr, osal_rs_task_exit_critical, osal_rs_task_exit_critical_from_isr
38};
39use super::thread::{ThreadState, ThreadMetadata};
40use super::types::{BaseType, TickType, UBaseType};
41use crate::tick_period_ms;
42use crate::traits::{SystemFn, ToTick};
43use crate::utils::{CpuRegisterSize::*, register_bit_size, OsalRsBool};
44
45/// Represents a snapshot of the system state including all threads.
46///
47/// Contains metadata for all threads in the system and total runtime statistics.
48/// This is useful for monitoring, debugging, and profiling.
49///
50/// # Examples
51///
52/// ```ignore
53/// use osal_rs::os::{System, SystemFn};
54///
55/// let state = System::get_all_thread();
56///
57/// println!("Total threads: {}", state.tasks.len());
58/// println!("Total runtime: {}", state.total_run_time);
59///
60/// for thread in &state.tasks {
61/// println!("Thread: {} - Priority: {} - State: {:?}",
62/// thread.name,
63/// thread.priority,
64/// thread.state
65/// );
66/// }
67/// ```
68#[derive(Debug, Clone)]
69pub struct SystemState {
70 /// List of all thread metadata in the system
71 pub tasks: Vec<ThreadMetadata>,
72 /// Total runtime counter across all threads (if enabled)
73 pub total_run_time: u32
74}
75
76/// Provides access to the task list as a slice.
77impl Deref for SystemState {
78 type Target = [ThreadMetadata];
79
80 fn deref(&self) -> &Self::Target {
81 &self.tasks
82 }
83}
84
85/// System-level operations and utilities.
86///
87/// Provides a collection of static methods for controlling the FreeRTOS scheduler
88/// and accessing system-wide information. All methods are static.
89///
90/// # Examples
91///
92/// ## Starting the scheduler
93///
94/// ```ignore
95/// use osal_rs::os::{System, SystemFn};
96///
97/// // Create threads, queues, etc.
98/// // ...
99///
100/// // Start the scheduler (never returns in normal operation)
101/// System::start();
102/// ```
103///
104/// ## Delays and timing
105///
106/// ```ignore
107/// use osal_rs::os::{System, SystemFn};
108/// use core::time::Duration;
109///
110/// // Simple delay
111/// System::delay_with_to_tick(Duration::from_millis(500));
112///
113/// // Get current system time
114/// let now = System::get_current_time_us();
115/// println!("Uptime: {:?}", now);
116///
117/// // Periodic execution using delay_until
118/// let mut last_wake = System::get_tick_count();
119/// loop {
120/// System::delay_until_with_to_tick(&mut last_wake, Duration::from_millis(100));
121/// println!("Periodic task");
122/// }
123/// ```
124///
125/// ## Critical sections
126///
127/// ```ignore
128/// use osal_rs::os::{System, SystemFn};
129///
130/// // Protect shared data
131/// System::critical_section_enter();
132/// // Access shared data here
133/// // ...
134/// System::critical_section_exit();
135/// ```
136///
137/// ## Thread enumeration
138///
139/// ```ignore
140/// use osal_rs::os::{System, SystemFn};
141///
142/// let count = System::count_threads();
143/// println!("Active threads: {}", count);
144///
145/// let state = System::get_all_thread();
146/// for thread in &state.tasks {
147/// println!("Thread: {} - Stack high water: {}",
148/// thread.name,
149/// thread.stack_high_water_mark
150/// );
151/// }
152/// ```
153///
154/// ## Heap monitoring
155///
156/// ```ignore
157/// use osal_rs::os::{System, SystemFn};
158///
159/// let free_heap = System::get_free_heap_size();
160/// println!("Free heap: {} bytes", free_heap);
161/// ```
162///
163/// ## Scheduler suspend/resume
164///
165/// ```ignore
166/// use osal_rs::os::{System, SystemFn};
167///
168/// // Suspend scheduler for atomic operations
169/// System::suspend_all();
170/// // Perform atomic operations
171/// // ...
172/// System::resume_all();
173/// ```
174/// System-level operations and scheduler control.
175///
176/// Provides static methods for controlling the RTOS scheduler, timing,
177/// and system-wide operations.
178pub struct System;
179
180impl System {
181 /// Delays execution using a type that implements `ToTick`.
182 ///
183 /// Convenience method that accepts `Duration` or other tick-convertible types.
184 ///
185 /// # Examples
186 ///
187 /// ```ignore
188 /// use osal_rs::os::{System, SystemFn};
189 /// use core::time::Duration;
190 ///
191 /// System::delay_with_to_tick(Duration::from_millis(100));
192 /// ```
193 #[inline]
194 pub fn delay_with_to_tick(ticks: impl ToTick){
195 Self::delay(ticks.to_ticks());
196 }
197
198 /// Delays until an absolute time point with tick conversion.
199 ///
200 /// Used for precise periodic timing.
201 ///
202 /// # Parameters
203 ///
204 /// * `previous_wake_time` - Previous wake time (updated by this function)
205 /// * `time_increment` - Time increment for next wake
206 ///
207 /// # Examples
208 ///
209 /// ```ignore
210 /// use osal_rs::os::{System, SystemFn};
211 /// use core::time::Duration;
212 ///
213 /// let mut last_wake = System::get_tick_count();
214 /// loop {
215 /// // Do work...
216 /// System::delay_until_with_to_tick(&mut last_wake, Duration::from_millis(100));
217 /// }
218 /// ```
219 #[inline]
220 pub fn delay_until_with_to_tick(previous_wake_time: &mut TickType, time_increment: impl ToTick) {
221 Self::delay_until(previous_wake_time, time_increment.to_ticks());
222 }
223}
224
225impl SystemFn for System {
226 /// Starts the RTOS scheduler.
227 ///
228 /// This function never returns if successful. All created threads will
229 /// begin execution according to their priorities.
230 ///
231 /// # Examples
232 ///
233 /// ```ignore
234 /// use osal_rs::os::{System, SystemFn, Thread};
235 ///
236 /// // Create threads...
237 /// let thread = Thread::new("worker", 2048, 5, || {
238 /// loop { /* work */ }
239 /// }).unwrap();
240 ///
241 /// thread.start().unwrap();
242 ///
243 /// // Start scheduler (does not return)
244 /// System::start();
245 /// ```
246 fn start() {
247 unsafe {
248 vTaskStartScheduler();
249 }
250 }
251
252 /// Gets the state of the currently executing thread.
253 ///
254 /// # Returns
255 ///
256 /// Current thread state enum value
257 ///
258 /// # Examples
259 ///
260 /// ```ignore
261 /// use osal_rs::os::{System, SystemFn, ThreadState};
262 ///
263 /// let state = System::get_state();
264 /// match state {
265 /// ThreadState::Running => println!("Currently running"),
266 /// _ => println!("Other state"),
267 /// }
268 /// ```
269 fn get_state() -> ThreadState {
270 use super::thread::ThreadState::*;
271 let state = unsafe { eTaskGetState(xTaskGetCurrentTaskHandle()) };
272 match state {
273 RUNNING => Running,
274 READY => Ready,
275 BLOCKED => Blocked,
276 SUSPENDED => Suspended,
277 DELETED => Deleted,
278 _ => Invalid, // INVALID or unknown state
279 }
280 }
281
282 /// Suspends all tasks in the scheduler.
283 ///
284 /// No context switches will occur until `resume_all()` is called.
285 /// Use this to create atomic sections spanning multiple operations.
286 ///
287 /// # Examples
288 ///
289 /// ```ignore
290 /// use osal_rs::os::{System, SystemFn};
291 ///
292 /// System::suspend_all();
293 /// // Perform critical operations
294 /// System::resume_all();
295 /// ```
296 fn suspend_all() {
297 unsafe {
298 vTaskSuspendAll();
299 }
300 }
301
302 /// Resumes all suspended tasks.
303 ///
304 /// # Returns
305 ///
306 /// Non-zero if a context switch should occur
307 ///
308 /// # Examples
309 ///
310 /// ```ignore
311 /// System::resume_all();
312 /// ```
313 fn resume_all() -> BaseType {
314 unsafe { xTaskResumeAll() }
315 }
316
317 /// Stops the RTOS scheduler.
318 ///
319 /// All threads will stop executing. Rarely used in embedded systems.
320 ///
321 /// # Examples
322 ///
323 /// ```ignore
324 /// System::stop();
325 /// ```
326 fn stop() {
327 unsafe {
328 vTaskEndScheduler();
329 }
330 }
331
332 /// Returns the current tick count.
333 ///
334 /// The tick count increments with each RTOS tick interrupt.
335 ///
336 /// # Returns
337 ///
338 /// Current tick count value
339 ///
340 /// # Examples
341 ///
342 /// ```ignore
343 /// use osal_rs::os::{System, SystemFn};
344 ///
345 /// let ticks = System::get_tick_count();
346 /// println!("Current ticks: {}", ticks);
347 /// ```
348 fn get_tick_count() -> TickType {
349 unsafe { xTaskGetTickCount() }
350 }
351
352 /// Returns the current system time as a `Duration`.
353 ///
354 /// Converts the current tick count to microseconds and returns it as
355 /// a standard `Duration` type.
356 ///
357 /// # Returns
358 ///
359 /// Current system uptime as `Duration`
360 ///
361 /// # Examples
362 ///
363 /// ```ignore
364 /// use osal_rs::os::{System, SystemFn};
365 ///
366 /// let uptime = System::get_current_time_us();
367 /// println!("System uptime: {:?}", uptime);
368 /// ```
369 fn get_current_time_us () -> Duration {
370 let ticks = Self::get_tick_count();
371 Duration::from_millis( 1_000 * ticks as u64 / tick_period_ms!() as u64 )
372 }
373
374 /// Converts a `Duration` to microsecond ticks.
375 ///
376 /// Helper function for converting duration values to system tick counts
377 /// in microsecond resolution.
378 ///
379 /// # Parameters
380 ///
381 /// * `duration` - Duration to convert
382 ///
383 /// # Returns
384 ///
385 /// Equivalent tick count in microseconds
386 ///
387 /// # Examples
388 ///
389 /// ```ignore
390 /// use osal_rs::os::{System, SystemFn};
391 /// use core::time::Duration;
392 ///
393 /// let duration = Duration::from_millis(100);
394 /// let us_ticks = System::get_us_from_tick(&duration);
395 /// ```
396 fn get_us_from_tick(duration: &Duration) -> TickType {
397 let millis = duration.as_millis() as TickType;
398 millis / (1_000 * tick_period_ms!() as TickType)
399 }
400
401 /// Returns the number of threads currently in the system.
402 ///
403 /// Includes threads in all states (running, ready, blocked, suspended).
404 ///
405 /// # Returns
406 ///
407 /// Total number of threads
408 ///
409 /// # Examples
410 ///
411 /// ```ignore
412 /// use osal_rs::os::{System, SystemFn};
413 ///
414 /// let count = System::count_threads();
415 /// println!("Total threads: {}", count);
416 /// ```
417 fn count_threads() -> usize {
418 unsafe { uxTaskGetNumberOfTasks() as usize }
419 }
420
421 /// Retrieves a snapshot of all threads in the system.
422 ///
423 /// Returns detailed metadata for every thread including state, priority,
424 /// stack usage, and runtime statistics.
425 ///
426 /// # Returns
427 ///
428 /// `SystemState` containing all thread information
429 ///
430 /// # Examples
431 ///
432 /// ```ignore
433 /// use osal_rs::os::{System, SystemFn};
434 ///
435 /// let state = System::get_all_thread();
436 ///
437 /// for thread in &state.tasks {
438 /// println!("Thread: {} - Stack remaining: {}",
439 /// thread.name,
440 /// thread.stack_high_water_mark
441 /// );
442 /// }
443 /// ```
444 fn get_all_thread() -> SystemState {
445 let threads_count = Self::count_threads();
446 let mut threads: Vec<TaskStatus> = Vec::with_capacity(threads_count);
447 let mut total_run_time: u32 = 0;
448
449 unsafe {
450 let count = uxTaskGetSystemState(
451 threads.as_mut_ptr(),
452 threads_count as UBaseType,
453 &raw mut total_run_time,
454 ) as usize;
455
456 // Set the length only after data has been written by FreeRTOS
457 threads.set_len(count);
458 }
459
460 let tasks = threads.into_iter()
461 .map(|task_status| {
462 ThreadMetadata::from((
463 task_status.xHandle,
464 task_status
465 ))
466 }).collect();
467
468 SystemState {
469 tasks,
470 total_run_time
471 }
472 }
473
474
475 /// Delays the current thread for the specified number of ticks.
476 ///
477 /// The thread will enter the Blocked state for the delay period.
478 ///
479 /// # Parameters
480 ///
481 /// * `ticks` - Number of ticks to delay
482 ///
483 /// # Examples
484 ///
485 /// ```ignore
486 /// use osal_rs::os::{System, SystemFn};
487 ///
488 /// System::delay(100); // Delay 100 ticks
489 /// ```
490 fn delay(ticks: TickType){
491 unsafe {
492 vTaskDelay(ticks);
493 }
494 }
495
496 /// Delays until an absolute time point.
497 ///
498 /// Used for creating precise periodic timing. The `previous_wake_time`
499 /// is updated automatically for the next period.
500 ///
501 /// # Parameters
502 ///
503 /// * `previous_wake_time` - Pointer to last wake time (will be updated)
504 /// * `time_increment` - Period in ticks
505 ///
506 /// # Examples
507 ///
508 /// ```ignore
509 /// use osal_rs::os::{System, SystemFn};
510 ///
511 /// let mut last_wake = System::get_tick_count();
512 /// loop {
513 /// // Periodic task code...
514 /// System::delay_until(&mut last_wake, 100); // 100 tick period
515 /// }
516 /// ```
517 fn delay_until(previous_wake_time: &mut TickType, time_increment: TickType) {
518 unsafe {
519 xTaskDelayUntil(
520 previous_wake_time,
521 time_increment,
522 );
523 }
524 }
525
526 /// Enters a critical section.
527 ///
528 /// Disables interrupts or increments the scheduler lock nesting count.
529 /// Must be paired with `critical_section_exit()`.
530 ///
531 /// # Examples
532 ///
533 /// ```ignore
534 /// use osal_rs::os::{System, SystemFn};
535 ///
536 /// System::critical_section_enter();
537 /// // Critical code - no task switches or interrupts
538 /// System::critical_section_exit();
539 /// ```
540 fn critical_section_enter() {
541 unsafe {
542 osal_rs_critical_section_enter();
543 }
544 }
545
546 /// Exits a critical section.
547 ///
548 /// Re-enables interrupts or decrements the scheduler lock nesting count.
549 ///
550 /// # Examples
551 ///
552 /// ```ignore
553 /// System::critical_section_exit();
554 /// ```
555 fn critical_section_exit() {
556 unsafe {
557 osal_rs_critical_section_exit();
558 }
559 }
560
561 /// Checks if a timer has elapsed.
562 ///
563 /// Compares the elapsed time since a timestamp against a target duration,
564 /// handling tick counter overflow correctly for both 32-bit and 64-bit systems.
565 ///
566 /// # Parameters
567 ///
568 /// * `timestamp` - Starting time reference
569 /// * `time` - Target duration to wait for
570 ///
571 /// # Returns
572 ///
573 /// * `OsalRsBool::True` - Timer has elapsed
574 /// * `OsalRsBool::False` - Timer has not yet elapsed
575 ///
576 /// # Examples
577 ///
578 /// ```ignore
579 /// use osal_rs::os::{System, SystemFn};
580 /// use core::time::Duration;
581 ///
582 /// let start = System::get_current_time_us();
583 /// let timeout = Duration::from_secs(1);
584 ///
585 /// // Later...
586 /// if System::check_timer(&start, &timeout).into() {
587 /// println!("Timeout occurred");
588 /// }
589 /// ```
590 fn check_timer(timestamp: &Duration, time: &Duration) -> OsalRsBool {
591 let temp_tick_time = Self::get_current_time_us();
592
593 let time_passing = if temp_tick_time >= *timestamp {
594 temp_tick_time - *timestamp
595 } else {
596 if register_bit_size() == Bit32 {
597 // Handle tick count overflow for 32-bit TickType
598 let overflow_correction = Duration::from_micros(0xff_ff_ff_ff_u64);
599 overflow_correction - *timestamp + temp_tick_time
600 } else {
601 // Handle tick count overflow for 64-bit TickType
602 let overflow_correction = Duration::from_micros(0xff_ff_ff_ff_ff_ff_ff_ff_u64);
603 overflow_correction - *timestamp + temp_tick_time
604 }
605 };
606
607 if time_passing >= *time {
608 OsalRsBool::True
609 } else {
610 OsalRsBool::False
611 }
612 }
613
614 /// Yields to a higher priority task from ISR context.
615 ///
616 /// Should be called when an ISR operation wakes a higher priority task.
617 ///
618 /// # Parameters
619 ///
620 /// * `higher_priority_task_woken` - pdTRUE if higher priority task was woken
621 ///
622 /// # Examples
623 ///
624 /// ```ignore
625 /// // In ISR:
626 /// let mut woken = pdFALSE;
627 /// // ... ISR operations that might wake a task ...
628 /// System::yield_from_isr(woken);
629 /// ```
630 fn yield_from_isr(higher_priority_task_woken: BaseType) {
631 unsafe {
632 osal_rs_port_yield_from_isr(higher_priority_task_woken);
633 }
634 }
635
636 /// Ends ISR and performs context switch if needed.
637 ///
638 /// This function should be called at the end of an interrupt service routine
639 /// to trigger a context switch if a higher priority task was woken during
640 /// the ISR.
641 ///
642 /// # Parameters
643 ///
644 /// * `switch_required` - `pdTRUE` if context switch is required, `pdFALSE` otherwise
645 ///
646 /// # Examples
647 ///
648 /// ```ignore
649 /// use osal_rs::os::{System, SystemFn};
650 /// use osal_rs::os::ffi::pdTRUE;
651 ///
652 /// // In ISR:
653 /// let mut switch_required = pdFALSE;
654 /// // ... ISR operations that might require context switch ...
655 /// System::end_switching_isr(switch_required);
656 /// ```
657 fn end_switching_isr( switch_required: BaseType ) {
658 unsafe {
659 osal_rs_port_end_switching_isr( switch_required );
660 }
661 }
662
663 /// Enters a critical section at task level.
664 ///
665 /// Disables scheduler and interrupts to protect shared resources.
666 /// Must be paired with [`exit_critical()`](Self::exit_critical).
667 /// This is the task-level version; for ISR context use
668 /// [`enter_critical_from_isr()`](Self::enter_critical_from_isr).
669 ///
670 /// # Examples
671 ///
672 /// ```ignore
673 /// use osal_rs::os::{System, SystemFn};
674 ///
675 /// System::enter_critical();
676 /// // Access shared resource safely
677 /// System::exit_critical();
678 /// ```
679 fn enter_critical() {
680 unsafe {
681 osal_rs_task_enter_critical();
682 }
683 }
684
685 /// Exits a critical section at task level.
686 ///
687 /// Re-enables scheduler and interrupts after [`enter_critical()`](Self::enter_critical).
688 /// Must be called from the same task that called `enter_critical()`.
689 ///
690 /// # Examples
691 ///
692 /// ```ignore
693 /// use osal_rs::os::{System, SystemFn};
694 ///
695 /// System::enter_critical();
696 /// // Critical section code
697 /// System::exit_critical();
698 /// ```
699 fn exit_critical() {
700 unsafe {
701 osal_rs_task_exit_critical();
702 }
703 }
704
705 /// Enters a critical section from an ISR context.
706 ///
707 /// ISR-safe version of critical section entry. Returns the interrupt mask state
708 /// that must be passed to [`exit_critical_from_isr()`](Self::exit_critical_from_isr).
709 /// Use this instead of [`enter_critical()`](Self::enter_critical) when in interrupt context.
710 ///
711 /// # Returns
712 ///
713 /// Saved interrupt status to be restored on exit
714 ///
715 /// # Examples
716 ///
717 /// ```ignore
718 /// use osal_rs::os::{System, SystemFn};
719 ///
720 /// // In an interrupt handler
721 /// let saved_status = System::enter_critical_from_isr();
722 /// // Critical ISR code
723 /// System::exit_critical_from_isr(saved_status);
724 /// ```
725 fn enter_critical_from_isr() -> UBaseType {
726 unsafe {
727 osal_rs_task_enter_critical_from_isr()
728 }
729 }
730
731 /// Exits a critical section from an ISR context.
732 ///
733 /// Restores the interrupt mask to the state saved by
734 /// [`enter_critical_from_isr()`](Self::enter_critical_from_isr).
735 ///
736 /// # Parameters
737 ///
738 /// * `saved_interrupt_status` - Interrupt status returned by `enter_critical_from_isr()`
739 ///
740 /// # Examples
741 ///
742 /// ```ignore
743 /// use osal_rs::os::{System, SystemFn};
744 ///
745 /// let saved = System::enter_critical_from_isr();
746 /// // Protected ISR operations
747 /// System::exit_critical_from_isr(saved);
748 /// ```
749 fn exit_critical_from_isr(saved_interrupt_status: UBaseType) {
750 unsafe {
751 osal_rs_task_exit_critical_from_isr(saved_interrupt_status);
752 }
753 }
754
755
756 /// Returns the amount of free heap space.
757 ///
758 /// Useful for monitoring memory usage and detecting leaks.
759 ///
760 /// # Returns
761 ///
762 /// Number of free heap bytes
763 ///
764 /// # Examples
765 ///
766 /// ```ignore
767 /// use osal_rs::os::{System, SystemFn};
768 ///
769 /// let free = System::get_free_heap_size();
770 /// println!("Free heap: {} bytes", free);
771 /// ```
772 fn get_free_heap_size() -> usize {
773 unsafe {
774 xPortGetFreeHeapSize()
775 }
776 }
777
778}
779