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//! - [`async_primitives`] - Async wrappers for OSAL primitives (feature `async`)
180//! - [`utils`] - Utility types and error definitions
181//! - [`log`] - Logging macros
182//! - `traits` - Private module defining the trait abstractions
183//! - `freertos` - Private FreeRTOS implementation (enabled with `freertos` feature)
184//! - `posix` - Private POSIX implementation (enabled with `posix` feature)
185//!
186//! ## Features
187//!
188//! | Feature | Default | Description |
189//! |---------|---------|-------------|
190//! | `freertos` | ❌ | FreeRTOS backend |
191//! | `posix` | ❌ | POSIX/host backend |
192//! | `async` | ❌ | Async/await without Tokio |
193//! | `serde` | ❌ | Serialization via `osal-rs-serde` |
194//! | `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 |
195//!
196//! There is no default backend: exactly one of `freertos`/`posix` must be
197//! enabled explicitly. Enabling neither trips the `compile_error!` below;
198//! enabling both is equally unsupported (the two are mutually exclusive by
199//! `cfg`, so the crate fails to build either way).
200//!
201//! ## Requirements
202//!
203//! When using with FreeRTOS:
204//! - FreeRTOS kernel must be properly configured
205//! - Link the C porting layer from `osal-rs-porting/freertos/`
206//! - Set appropriate `FreeRTOSConfig.h` options:
207//! - `configTICK_RATE_HZ` - Defines the tick frequency
208//! - `configUSE_MUTEXES` - Must be 1 for mutex support
209//! - `configUSE_COUNTING_SEMAPHORES` - Must be 1 for semaphore support
210//! - `configUSE_TIMERS` - Must be 1 for timer support
211//! - `configSUPPORT_DYNAMIC_ALLOCATION` - Must be 1 for dynamic allocation
212//!
213//! When using with POSIX:
214//! - A POSIX-compliant host implementing pthreads, `timer_create(2)`/`sigwait(3)`
215//! and `CLOCK_MONOTONIC` (glibc/Linux is part of this crate's test suite)
216//! - No special build steps: unlike `freertos`, this backend links only
217//! against the host's libc/libpthread - no cross toolchain or RTOS kernel
218//! sources required
219//! - Disables `no_std`: the `posix` feature builds the crate against `std`
220//!
221//! ## Platform Support
222//!
223//! Currently tested on:
224//! - ARM Cortex-M (Raspberry Pi Pico/RP2040, RP2350) - `freertos` backend
225//! - ARM Cortex-M4F (STM32F4 series) - `freertos` backend
226//! - ARM Cortex-M7 (STM32H7 series) - `freertos` backend
227//! - RISC-V (RP2350 RISC-V cores) - `freertos` backend
228//! - glibc/Linux - `posix` backend
229//!
230//! ## Thread Safety
231//!
232//! All types are designed with thread safety in mind:
233//! - Most operations are thread-safe and can be called from multiple threads
234//! - Methods with `_from_isr` suffix are ISR-safe (callable from interrupt context)
235//! - Regular methods (without `_from_isr`) must not be called from ISR context
236//! - Mutexes use priority inheritance to prevent priority inversion
237//!
238//! ## ISR Context
239//!
240//! Operations in ISR context have restrictions (applies to the `freertos`
241//! backend; POSIX has no interrupt context - `_from_isr` variants are
242//! provided there for API compatibility but behave like their regular
243//! counterparts):
244//! - Cannot block or use timeouts (must use zero timeout or `_from_isr` variants)
245//! - Must be extremely fast to avoid blocking other interrupts
246//! - Use semaphores or queues to defer work to task context
247//! - Event groups and notifications are ISR-safe for signaling
248//!
249//! ## Safety
250//!
251//! This library uses `unsafe` internally to interface with C APIs but provides
252//! safe Rust abstractions. All public APIs are designed to be memory-safe when
253//! used correctly:
254//! - Type safety through generic parameters
255//! - RAII patterns for automatic resource management
256//! - Rust's ownership system prevents data races
257//! - FFI boundaries are carefully validated
258//!
259//! ## Performance Considerations
260//!
261//! - `freertos` backend: allocations happen on the FreeRTOS heap (via the
262//! `#[global_allocator]` in [`os`]), not the system heap
263//! - `posix` backend: uses the system allocator and native OS threads; each
264//! [`os::Timer`] spawns a dedicated background thread
265//! - Stack sizes must be carefully tuned for each thread
266//! - Priority inversion is mitigated through priority inheritance
267//! - Context switches are triggered by blocking operations
268//!
269//! ## Best Practices
270//!
271//! 1. **Thread Creation**: Always specify appropriate stack sizes based on usage
272//! 2. **Mutexes**: Prefer scoped locking with guards to prevent deadlocks
273//! 3. **Queues**: Use type-safe `QueueStreamed` when possible
274//! 4. **Semaphores**: Use binary semaphores for signaling, counting for resources
275//! 5. **ISR Handlers**: Keep ISR code minimal, defer work to tasks
276//! 6. **Error Handling**: Always check `Result` return values
277//! 7. **Async Tasks**: Call `block_on` once per RTOS task; do not nest executors
278//!
279//! ## License
280//!
281//! LGPL-2.1-or-later - See LICENSE file for details
282
283#![cfg_attr(not(feature = "posix"), no_std)]
284
285extern crate alloc;
286
287#[cfg(not(any(feature = "freertos", feature = "posix")))]
288compile_error!("Enable either the `freertos` backend or the `posix` host backend.");
289
290/// FreeRTOS implementation of OSAL traits.
291///
292/// This module contains the concrete implementation of all OSAL abstractions
293/// for FreeRTOS, including threads, mutexes, queues, timers, etc.
294///
295/// Enabled with the `freertos` feature flag (no default backend - must be
296/// requested explicitly).
297#[cfg(all(not(feature = "posix"), feature = "freertos"))]
298mod freertos;
299
300/// POSIX implementation of OSAL traits.
301///
302/// This module contains the concrete implementation of all OSAL abstractions
303/// on top of the POSIX/pthreads API (threads, mutexes, semaphores, queues,
304/// event groups, timers), so applications - and their tests and doc examples -
305/// can run natively on any POSIX host (Linux, macOS) without embedded hardware
306/// or a cross toolchain. See [`posix`] for details.
307///
308/// Enabled with the `posix` feature flag.
309#[cfg(all(feature = "posix", not(feature = "freertos")))]
310mod posix;
311
312pub mod log;
313
314/// Trait definitions for OSAL abstractions.
315///
316/// This private module defines all the trait interfaces that concrete
317/// implementations must satisfy. Traits are re-exported through the `os` module.
318mod traits;
319
320pub mod utils;
321
322/// Async executor (block_on).
323#[cfg(feature = "async")]
324mod async_executor;
325
326/// Async primitives (AsyncQueue, AsyncSemaphore, AsyncMutex).
327#[cfg(feature = "async")]
328pub mod async_primitives;
329
330/// Select FreeRTOS as the active OSAL backend.
331#[cfg(all(not(feature = "posix"), feature = "freertos"))]
332use crate::freertos as osal;
333
334/// Select POSIX as the active OSAL backend.
335#[cfg(all(feature = "posix", not(feature = "freertos")))]
336use crate::posix as osal;
337
338/// Main OSAL module re-exporting all OS abstractions and traits.
339///
340/// This module provides a unified interface to all OSAL functionality through `osal_rs::os::*`.
341/// It re-exports:
342/// - Thread management types (`Thread`, `ThreadNotification`)
343/// - Synchronization primitives (`Mutex`, `Semaphore`, `EventGroup`)
344/// - Communication types (`Queue`, `QueueStreamed`)
345/// - Timer types (`Timer`)
346/// - System functions (`System`)
347/// - All trait definitions from the `traits` module
348/// - Type definitions and configuration from the active backend
349///
350/// The actual implementation (FreeRTOS or POSIX) is selected at compile time via features.
351///
352/// # Examples
353///
354/// ```ignore
355/// use osal_rs::os::*;
356///
357/// fn main() {
358/// // Create and start a thread
359/// let thread = Thread::new("worker", 4096, 5, || {
360/// println!("Worker thread running");
361/// }).unwrap();
362///
363/// thread.start().unwrap();
364/// System::start();
365/// }
366/// ```
367pub mod os {
368
369 #[cfg(all(not(feature = "posix"), feature = "freertos"))]
370 use crate::osal::allocator::Allocator;
371
372 /// Global allocator using the underlying RTOS heap.
373 ///
374 /// This static variable configures Rust's global allocator to use the
375 /// RTOS heap (e.g., FreeRTOS heap) instead of the system heap.
376 ///
377 /// # Behavior
378 ///
379 /// - All allocations via `alloc::vec::Vec`, `alloc::boxed::Box`, `alloc::string::String`, etc.
380 /// will use the RTOS heap
381 /// - Memory is managed by the underlying RTOS (e.g., `pvPortMalloc`/`vPortFree` in FreeRTOS)
382 /// - Thread-safe: can be used from multiple tasks safely
383 ///
384 /// # Feature Flag
385 ///
386 /// Active when using the `freertos` backend.
387 ///
388 /// # FreeRTOS Configuration
389 ///
390 /// Ensure your `FreeRTOSConfig.h` has:
391 /// - `configSUPPORT_DYNAMIC_ALLOCATION` set to 1
392 /// - `configTOTAL_HEAP_SIZE` configured appropriately for your application
393 ///
394 /// # Example
395 ///
396 /// ```ignore
397 /// use alloc::vec::Vec;
398 ///
399 /// // This allocation uses the FreeRTOS heap via ALLOCATOR
400 /// let mut v = Vec::new();
401 /// v.push(42);
402 /// ```
403 #[cfg(all(not(feature = "posix"), feature = "freertos"))]
404 #[global_allocator]
405 pub static ALLOCATOR: Allocator = Allocator;
406
407 /// Event group synchronization primitives.
408 #[allow(unused_imports)]
409 pub use crate::osal::event_group::*;
410
411 /// Mutex types and guards for mutual exclusion.
412 #[allow(unused_imports)]
413 pub use crate::osal::mutex::*;
414
415 /// Queue types for inter-task communication.
416 #[allow(unused_imports)]
417 pub use crate::osal::queue::*;
418
419 /// Semaphore types for signaling and resource management.
420 #[allow(unused_imports)]
421 pub use crate::osal::semaphore::*;
422
423 /// System-level functions (scheduler, timing, critical sections).
424 pub use crate::osal::system::*;
425
426 /// Thread/task management and notification types.
427 pub use crate::osal::thread::*;
428
429 /// Software timer types for periodic and one-shot callbacks.
430 #[allow(unused_imports)]
431 pub use crate::osal::timer::*;
432
433 /// All OSAL trait definitions for advanced usage.
434 pub use crate::traits::*;
435
436 /// RTOS configuration constants and types.
437 pub use crate::osal::config as config;
438
439 /// Type aliases and common types used throughout OSAL.
440 pub use crate::osal::types as types;
441
442 /// Single-future async executor (backend-agnostic, no Tokio).
443 #[cfg(feature = "async")]
444 pub use crate::async_executor::block_on;
445
446 /// Async-capable wrappers for OSAL primitives.
447 #[cfg(feature = "async")]
448 pub use crate::async_primitives::*;
449
450}
451
452/// Default panic handler for `no_std` environments.
453///
454/// This panic handler is active for the `freertos` backend.
455/// It prints panic information and enters an infinite loop to halt execution.
456///
457/// # Behavior
458///
459/// 1. Attempts to print panic information using the `println!` macro
460/// 2. Enters an infinite empty loop, halting the program
461///
462/// # Feature Flag
463///
464/// - Enabled for `freertos`
465/// - Automatically disabled when using `posix`
466///
467/// # Safety
468///
469/// This handler is intentionally simple and does not attempt cleanup or recovery.
470/// In production embedded systems, consider:
471/// - Logging panic info to persistent storage
472/// - Performing safe shutdown procedures
473/// - Resetting the system via watchdog
474///
475#[cfg(all(not(feature = "posix"), feature = "freertos"))]
476#[panic_handler]
477fn panic(info: &core::panic::PanicInfo) -> ! {
478 println!("Panic occurred: {}", info);
479 #[allow(clippy::empty_loop)]
480 loop {}
481}
482