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/// ```
354/// use osal_rs::os::*;
355/// use std::sync::Arc;
356///
357/// // Create and start a thread
358/// let mut thread = Thread::new("worker", 4096, 5);
359/// let worker = thread.spawn_simple(|| {
360/// println!("Worker thread running");
361/// System::stop(); // asks `System::start()` below to hand control back
362/// Ok(Arc::new(()))
363/// }).unwrap();
364///
365/// System::start();
366///
367/// worker.delete();
368/// ```
369pub mod os {
370
371 #[cfg(all(not(feature = "posix"), feature = "freertos"))]
372 use crate::osal::allocator::Allocator;
373
374 /// Global allocator using the underlying RTOS heap.
375 ///
376 /// This static variable configures Rust's global allocator to use the
377 /// RTOS heap (e.g., FreeRTOS heap) instead of the system heap.
378 ///
379 /// # Behavior
380 ///
381 /// - All allocations via `alloc::vec::Vec`, `alloc::boxed::Box`, `alloc::string::String`, etc.
382 /// will use the RTOS heap
383 /// - Memory is managed by the underlying RTOS (e.g., `pvPortMalloc`/`vPortFree` in FreeRTOS)
384 /// - Thread-safe: can be used from multiple tasks safely
385 ///
386 /// # Feature Flag
387 ///
388 /// Active when using the `freertos` backend.
389 ///
390 /// # FreeRTOS Configuration
391 ///
392 /// Ensure your `FreeRTOSConfig.h` has:
393 /// - `configSUPPORT_DYNAMIC_ALLOCATION` set to 1
394 /// - `configTOTAL_HEAP_SIZE` configured appropriately for your application
395 ///
396 /// # Example
397 ///
398 /// ```ignore
399 /// use alloc::vec::Vec;
400 ///
401 /// // This allocation uses the FreeRTOS heap via ALLOCATOR
402 /// let mut v = Vec::new();
403 /// v.push(42);
404 /// ```
405 #[cfg(all(not(feature = "posix"), feature = "freertos"))]
406 #[global_allocator]
407 pub static ALLOCATOR: Allocator = Allocator;
408
409 /// Event group synchronization primitives.
410 #[allow(unused_imports)]
411 pub use crate::osal::event_group::*;
412
413 /// Mutex types and guards for mutual exclusion.
414 #[allow(unused_imports)]
415 pub use crate::osal::mutex::*;
416
417 /// Queue types for inter-task communication.
418 #[allow(unused_imports)]
419 pub use crate::osal::queue::*;
420
421 /// Semaphore types for signaling and resource management.
422 #[allow(unused_imports)]
423 pub use crate::osal::semaphore::*;
424
425 /// System-level functions (scheduler, timing, critical sections).
426 pub use crate::osal::system::*;
427
428 /// Thread/task management and notification types.
429 pub use crate::osal::thread::*;
430
431 /// Software timer types for periodic and one-shot callbacks.
432 #[allow(unused_imports)]
433 pub use crate::osal::timer::*;
434
435 /// All OSAL trait definitions for advanced usage.
436 pub use crate::traits::*;
437
438 /// RTOS configuration constants and types.
439 pub use crate::osal::config as config;
440
441 /// Type aliases and common types used throughout OSAL.
442 pub use crate::osal::types as types;
443
444 /// Single-future async executor (backend-agnostic, no Tokio).
445 #[cfg(feature = "async")]
446 pub use crate::async_executor::block_on;
447
448 /// Async-capable wrappers for OSAL primitives.
449 #[cfg(feature = "async")]
450 pub use crate::async_primitives::*;
451
452}
453
454/// Default panic handler for `no_std` environments.
455///
456/// This panic handler is active for the `freertos` backend.
457/// It prints panic information and enters an infinite loop to halt execution.
458///
459/// # Behavior
460///
461/// 1. Attempts to print panic information using the `println!` macro
462/// 2. Enters an infinite empty loop, halting the program
463///
464/// # Feature Flag
465///
466/// - Enabled for `freertos`
467/// - Automatically disabled when using `posix`
468///
469/// # Safety
470///
471/// This handler is intentionally simple and does not attempt cleanup or recovery.
472/// In production embedded systems, consider:
473/// - Logging panic info to persistent storage
474/// - Performing safe shutdown procedures
475/// - Resetting the system via watchdog
476///
477#[cfg(all(not(feature = "posix"), feature = "freertos"))]
478#[panic_handler]
479fn panic(info: &core::panic::PanicInfo) -> ! {
480 println!("Panic occurred: {}", info);
481 #[allow(clippy::empty_loop)]
482 loop {}
483}
484