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