Skip to main content

osal_rs/freertos/
system.rs

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