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