Skip to main content

osal_rs/
lib.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
18 *
19 ***************************************************************************/
20
21//! # OSAL-RS - Operating System Abstraction Layer for Rust
22//!
23//! A cross-platform abstraction layer for embedded and real-time operating systems.
24//!
25//! ## Overview
26//!
27//! OSAL-RS provides a unified, safe Rust API for working with different real-time
28//! operating systems. It currently ships two backends, selected at compile time
29//! via feature flags - there is no default, exactly one must be enabled:
30//! - **FreeRTOS** (feature `freertos`) - for bare-metal embedded targets
31//! - **POSIX** (feature `posix`) - runs on any pthreads-capable host (Linux, macOS)
32//!   so applications, tests and doc examples can execute natively without
33//!   embedded hardware or a cross toolchain
34//!
35//! Application code written against `osal_rs::os::*` is portable between the
36//! two backends by switching feature flags.
37//!
38//! ## Features
39//!
40//! - **Thread Management**: Create and control threads with priorities
41//! - **Synchronization**: Mutexes, semaphores, and event groups
42//! - **Communication**: Queues for inter-thread message passing
43//! - **Timers**: Software timers for periodic and one-shot operations
44//! - **Time Management**: Duration-based timing with tick conversion
45//! - **No-std Support**: Works in bare-metal embedded environments (`freertos` backend)
46//! - **Host Testing**: Runs under `std` on POSIX hosts for native testing (`posix` backend)
47//! - **Type Safety**: Leverages Rust's type system for correctness
48//! - **Async/Await**: Backend-agnostic `async`/`await` without Tokio (feature `async`)
49//!
50//! ## Quick Start
51//!
52//! ### Basic Thread Example
53//!
54//! ```no_run
55//! use osal_rs::os::*;
56//!
57//! fn main() {
58//!     // Create a thread
59//!     let mut thread = Thread::new(
60//!         "worker",
61//!         4096,  // stack size
62//!         5,     // priority
63//!     );
64//!
65//!     thread.spawn_simple(|| {
66//!         loop {
67//!             println!("Working...");
68//!             System::delay(1000);
69//!         }
70//!     }).unwrap();
71//!
72//!     // Start the scheduler (never returns)
73//!     System::start();
74//! }
75//! ```
76//!
77//! ### Mutex Example
78//!
79//! ```
80//! use osal_rs::os::*;
81//! use std::sync::Arc;
82//!
83//! let counter = Arc::new(Mutex::new(0));
84//! let counter_clone = counter.clone();
85//!
86//! let mut thread = Thread::new("incrementer", 2048, 5);
87//! thread.spawn_simple(move || {
88//!     let mut guard = counter_clone.lock().unwrap();
89//!     *guard += 1;
90//!     Ok(Arc::new(()))
91//! }).unwrap();
92//! ```
93//!
94//! ### Queue Example
95//!
96//! ```
97//! use osal_rs::os::*;
98//!
99//! let queue = Queue::new(10, 4).unwrap();
100//!
101//! // Send data
102//! let data = [1u8, 2, 3, 4];
103//! queue.post(&data, 100).unwrap();
104//!
105//! // Receive data
106//! let mut buffer = [0u8; 4];
107//! queue.fetch(&mut buffer, 100).unwrap();
108//! ```
109//!
110//! ### Semaphore Example
111//!
112//! ```
113//! use osal_rs::os::*;
114//! use osal_rs::utils::OsalRsBool;
115//! use core::time::Duration;
116//!
117//! let sem = Semaphore::new(1, 1).unwrap();
118//!
119//! if sem.wait(Duration::from_millis(100)) == OsalRsBool::True {
120//!     // Critical section
121//!     sem.signal();
122//! }
123//! ```
124//!
125//! ### Timer Example
126//!
127//! ```
128//! extern crate alloc;
129//! use osal_rs::os::*;
130//! use alloc::sync::Arc;
131//! use core::time::Duration;
132//!
133//! let timer = Timer::new_with_to_tick(
134//!     "periodic",
135//!     Duration::from_millis(500),
136//!     true,  // auto-reload
137//!     None,
138//!     |_timer, _param| {
139//!         println!("Timer tick");
140//!         Ok(Arc::new(()))
141//!     }
142//! ).unwrap();
143//!
144//! timer.start_with_to_tick(Duration::from_millis(10));
145//! ```
146//!
147//! ### Async/Await Example (feature `async`)
148//!
149#![cfg_attr(feature = "async", doc = "```")]
150#![cfg_attr(not(feature = "async"), doc = "```ignore")]
151//! use osal_rs::os::{block_on, AsyncMutex, AsyncQueue, AsyncSemaphore};
152//!
153//! // Drive a future to completion on the calling RTOS task — no Tokio needed.
154//! block_on(async {
155//!     let mutex = AsyncMutex::new(0u32);
156//!     {
157//!         let mut guard = mutex.lock().await;
158//!         *guard += 1;
159//!     }
160//!
161//!     let sem = AsyncSemaphore::new(1, 0).unwrap();
162//!     sem.signal();
163//!     sem.wait_async().await;
164//!
165//!     let queue = AsyncQueue::new(8, 4).unwrap();
166//!     queue.post_async(&[1u8, 2, 3, 4]).await.unwrap();
167//!     let mut buf = [0u8; 4];
168//!     queue.fetch_async(&mut buf).await.unwrap();
169//! });
170//! ```
171//!
172//! ## Module Organization
173//!
174//! - [`os`] - Main module containing all OS abstractions
175//!   - Threads, mutexes, semaphores, queues, event groups, timers
176//!   - System-level functions
177//!   - Type definitions
178//!   - `block_on`, `AsyncQueue`, `AsyncSemaphore`, `AsyncMutex` (feature `async`)
179//! - [`utils`] - Utility types and error definitions
180//! - [`log`] - Logging macros
181//! - `traits` - Private module defining the trait abstractions
182//! - `freertos` - Private FreeRTOS implementation (enabled with `freertos` feature)
183//! - `posix` - Private POSIX implementation (enabled with `posix` feature)
184//!
185//! ## Features
186//!
187//! | Feature | Default | Description |
188//! |---------|---------|-------------|
189//! | `freertos` | ❌ | FreeRTOS backend |
190//! | `posix` | ❌ | POSIX/host backend |
191//! | `async` | ❌ | Async/await without Tokio |
192//! | `serde` | ❌ | Serialization via `osal-rs-serde` |
193//! | `real_time` | ❌ | POSIX only: schedules spawned threads with `SCHED_FIFO` instead of inheriting the creating thread's policy/priority. Not meant to be requested by hand - the build script auto-enables it when the host OS/kernel supports real-time scheduling |
194//!
195//! There is no default backend: exactly one of `freertos`/`posix` must be
196//! enabled explicitly. Enabling neither trips the `compile_error!` below;
197//! enabling both is equally unsupported (the two are mutually exclusive by
198//! `cfg`, so the crate fails to build either way).
199//!
200//! ## Requirements
201//!
202//! When using with FreeRTOS:
203//! - FreeRTOS kernel must be properly configured
204//! - Link the C porting layer from `osal-rs-porting/freertos/`
205//! - Set appropriate `FreeRTOSConfig.h` options:
206//!   - `configTICK_RATE_HZ` - Defines the tick frequency
207//!   - `configUSE_MUTEXES` - Must be 1 for mutex support
208//!   - `configUSE_COUNTING_SEMAPHORES` - Must be 1 for semaphore support
209//!   - `configUSE_TIMERS` - Must be 1 for timer support
210//!   - `configSUPPORT_DYNAMIC_ALLOCATION` - Must be 1 for dynamic allocation
211//!
212//! When using with POSIX:
213//! - A POSIX-compliant host implementing pthreads, `timer_create(2)`/`sigwait(3)`
214//!   and `CLOCK_MONOTONIC` (glibc/Linux is part of this crate's test suite)
215//! - No special build steps: unlike `freertos`, this backend links only
216//!   against the host's libc/libpthread - no cross toolchain or RTOS kernel
217//!   sources required
218//! - Disables `no_std`: the `posix` feature builds the crate against `std`
219//!
220//! ## Platform Support
221//!
222//! Currently tested on:
223//! - ARM Cortex-M (Raspberry Pi Pico/RP2040, RP2350) - `freertos` backend
224//! - ARM Cortex-M4F (STM32F4 series) - `freertos` backend
225//! - ARM Cortex-M7 (STM32H7 series) - `freertos` backend
226//! - RISC-V (RP2350 RISC-V cores) - `freertos` backend
227//! - glibc/Linux - `posix` backend
228//!
229//! ## Thread Safety
230//!
231//! All types are designed with thread safety in mind:
232//! - Most operations are thread-safe and can be called from multiple threads
233//! - Methods with `_from_isr` suffix are ISR-safe (callable from interrupt context)
234//! - Regular methods (without `_from_isr`) must not be called from ISR context
235//! - Mutexes use priority inheritance to prevent priority inversion
236//!
237//! ## ISR Context
238//!
239//! Operations in ISR context have restrictions (applies to the `freertos`
240//! backend; POSIX has no interrupt context - `_from_isr` variants are
241//! provided there for API compatibility but behave like their regular
242//! counterparts):
243//! - Cannot block or use timeouts (must use zero timeout or `_from_isr` variants)
244//! - Must be extremely fast to avoid blocking other interrupts
245//! - Use semaphores or queues to defer work to task context
246//! - Event groups and notifications are ISR-safe for signaling
247//!
248//! ## Safety
249//!
250//! This library uses `unsafe` internally to interface with C APIs but provides
251//! safe Rust abstractions. All public APIs are designed to be memory-safe when
252//! used correctly:
253//! - Type safety through generic parameters
254//! - RAII patterns for automatic resource management
255//! - Rust's ownership system prevents data races
256//! - FFI boundaries are carefully validated
257//!
258//! ## Performance Considerations
259//!
260//! - `freertos` backend: allocations happen on the FreeRTOS heap (via the
261//!   `#[global_allocator]` in [`os`]), not the system heap
262//! - `posix` backend: uses the system allocator and native OS threads; each
263//!   [`os::Timer`] spawns a dedicated background thread
264//! - Stack sizes must be carefully tuned for each thread
265//! - Priority inversion is mitigated through priority inheritance
266//! - Context switches are triggered by blocking operations
267//!
268//! ## Best Practices
269//!
270//! 1. **Thread Creation**: Always specify appropriate stack sizes based on usage
271//! 2. **Mutexes**: Prefer scoped locking with guards to prevent deadlocks
272//! 3. **Queues**: Use type-safe `QueueStreamed` when possible
273//! 4. **Semaphores**: Use binary semaphores for signaling, counting for resources
274//! 5. **ISR Handlers**: Keep ISR code minimal, defer work to tasks
275//! 6. **Error Handling**: Always check `Result` return values
276//! 7. **Async Tasks**: Call `block_on` once per RTOS task; do not nest executors
277//!
278//! ## License
279//!
280//! LGPL-2.1-or-later - See LICENSE file for details
281
282#![cfg_attr(not(feature = "posix"), no_std)]
283
284extern crate alloc;
285
286#[cfg(not(any(feature = "freertos", feature = "posix")))]
287compile_error!("Enable either the `freertos` backend or the `posix` host backend.");
288
289/// FreeRTOS implementation of OSAL traits.
290///
291/// This module contains the concrete implementation of all OSAL abstractions
292/// for FreeRTOS, including threads, mutexes, queues, timers, etc.
293///
294/// Enabled with the `freertos` feature flag (no default backend - must be
295/// requested explicitly).
296#[cfg(all(not(feature = "posix"), feature = "freertos"))]
297mod freertos;
298
299/// POSIX implementation of OSAL traits.
300///
301/// This module contains the concrete implementation of all OSAL abstractions
302/// on top of the POSIX/pthreads API (threads, mutexes, semaphores, queues,
303/// event groups, timers), so applications - and their tests and doc examples -
304/// can run natively on any POSIX host (Linux, macOS) without embedded hardware
305/// or a cross toolchain. See [`posix`] for details.
306///
307/// Enabled with the `posix` feature flag.
308#[cfg(all(feature = "posix", not(feature = "freertos")))]
309mod posix;
310
311pub mod log;
312
313/// Trait definitions for OSAL abstractions.
314///
315/// This private module defines all the trait interfaces that concrete
316/// implementations must satisfy. Traits are re-exported through the `os` module.
317mod traits;
318
319pub mod utils;
320
321/// Async executor (block_on).
322#[cfg(feature = "async")]
323mod async_executor;
324
325/// Async primitives (AsyncQueue, AsyncSemaphore, AsyncMutex).
326#[cfg(feature = "async")]
327mod async_primitives;
328
329/// Select FreeRTOS as the active OSAL backend.
330#[cfg(all(not(feature = "posix"), feature = "freertos"))]
331use crate::freertos as osal;
332
333/// Select POSIX as the active OSAL backend.
334#[cfg(all(feature = "posix", not(feature = "freertos")))]
335use crate::posix as osal;
336
337/// Main OSAL module re-exporting all OS abstractions and traits.
338///
339/// This module provides a unified interface to all OSAL functionality through `osal_rs::os::*`.
340/// It re-exports:
341/// - Thread management types (`Thread`, `ThreadNotification`)
342/// - Synchronization primitives (`Mutex`, `Semaphore`, `EventGroup`)
343/// - Communication types (`Queue`, `QueueStreamed`)
344/// - Timer types (`Timer`)
345/// - System functions (`System`)
346/// - All trait definitions from the `traits` module
347/// - Type definitions and configuration from the active backend
348///
349/// The actual implementation (FreeRTOS or POSIX) is selected at compile time via features.
350///
351/// # Examples
352///
353/// ```ignore
354/// use osal_rs::os::*;
355///
356/// fn main() {
357///     // Create and start a thread
358///     let thread = Thread::new("worker", 4096, 5, || {
359///         println!("Worker thread running");
360///     }).unwrap();
361///     
362///     thread.start().unwrap();
363///     System::start();
364/// }
365/// ```
366pub mod os {
367
368    #[cfg(all(not(feature = "posix"), feature = "freertos"))]
369    use crate::osal::allocator::Allocator;
370
371    /// Global allocator using the underlying RTOS heap.
372    ///
373    /// This static variable configures Rust's global allocator to use the
374    /// RTOS heap (e.g., FreeRTOS heap) instead of the system heap.
375    ///
376    /// # Behavior
377    ///
378    /// - All allocations via `alloc::vec::Vec`, `alloc::boxed::Box`, `alloc::string::String`, etc.
379    ///   will use the RTOS heap
380    /// - Memory is managed by the underlying RTOS (e.g., `pvPortMalloc`/`vPortFree` in FreeRTOS)
381    /// - Thread-safe: can be used from multiple tasks safely
382    ///
383    /// # Feature Flag
384    ///
385    /// Active when using the `freertos` backend.
386    ///
387    /// # FreeRTOS Configuration
388    ///
389    /// Ensure your `FreeRTOSConfig.h` has:
390    /// - `configSUPPORT_DYNAMIC_ALLOCATION` set to 1
391    /// - `configTOTAL_HEAP_SIZE` configured appropriately for your application
392    ///
393    /// # Example
394    ///
395    /// ```ignore
396    /// use alloc::vec::Vec;
397    ///
398    /// // This allocation uses the FreeRTOS heap via ALLOCATOR
399    /// let mut v = Vec::new();
400    /// v.push(42);
401    /// ```
402    #[cfg(all(not(feature = "posix"), feature = "freertos"))]
403    #[global_allocator]
404    pub static ALLOCATOR: Allocator = Allocator;
405
406    /// Event group synchronization primitives.
407    #[allow(unused_imports)]
408    pub use crate::osal::event_group::*;
409    
410    /// Mutex types and guards for mutual exclusion.
411    #[allow(unused_imports)]
412    pub use crate::osal::mutex::*;
413    
414    /// Queue types for inter-task communication.
415    #[allow(unused_imports)]
416    pub use crate::osal::queue::*;
417    
418    /// Semaphore types for signaling and resource management.
419    #[allow(unused_imports)]
420    pub use crate::osal::semaphore::*;
421    
422    /// System-level functions (scheduler, timing, critical sections).
423    pub use crate::osal::system::*;
424    
425    /// Thread/task management and notification types.
426    pub use crate::osal::thread::*;
427    
428    /// Software timer types for periodic and one-shot callbacks.
429    #[allow(unused_imports)]
430    pub use crate::osal::timer::*;
431    
432    /// All OSAL trait definitions for advanced usage.
433    pub use crate::traits::*;
434    
435    /// RTOS configuration constants and types.
436    pub use crate::osal::config as config;
437    
438    /// Type aliases and common types used throughout OSAL.
439    pub use crate::osal::types as types;
440
441    /// Single-future async executor (backend-agnostic, no Tokio).
442    #[cfg(feature = "async")]
443    pub use crate::async_executor::block_on;
444
445    /// Async-capable wrappers for OSAL primitives.
446    #[cfg(feature = "async")]
447    pub use crate::async_primitives::*;
448    
449}
450
451/// Default panic handler for `no_std` environments.
452///
453/// This panic handler is active for the `freertos` backend.
454/// It prints panic information and enters an infinite loop to halt execution.
455///
456/// # Behavior
457///
458/// 1. Attempts to print panic information using the `println!` macro
459/// 2. Enters an infinite empty loop, halting the program
460///
461/// # Feature Flag
462///
463/// - Enabled for `freertos`
464/// - Automatically disabled when using `posix`
465///
466/// # Safety
467///
468/// This handler is intentionally simple and does not attempt cleanup or recovery.
469/// In production embedded systems, consider:
470/// - Logging panic info to persistent storage
471/// - Performing safe shutdown procedures
472/// - Resetting the system via watchdog
473///
474#[cfg(all(not(feature = "posix"), feature = "freertos"))]
475#[panic_handler]
476fn panic(info: &core::panic::PanicInfo) -> ! {
477    println!("Panic occurred: {}", info);
478    #[allow(clippy::empty_loop)]
479    loop {}
480}
481