osal_rs/freertos/
system.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//! 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
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
75impl Deref for SystemState {
76    type Target = [ThreadMetadata];
77
78    fn deref(&self) -> &Self::Target {
79        &self.tasks
80    }
81}
82
83/// System-level operations and utilities.
84///
85/// Provides a collection of static methods for controlling the FreeRTOS scheduler
86/// and accessing system-wide information. All methods are static.
87///
88/// # Examples
89///
90/// ## Starting the scheduler
91///
92/// ```ignore
93/// use osal_rs::os::{System, SystemFn};
94/// 
95/// // Create threads, queues, etc.
96/// // ...
97/// 
98/// // Start the scheduler (never returns in normal operation)
99/// System::start();
100/// ```
101///
102/// ## Delays and timing
103///
104/// ```ignore
105/// use osal_rs::os::{System, SystemFn};
106/// use core::time::Duration;
107/// 
108/// // Simple delay
109/// System::delay_with_to_tick(Duration::from_millis(500));
110/// 
111/// // Get current system time
112/// let now = System::get_current_time_us();
113/// println!("Uptime: {:?}", now);
114/// 
115/// // Periodic execution using delay_until
116/// let mut last_wake = System::get_tick_count();
117/// loop {
118///     System::delay_until_with_to_tick(&mut last_wake, Duration::from_millis(100));
119///     println!("Periodic task");
120/// }
121/// ```
122///
123/// ## Critical sections
124///
125/// ```ignore
126/// use osal_rs::os::{System, SystemFn};
127/// 
128/// // Protect shared data
129/// System::critical_section_enter();
130/// // Access shared data here
131/// // ...
132/// System::critical_section_exit();
133/// ```
134///
135/// ## Thread enumeration
136///
137/// ```ignore
138/// use osal_rs::os::{System, SystemFn};
139/// 
140/// let count = System::count_threads();
141/// println!("Active threads: {}", count);
142/// 
143/// let state = System::get_all_thread();
144/// for thread in &state.tasks {
145///     println!("Thread: {} - Stack high water: {}",
146///         thread.name,
147///         thread.stack_high_water_mark
148///     );
149/// }
150/// ```
151///
152/// ## Heap monitoring
153///
154/// ```ignore
155/// use osal_rs::os::{System, SystemFn};
156/// 
157/// let free_heap = System::get_free_heap_size();
158/// println!("Free heap: {} bytes", free_heap);
159/// ```
160///
161/// ## Scheduler suspend/resume
162///
163/// ```ignore
164/// use osal_rs::os::{System, SystemFn};
165/// 
166/// // Suspend scheduler for atomic operations
167/// System::suspend_all();
168/// // Perform atomic operations
169/// // ...
170/// System::resume_all();
171/// ```
172/// System-level operations and scheduler control.
173///
174/// Provides static methods for controlling the RTOS scheduler, timing,
175/// and system-wide operations.
176pub struct System;
177
178impl System {
179    /// Delays execution using a type that implements `ToTick`.
180    ///
181    /// Convenience method that accepts `Duration` or other tick-convertible types.
182    ///
183    /// # Examples
184    ///
185    /// ```ignore
186    /// use osal_rs::os::{System, SystemFn};
187    /// use core::time::Duration;
188    /// 
189    /// System::delay_with_to_tick(Duration::from_millis(100));
190    /// ```
191    #[inline]
192    pub fn delay_with_to_tick(ticks: impl ToTick){
193        Self::delay(ticks.to_ticks());
194    }
195
196    /// Delays until an absolute time point with tick conversion.
197    ///
198    /// Used for precise periodic timing.
199    ///
200    /// # Parameters
201    ///
202    /// * `previous_wake_time` - Previous wake time (updated by this function)
203    /// * `time_increment` - Time increment for next wake
204    ///
205    /// # Examples
206    ///
207    /// ```ignore
208    /// use osal_rs::os::{System, SystemFn};
209    /// use core::time::Duration;
210    /// 
211    /// let mut last_wake = System::get_tick_count();
212    /// loop {
213    ///     // Do work...
214    ///     System::delay_until_with_to_tick(&mut last_wake, Duration::from_millis(100));
215    /// }
216    /// ```
217    #[inline]
218    pub fn delay_until_with_to_tick(previous_wake_time: &mut TickType, time_increment: impl ToTick) { 
219        Self::delay_until(previous_wake_time, time_increment.to_ticks());
220    }
221}
222
223impl SystemFn for System {
224    /// Starts the RTOS scheduler.
225    ///
226    /// This function never returns if successful. All created threads will
227    /// begin execution according to their priorities.
228    ///
229    /// # Examples
230    ///
231    /// ```ignore
232    /// use osal_rs::os::{System, SystemFn, Thread};
233    /// 
234    /// // Create threads...
235    /// let thread = Thread::new("worker", 2048, 5, || {
236    ///     loop { /* work */ }
237    /// }).unwrap();
238    /// 
239    /// thread.start().unwrap();
240    /// 
241    /// // Start scheduler (does not return)
242    /// System::start();
243    /// ```
244    fn start() {
245        unsafe {
246            vTaskStartScheduler();
247        }
248    }
249
250    /// Gets the state of the currently executing thread.
251    ///
252    /// # Returns
253    ///
254    /// Current thread state enum value
255    ///
256    /// # Examples
257    ///
258    /// ```ignore
259    /// use osal_rs::os::{System, SystemFn, ThreadState};
260    /// 
261    /// let state = System::get_state();
262    /// match state {
263    ///     ThreadState::Running => println!("Currently running"),
264    ///     _ => println!("Other state"),
265    /// }
266    /// ```
267    fn get_state() -> ThreadState {
268        use super::thread::ThreadState::*;
269        let state = unsafe { eTaskGetState(xTaskGetCurrentTaskHandle()) };
270        match state {
271            RUNNING => Running,
272            READY => Ready,
273            BLOCKED => Blocked,
274            SUSPENDED => Suspended,
275            DELETED => Deleted,
276            _ => Invalid, // INVALID or unknown state
277        }
278    }
279
280    /// Suspends all tasks in the scheduler.
281    ///
282    /// No context switches will occur until `resume_all()` is called.
283    /// Use this to create atomic sections spanning multiple operations.
284    ///
285    /// # Examples
286    ///
287    /// ```ignore
288    /// use osal_rs::os::{System, SystemFn};
289    /// 
290    /// System::suspend_all();
291    /// // Perform critical operations
292    /// System::resume_all();
293    /// ```
294    fn suspend_all() {
295        unsafe {
296            vTaskSuspendAll();
297        }
298    }
299    
300    /// Resumes all suspended tasks.
301    ///
302    /// # Returns
303    ///
304    /// Non-zero if a context switch should occur
305    ///
306    /// # Examples
307    ///
308    /// ```ignore
309    /// System::resume_all();
310    /// ```
311    fn resume_all() -> BaseType {
312        unsafe { xTaskResumeAll() }
313    }
314
315    /// Stops the RTOS scheduler.
316    ///
317    /// All threads will stop executing. Rarely used in embedded systems.
318    ///
319    /// # Examples
320    ///
321    /// ```ignore
322    /// System::stop();
323    /// ```
324    fn stop() {
325        unsafe {
326            vTaskEndScheduler();
327        }
328    }
329
330    /// Returns the current tick count.
331    ///
332    /// The tick count increments with each RTOS tick interrupt.
333    ///
334    /// # Returns
335    ///
336    /// Current tick count value
337    ///
338    /// # Examples
339    ///
340    /// ```ignore
341    /// use osal_rs::os::{System, SystemFn};
342    /// 
343    /// let ticks = System::get_tick_count();
344    /// println!("Current ticks: {}", ticks);
345    /// ```
346    fn get_tick_count() -> TickType {
347        unsafe { xTaskGetTickCount() }
348    }
349
350    fn get_current_time_us () -> Duration {
351        let ticks = Self::get_tick_count();
352        Duration::from_millis( 1_000 * ticks as u64 / tick_period_ms!() as u64 )
353    }
354
355    fn get_us_from_tick(duration: &Duration) -> TickType {
356        let millis = duration.as_millis() as TickType;
357        millis / (1_000 * tick_period_ms!() as TickType) 
358    }
359
360    /// Returns the number of threads currently in the system.
361    ///
362    /// Includes threads in all states (running, ready, blocked, suspended).
363    ///
364    /// # Returns
365    ///
366    /// Total number of threads
367    ///
368    /// # Examples
369    ///
370    /// ```ignore
371    /// use osal_rs::os::{System, SystemFn};
372    /// 
373    /// let count = System::count_threads();
374    /// println!("Total threads: {}", count);
375    /// ```
376    fn count_threads() -> usize {
377        unsafe { uxTaskGetNumberOfTasks() as usize }
378    }
379
380    /// Retrieves a snapshot of all threads in the system.
381    ///
382    /// Returns detailed metadata for every thread including state, priority,
383    /// stack usage, and runtime statistics.
384    ///
385    /// # Returns
386    ///
387    /// `SystemState` containing all thread information
388    ///
389    /// # Examples
390    ///
391    /// ```ignore
392    /// use osal_rs::os::{System, SystemFn};
393    /// 
394    /// let state = System::get_all_thread();
395    /// 
396    /// for thread in &state.tasks {
397    ///     println!("Thread: {} - Stack remaining: {}",
398    ///         thread.name,
399    ///         thread.stack_high_water_mark
400    ///     );
401    /// }
402    /// ```
403    fn get_all_thread() -> SystemState {
404        let threads_count = Self::count_threads();
405        let mut threads: Vec<TaskStatus> = Vec::with_capacity(threads_count);
406        let mut total_run_time: u32 = 0;
407
408        unsafe {
409            let count = uxTaskGetSystemState(
410                threads.as_mut_ptr(),
411                threads_count as UBaseType,
412                &raw mut total_run_time,
413            ) as usize;
414            
415            // Set the length only after data has been written by FreeRTOS
416            threads.set_len(count);
417        }
418
419        let tasks = threads.into_iter()
420            .map(|task_status| {
421                ThreadMetadata::from((
422                    task_status.xHandle, 
423                    task_status
424                ))
425            }).collect();
426
427        SystemState {
428            tasks,
429            total_run_time
430        }
431    }
432
433
434    /// Delays the current thread for the specified number of ticks.
435    ///
436    /// The thread will enter the Blocked state for the delay period.
437    ///
438    /// # Parameters
439    ///
440    /// * `ticks` - Number of ticks to delay
441    ///
442    /// # Examples
443    ///
444    /// ```ignore
445    /// use osal_rs::os::{System, SystemFn};
446    /// 
447    /// System::delay(100);  // Delay 100 ticks
448    /// ```
449    fn delay(ticks: TickType){
450        unsafe {
451            vTaskDelay(ticks);
452        }
453    }
454
455    /// Delays until an absolute time point.
456    ///
457    /// Used for creating precise periodic timing. The `previous_wake_time`
458    /// is updated automatically for the next period.
459    ///
460    /// # Parameters
461    ///
462    /// * `previous_wake_time` - Pointer to last wake time (will be updated)
463    /// * `time_increment` - Period in ticks
464    ///
465    /// # Examples
466    ///
467    /// ```ignore
468    /// use osal_rs::os::{System, SystemFn};
469    /// 
470    /// let mut last_wake = System::get_tick_count();
471    /// loop {
472    ///     // Periodic task code...
473    ///     System::delay_until(&mut last_wake, 100);  // 100 tick period
474    /// }
475    /// ```
476    fn delay_until(previous_wake_time: &mut TickType, time_increment: TickType) {
477        unsafe {
478            xTaskDelayUntil(
479                previous_wake_time,
480                time_increment,
481            );
482        }
483    }
484
485    /// Enters a critical section.
486    ///
487    /// Disables interrupts or increments the scheduler lock nesting count.
488    /// Must be paired with `critical_section_exit()`.
489    ///
490    /// # Examples
491    ///
492    /// ```ignore
493    /// use osal_rs::os::{System, SystemFn};
494    /// 
495    /// System::critical_section_enter();
496    /// // Critical code - no task switches or interrupts
497    /// System::critical_section_exit();
498    /// ```
499    fn critical_section_enter() {
500        unsafe {
501            osal_rs_critical_section_enter();
502        }
503    }
504    
505    /// Exits a critical section.
506    ///
507    /// Re-enables interrupts or decrements the scheduler lock nesting count.
508    ///
509    /// # Examples
510    ///
511    /// ```ignore
512    /// System::critical_section_exit();
513    /// ```
514    fn critical_section_exit() {
515        unsafe {
516            osal_rs_critical_section_exit();
517        }   
518    }
519    
520    fn check_timer(timestamp: &Duration, time: &Duration) -> OsalRsBool {
521        let temp_tick_time = Self::get_current_time_us();
522        
523        let time_passing = if temp_tick_time >= *timestamp {
524            temp_tick_time - *timestamp
525        } else {
526            if register_bit_size() == Bit32 {
527                // Handle tick count overflow for 32-bit TickType
528                let overflow_correction = Duration::from_micros(0xff_ff_ff_ff_u64);
529                overflow_correction - *timestamp + temp_tick_time
530            } else {
531                // Handle tick count overflow for 64-bit TickType
532                let overflow_correction = Duration::from_micros(0xff_ff_ff_ff_ff_ff_ff_ff_u64);
533                overflow_correction - *timestamp + temp_tick_time
534            }
535        };
536
537        if time_passing >= *time {
538            OsalRsBool::True
539        } else {
540            OsalRsBool::False
541        }
542    }
543
544    /// Yields to a higher priority task from ISR context.
545    ///
546    /// Should be called when an ISR operation wakes a higher priority task.
547    ///
548    /// # Parameters
549    ///
550    /// * `higher_priority_task_woken` - pdTRUE if higher priority task was woken
551    ///
552    /// # Examples
553    ///
554    /// ```ignore
555    /// // In ISR:
556    /// let mut woken = pdFALSE;
557    /// // ... ISR operations that might wake a task ...
558    /// System::yield_from_isr(woken);
559    /// ```
560    fn yield_from_isr(higher_priority_task_woken: BaseType) {
561        unsafe {
562            osal_rs_port_yield_from_isr(higher_priority_task_woken);
563        }
564    }
565
566    /// Ends ISR and performs context switch if needed.
567    ///
568    /// # Parameters
569    ///
570    /// * `switch_required` - pdTRUE if context switch is required
571    fn end_switching_isr( switch_required: BaseType ) {
572        unsafe {
573            osal_rs_port_end_switching_isr( switch_required );
574        }
575    }
576
577    /// Returns the amount of free heap space.
578    ///
579    /// Useful for monitoring memory usage and detecting leaks.
580    ///
581    /// # Returns
582    ///
583    /// Number of free heap bytes
584    ///
585    /// # Examples
586    ///
587    /// ```ignore
588    /// use osal_rs::os::{System, SystemFn};
589    /// 
590    /// let free = System::get_free_heap_size();
591    /// println!("Free heap: {} bytes", free);
592    /// ```
593    fn get_free_heap_size() -> usize {
594        unsafe {
595            xPortGetFreeHeapSize()
596        }
597    }
598
599}
600