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
20use core::fmt::Debug;
21use core::ops::Deref;
22use core::time::Duration;
23
24use alloc::vec::Vec;
25
26use super::ffi::{
27    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
28};
29use super::thread::{ThreadState, ThreadMetadata};
30use super::types::{BaseType, TickType, UBaseType};
31use crate::tick_period_ms;
32use crate::traits::{SystemFn, ToTick};
33use crate::utils::{CpuRegisterSize::*, register_bit_size, OsalRsBool};
34
35#[derive(Debug, Clone)]
36pub struct SystemState {
37    pub tasks: Vec<ThreadMetadata>,
38    pub total_run_time: u32
39}
40
41impl Deref for SystemState {
42    type Target = [ThreadMetadata];
43
44    fn deref(&self) -> &Self::Target {
45        &self.tasks
46    }
47}
48
49pub struct System;
50
51impl System {
52    #[inline]
53    pub fn delay_with_to_tick(ticks: impl ToTick){
54        Self::delay(ticks.to_ticks());
55    }
56
57    #[inline]
58    pub fn delay_until_with_to_tick(previous_wake_time: &mut TickType, time_increment: impl ToTick) { 
59        Self::delay_until(previous_wake_time, time_increment.to_ticks());
60    }
61}
62
63impl SystemFn for System {
64    fn start() {
65        unsafe {
66            vTaskStartScheduler();
67        }
68    }
69
70    fn get_state() -> ThreadState {
71        use super::thread::ThreadState::*;
72        let state = unsafe { eTaskGetState(xTaskGetCurrentTaskHandle()) };
73        match state {
74            RUNNING => Running,
75            READY => Ready,
76            BLOCKED => Blocked,
77            SUSPENDED => Suspended,
78            DELETED => Deleted,
79            _ => Invalid, // INVALID or unknown state
80        }
81    }
82
83    fn suspend_all() {
84        unsafe {
85            vTaskSuspendAll();
86        }
87    }
88    fn resume_all() -> BaseType {
89        unsafe { xTaskResumeAll() }
90    }
91
92    fn stop() {
93        unsafe {
94            vTaskEndScheduler();
95        }
96    }
97
98    fn get_tick_count() -> TickType {
99        unsafe { xTaskGetTickCount() }
100    }
101
102    fn get_current_time_us () -> Duration {
103        let ticks = Self::get_tick_count();
104        Duration::from_millis( 1_000 * ticks as u64 / tick_period_ms!() as u64 )
105    }
106
107    fn get_us_from_tick(duration: &Duration) -> TickType {
108        let millis = duration.as_millis() as TickType;
109        millis / (1_000 * tick_period_ms!() as TickType) 
110    }
111
112    fn count_threads() -> usize {
113        unsafe { uxTaskGetNumberOfTasks() as usize }
114    }
115
116    fn get_all_thread() -> SystemState {
117        let threads_count = Self::count_threads();
118        let mut threads: Vec<TaskStatus> = Vec::with_capacity(threads_count);
119        let mut total_run_time: u32 = 0;
120
121        unsafe {
122            let count = uxTaskGetSystemState(
123                threads.as_mut_ptr(),
124                threads_count as UBaseType,
125                &raw mut total_run_time,
126            ) as usize;
127            
128            // Set the length only after data has been written by FreeRTOS
129            threads.set_len(count);
130        }
131
132        let tasks = threads.into_iter()
133            .map(|task_status| {
134                ThreadMetadata::from((
135                    task_status.xHandle, 
136                    task_status
137                ))
138            }).collect();
139
140        SystemState {
141            tasks,
142            total_run_time
143        }
144    }
145
146
147    fn delay(ticks: TickType){
148        unsafe {
149            vTaskDelay(ticks);
150        }
151    }
152
153    fn delay_until(previous_wake_time: &mut TickType, time_increment: TickType) {
154        unsafe {
155            xTaskDelayUntil(
156                previous_wake_time,
157                time_increment,
158            );
159        }
160    }
161
162    fn critical_section_enter() {
163        unsafe {
164            osal_rs_critical_section_enter();
165        }
166    }
167    
168    fn critical_section_exit() {
169        unsafe {
170            osal_rs_critical_section_exit();
171        }   
172    }
173    
174    fn check_timer(timestamp: &Duration, time: &Duration) -> OsalRsBool {
175        let temp_tick_time = Self::get_current_time_us();
176        
177        let time_passing = if temp_tick_time >= *timestamp {
178            temp_tick_time - *timestamp
179        } else {
180            if register_bit_size() == Bit32 {
181                // Handle tick count overflow for 32-bit TickType
182                let overflow_correction = Duration::from_micros(0xff_ff_ff_ff_u64);
183                overflow_correction - *timestamp + temp_tick_time
184            } else {
185                // Handle tick count overflow for 64-bit TickType
186                let overflow_correction = Duration::from_micros(0xff_ff_ff_ff_ff_ff_ff_ff_u64);
187                overflow_correction - *timestamp + temp_tick_time
188            }
189        };
190
191        if time_passing >= *time {
192            OsalRsBool::True
193        } else {
194            OsalRsBool::False
195        }
196    }
197
198    fn yield_from_isr(higher_priority_task_woken: BaseType) {
199        unsafe {
200            osal_rs_port_yield_from_isr(higher_priority_task_woken);
201        }
202    }
203
204    fn end_switching_isr( switch_required: BaseType ) {
205        unsafe {
206            osal_rs_port_end_switching_isr( switch_required );
207        }
208    }
209
210    fn get_free_heap_size() -> usize {
211        unsafe {
212            xPortGetFreeHeapSize()
213        }
214    }
215
216}
217