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. Currently supports FreeRTOS with planned support for POSIX
29//! and other RTOSes.
30//!
31//! ## Features
32//!
33//! - **Thread Management**: Create and control threads with priorities
34//! - **Synchronization**: Mutexes, semaphores, and event groups
35//! - **Communication**: Queues for inter-thread message passing
36//! - **Timers**: Software timers for periodic and one-shot operations
37//! - **Time Management**: Duration-based timing with tick conversion
38//! - **No-std Support**: Works in bare-metal embedded environments
39//! - **Type Safety**: Leverages Rust's type system for correctness
40//!
41//! ## Quick Start
42//!
43//! ### Basic Thread Example
44//!
45//! ```ignore
46//! use osal_rs::os::*;
47//! use core::time::Duration;
48//!
49//! fn main() {
50//!     // Create a thread
51//!     let thread = Thread::new(
52//!         "worker",
53//!         4096,  // stack size
54//!         5,     // priority
55//!         || {
56//!             loop {
57//!                 println!("Working...");
58//!                 Duration::from_secs(1).sleep();
59//!             }
60//!         }
61//!     ).unwrap();
62//!
63//!     thread.start().unwrap();
64//!     
65//!     // Start the scheduler
66//!     System::start();
67//! }
68//! ```
69//!
70//! ### Mutex Example
71//!
72//! ```ignore
73//! use osal_rs::os::*;
74//! use alloc::sync::Arc;
75//!
76//! let counter = Arc::new(Mutex::new(0));
77//! let counter_clone = counter.clone();
78//!
79//! let thread = Thread::new("incrementer", 2048, 5, move || {
80//!     let mut guard = counter_clone.lock().unwrap();
81//!     *guard += 1;
82//! }).unwrap();
83//! ```
84//!
85//! ### Queue Example
86//!
87//! ```ignore
88//! use osal_rs::os::*;
89//! use core::time::Duration;
90//!
91//! let queue = Queue::new(10, 4).unwrap();
92//!
93//! // Send data
94//! let data = [1u8, 2, 3, 4];
95//! queue.post(&data, 100).unwrap();
96//!
97//! // Receive data
98//! let mut buffer = [0u8; 4];
99//! queue.fetch(&mut buffer, 100).unwrap();
100//! ```
101//!
102//! ### Semaphore Example
103//!
104//! ```ignore
105//! use osal_rs::os::*;
106//! use core::time::Duration;
107//!
108//! let sem = Semaphore::new(1, 1).unwrap();
109//!
110//! if sem.wait(Duration::from_millis(100)).into() {
111//!     // Critical section
112//!     sem.signal();
113//! }
114//! ```
115//!
116//! ### Timer Example
117//!
118//! ```ignore
119//! use osal_rs::os::*;
120//! use core::time::Duration;
121//!
122//! let timer = Timer::new_with_to_tick(
123//!     "periodic",
124//!     Duration::from_millis(500),
125//!     true,  // auto-reload
126//!     None,
127//!     |_, _| {
128//!         println!("Timer tick");
129//!         Ok(None)
130//!     }
131//! ).unwrap();
132//!
133//! timer.start_with_to_tick(Duration::from_millis(10));
134//! ```
135//!
136//! ## Module Organization
137//!
138//! - [`os`] - Main module containing all OS abstractions
139//!   - Threads, mutexes, semaphores, queues, event groups, timers
140//!   - System-level functions
141//!   - Type definitions
142//! - [`utils`] - Utility types and error definitions
143//! - [`log`] - Logging macros
144//! - `traits` - Private module defining the trait abstractions
145//! - `freertos` - Private FreeRTOS implementation (enabled with `freertos` feature)
146//! - `posix` - Private POSIX implementation (enabled with `posix` feature, planned)
147//!
148//! ## Features
149//!
150//! - `freertos` - Enable FreeRTOS support (default)
151//! - `posix` - Enable POSIX support (planned)
152//! - `std` - Enable standard library support for testing
153//! - `disable_panic` - Disable the default panic handler and allocator
154//!
155//! ## Requirements
156//!
157//! When using with FreeRTOS:
158//! - FreeRTOS kernel must be properly configured
159//! - Link the C porting layer from `osal-rs-porting/freertos/`
160//! - Set appropriate `FreeRTOSConfig.h` options:
161//!   - `configTICK_RATE_HZ` - Defines the tick frequency
162//!   - `configUSE_MUTEXES` - Must be 1 for mutex support
163//!   - `configUSE_COUNTING_SEMAPHORES` - Must be 1 for semaphore support
164//!   - `configUSE_TIMERS` - Must be 1 for timer support
165//!   - `configSUPPORT_DYNAMIC_ALLOCATION` - Must be 1 for dynamic allocation
166//!
167//! ## Platform Support
168//!
169//! Currently tested on:
170//! - ARM Cortex-M (Raspberry Pi Pico/RP2040, RP2350)
171//! - ARM Cortex-M4F (STM32F4 series)
172//! - ARM Cortex-M7 (STM32H7 series)
173//! - RISC-V (RP2350 RISC-V cores)
174//!
175//! ## Thread Safety
176//!
177//! All types are designed with thread safety in mind:
178//! - Most operations are thread-safe and can be called from multiple threads
179//! - Methods with `_from_isr` suffix are ISR-safe (callable from interrupt context)
180//! - Regular methods (without `_from_isr`) must not be called from ISR context
181//! - Mutexes use priority inheritance to prevent priority inversion
182//!
183//! ## ISR Context
184//!
185//! Operations in ISR context have restrictions:
186//! - Cannot block or use timeouts (must use zero timeout or `_from_isr` variants)
187//! - Must be extremely fast to avoid blocking other interrupts
188//! - Use semaphores or queues to defer work to task context
189//! - Event groups and notifications are ISR-safe for signaling
190//!
191//! ## Safety
192//!
193//! This library uses `unsafe` internally to interface with C APIs but provides
194//! safe Rust abstractions. All public APIs are designed to be memory-safe when
195//! used correctly:
196//! - Type safety through generic parameters
197//! - RAII patterns for automatic resource management
198//! - Rust's ownership system prevents data races
199//! - FFI boundaries are carefully validated
200//!
201//! ## Performance Considerations
202//!
203//! - Allocations happen on the FreeRTOS heap, not the system heap
204//! - Stack sizes must be carefully tuned for each thread
205//! - Priority inversion is mitigated through priority inheritance
206//! - Context switches are triggered by blocking operations
207//!
208//! ## Best Practices
209//!
210//! 1. **Thread Creation**: Always specify appropriate stack sizes based on usage
211//! 2. **Mutexes**: Prefer scoped locking with guards to prevent deadlocks
212//! 3. **Queues**: Use type-safe `QueueStreamed` when possible
213//! 4. **Semaphores**: Use binary semaphores for signaling, counting for resources
214//! 5. **ISR Handlers**: Keep ISR code minimal, defer work to tasks
215//! 6. **Error Handling**: Always check `Result` return values
216//!
217//! ## License
218//!
219//! LGPL-2.1-or-later - See LICENSE file for details
220
221#![cfg_attr(not(feature = "std"), no_std)]
222
223extern crate alloc;
224
225#[cfg(all(feature = "posix", not(feature = "std")))]
226compile_error!("The `posix` backend requires the `std` feature.");
227
228#[cfg(not(any(feature = "freertos", feature = "std")))]
229compile_error!("Enable either the `freertos` backend or the `std` host backend.");
230
231/// FreeRTOS implementation of OSAL traits.
232///
233/// This module contains the concrete implementation of all OSAL abstractions
234/// for FreeRTOS, including threads, mutexes, queues, timers, etc.
235///
236/// Enabled with the `freertos` feature flag (on by default).
237#[cfg(feature = "freertos")]
238mod freertos;
239
240/// POSIX implementation of OSAL traits (planned).
241///
242/// This module will contain the implementation for POSIX-compliant systems.
243/// Currently under development.
244///
245/// Enabled with the `posix` feature flag.
246#[cfg(all(feature = "std", not(feature = "freertos")))]
247mod posix;
248
249pub mod log;
250
251/// Trait definitions for OSAL abstractions.
252///
253/// This private module defines all the trait interfaces that concrete
254/// implementations must satisfy. Traits are re-exported through the `os` module.
255mod traits;
256
257pub mod utils;
258
259/// Select FreeRTOS as the active OSAL backend.
260#[cfg(feature = "freertos")]
261use crate::freertos as osal;
262
263/// Select POSIX as the active OSAL backend.
264#[cfg(all(feature = "std", not(feature = "freertos")))]
265use crate::posix as osal;
266
267/// Main OSAL module re-exporting all OS abstractions and traits.
268///
269/// This module provides a unified interface to all OSAL functionality through `osal_rs::os::*`.
270/// It re-exports:
271/// - Thread management types (`Thread`, `ThreadNotification`)
272/// - Synchronization primitives (`Mutex`, `Semaphore`, `EventGroup`)
273/// - Communication types (`Queue`, `QueueStreamed`)
274/// - Timer types (`Timer`)
275/// - System functions (`System`)
276/// - All trait definitions from the `traits` module
277/// - Type definitions and configuration from the active backend
278///
279/// The actual implementation (FreeRTOS or POSIX) is selected at compile time via features.
280///
281/// # Examples
282///
283/// ```ignore
284/// use osal_rs::os::*;
285///
286/// fn main() {
287///     // Create and start a thread
288///     let thread = Thread::new("worker", 4096, 5, || {
289///         println!("Worker thread running");
290///     }).unwrap();
291///     
292///     thread.start().unwrap();
293///     System::start();
294/// }
295/// ```
296pub mod os {
297
298    #[cfg(all(not(feature = "disable_panic"), feature = "freertos"))]
299    use crate::osal::allocator::Allocator;
300
301    /// Global allocator using the underlying RTOS heap.
302    ///
303    /// This static variable configures Rust's global allocator to use the
304    /// RTOS heap (e.g., FreeRTOS heap) instead of the system heap.
305    ///
306    /// # Behavior
307    ///
308    /// - All allocations via `alloc::vec::Vec`, `alloc::boxed::Box`, `alloc::string::String`, etc.
309    ///   will use the RTOS heap
310    /// - Memory is managed by the underlying RTOS (e.g., `pvPortMalloc`/`vPortFree` in FreeRTOS)
311    /// - Thread-safe: can be used from multiple tasks safely
312    ///
313    /// # Feature Flag
314    ///
315    /// - Active by default
316    /// - Disabled with `disable_panic` feature if you want to provide your own allocator
317    ///
318    /// # FreeRTOS Configuration
319    ///
320    /// Ensure your `FreeRTOSConfig.h` has:
321    /// - `configSUPPORT_DYNAMIC_ALLOCATION` set to 1
322    /// - `configTOTAL_HEAP_SIZE` configured appropriately for your application
323    ///
324    /// # Example
325    ///
326    /// ```ignore
327    /// use alloc::vec::Vec;
328    ///
329    /// // This allocation uses the FreeRTOS heap via ALLOCATOR
330    /// let mut v = Vec::new();
331    /// v.push(42);
332    /// ```
333    #[cfg(all(not(feature = "disable_panic"), feature = "freertos"))]
334    #[global_allocator]
335    pub static ALLOCATOR: Allocator = Allocator;
336
337    /// Event group synchronization primitives.
338    #[allow(unused_imports)]
339    pub use crate::osal::event_group::*;
340    
341    /// Mutex types and guards for mutual exclusion.
342    #[allow(unused_imports)]
343    pub use crate::osal::mutex::*;
344    
345    /// Queue types for inter-task communication.
346    #[allow(unused_imports)]
347    pub use crate::osal::queue::*;
348    
349    /// Semaphore types for signaling and resource management.
350    #[allow(unused_imports)]
351    pub use crate::osal::semaphore::*;
352    
353    /// System-level functions (scheduler, timing, critical sections).
354    pub use crate::osal::system::*;
355    
356    /// Thread/task management and notification types.
357    pub use crate::osal::thread::*;
358    
359    /// Software timer types for periodic and one-shot callbacks.
360    #[allow(unused_imports)]
361    pub use crate::osal::timer::*;
362    
363    /// All OSAL trait definitions for advanced usage.
364    pub use crate::traits::*;
365    
366    /// RTOS configuration constants and types.
367    pub use crate::osal::config as config;
368    
369    /// Type aliases and common types used throughout OSAL.
370    pub use crate::osal::types as types;
371    
372}
373
374/// Default panic handler for `no_std` environments.
375///
376/// This panic handler is active when the `disable_panic` feature is **not** enabled.
377/// It prints panic information and enters an infinite loop to halt execution.
378///
379/// # Behavior
380///
381/// 1. Attempts to print panic information using the `println!` macro
382/// 2. Enters an infinite empty loop, halting the program
383///
384/// # Feature Flag
385///
386/// - Enabled by default in library mode
387/// - Disabled with `disable_panic` feature when users want to provide their own handler
388/// - Automatically disabled in examples that use `std`
389///
390/// # Safety
391///
392/// This handler is intentionally simple and does not attempt cleanup or recovery.
393/// In production embedded systems, consider:
394/// - Logging panic info to persistent storage
395/// - Performing safe shutdown procedures
396/// - Resetting the system via watchdog
397///
398/// # Custom Panic Handler
399///
400/// To provide your own panic handler, enable the `disable_panic` feature:
401///
402/// ```toml
403/// [dependencies]
404/// osal-rs = { version = "*", features = ["disable_panic"] }
405/// ```
406///
407/// Then define your own `#[panic_handler]` in your application.
408#[cfg(not(feature = "disable_panic"))]
409#[panic_handler]
410fn panic(info: &core::panic::PanicInfo) -> ! {
411    println!("Panic occurred: {}", info);
412    #[allow(clippy::empty_loop)]
413    loop {}
414}
415