osal_rs/
utils.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2023/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//! Utility types and functions for OSAL-RS.
21//!
22//! This module contains common types, error definitions, and helper functions
23//! used throughout the library.
24
25use core::ffi::{CStr, c_char};
26use core::{ffi::c_void, str::from_utf8_mut};
27use core::fmt::{Debug, Display}; 
28use core::ops::Deref;
29use core::time::Duration;
30use alloc::string::{String, ToString};
31
32/// Error types for OSAL-RS operations.
33///
34/// Represents all possible error conditions that can occur when using
35/// the OSAL-RS library.
36///
37/// # Examples
38///
39/// ```ignore
40/// use osal_rs::os::{Queue, QueueFn};
41/// use osal_rs::utils::Error;
42/// 
43/// match Queue::new(10, 32) {
44///     Ok(queue) => { /* use queue */ },
45///     Err(Error::OutOfMemory) => println!("Failed to allocate queue"),
46///     Err(e) => println!("Other error: {:?}", e),
47/// }
48/// ```
49#[derive(Debug, Clone, PartialEq, Eq, Hash)]
50pub enum Error {
51    /// Insufficient memory to complete operation
52    OutOfMemory,
53    /// Queue send operation timed out
54    QueueSendTimeout,
55    /// Queue receive operation timed out
56    QueueReceiveTimeout,
57    /// Mutex operation timed out
58    MutexTimeout,
59    /// Failed to acquire mutex lock
60    MutexLockFailed,
61    /// Generic timeout error
62    Timeout,
63    /// Queue is full and cannot accept more items
64    QueueFull,
65    /// String conversion failed
66    StringConversionError,
67    /// Thread/task not found
68    TaskNotFound,
69    /// Invalid queue size specified
70    InvalidQueueSize,
71    /// Null pointer encountered
72    NullPtr,
73    /// Requested item not found
74    NotFound,
75    /// Index out of bounds
76    OutOfIndex,
77    /// Invalid type for operation
78    InvalidType,
79    /// Unhandled error with description
80    Unhandled(&'static str)
81}
82
83/// CPU register size enumeration.
84///
85/// Identifies whether the target CPU uses 32-bit or 64-bit registers.
86/// This is used for platform-specific tick count overflow handling.
87#[derive(PartialEq, Eq, Clone, Copy, Debug)]
88pub enum CpuRegisterSize {
89    /// 64-bit CPU registers
90    Bit64,
91    /// 32-bit CPU registers
92    Bit32
93}
94
95/// Boolean type compatible with RTOS return values.
96///
97/// Many RTOS functions return 0 for success and non-zero for failure.
98/// This type provides a Rust-idiomatic way to work with such values.
99///
100/// # Examples
101///
102/// ```ignore
103/// use osal_rs::os::{Semaphore, SemaphoreFn};
104/// use osal_rs::utils::OsalRsBool;
105/// use core::time::Duration;
106/// 
107/// let sem = Semaphore::new(1, 1).unwrap();
108/// 
109/// match sem.wait(Duration::from_millis(100)) {
110///     OsalRsBool::True => println!("Acquired semaphore"),
111///     OsalRsBool::False => println!("Failed to acquire"),
112/// }
113/// 
114/// // Can also convert to bool
115/// if sem.signal().into() {
116///     println!("Semaphore signaled");
117/// }
118/// ```
119#[derive(PartialEq, Eq, Clone, Copy, Debug)]
120#[repr(u8)]
121pub enum OsalRsBool {
122    /// Operation failed or condition is false
123    False = 1,
124    /// Operation succeeded or condition is true
125    True = 0
126}
127
128/// Maximum delay constant for blocking operations.
129///
130/// When used as a timeout parameter, indicates the operation should
131/// block indefinitely until it succeeds.
132///
133/// # Examples
134///
135/// ```ignore
136/// use osal_rs::os::{Mutex, MutexFn};
137/// use osal_rs::utils::MAX_DELAY;
138/// 
139/// let mutex = Mutex::new(0);
140/// let guard = mutex.lock();  // Blocks forever if needed
141/// ```
142pub const MAX_DELAY: Duration = Duration::from_millis(usize::MAX as u64);
143
144/// Standard Result type for OSAL-RS operations.
145///
146/// Uses [`Error`] as the default error type.
147pub type Result<T, E = Error> = core::result::Result<T, E>;
148
149/// Pointer to pointer type for C FFI.
150pub type DoublePtr = *mut *mut c_void;
151
152/// Mutable pointer type for C FFI.
153pub type Ptr = *mut c_void;
154
155/// Const pointer type for C FFI.
156pub type ConstPtr = *const c_void;
157
158
159pub const fn register_bit_size() -> CpuRegisterSize {
160    if size_of::<usize>() == 8 {
161        CpuRegisterSize::Bit64
162    } else {
163        CpuRegisterSize::Bit32
164    }
165}
166
167#[macro_export]
168macro_rules! from_c_str {
169    ($str:expr) => {
170        unsafe {
171            let c_str = core::ffi::CStr::from_ptr($str);
172            alloc::string::String::from_utf8_lossy(c_str.to_bytes()).to_string()
173        }
174    };
175}
176
177#[macro_export]
178macro_rules! to_cstring {
179    ($s:expr) => {
180        alloc::ffi::CString::new($s.as_str())
181            .map_err(|_| $crate::utils::Error::Unhandled("Failed to convert string to CString"))
182    };
183}
184
185#[macro_export]
186macro_rules! to_c_str {
187    ($s:expr) => {
188        alloc::ffi::CString::new($s.as_ref() as &str).unwrap().as_ptr()
189    };
190}
191
192#[macro_export]
193macro_rules! from_str_to_array {
194    ($str:expr, $buff_name:ident, $buff_size:expr) => {
195        let mut $buff_name = [b' '; $buff_size];
196        let _bytes = $str.as_bytes();
197        let _len = core::cmp::min(_bytes.len(), $buff_size);
198        $buff_name[.._len].copy_from_slice(&_bytes[.._len]);
199    };
200}
201
202#[macro_export]
203macro_rules! thread_extract_param {
204    ($param:expr, $t:ty) => {
205        match $param.as_ref() {
206            Some(p) => {
207                match p.downcast_ref::<$t>() {
208                    Some(value) => value,
209                    None => return Err($crate::utils::Error::InvalidType),
210                }
211            }
212            None => return Err($crate::utils::Error::NullPtr),
213        }
214    };
215}
216
217#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
218pub struct Bytes<const SIZE: usize = 0> (pub [u8; SIZE]);
219
220impl<const SIZE: usize> Deref for Bytes<SIZE> {
221    type Target = [u8; SIZE];
222
223    fn deref(&self) -> &Self::Target {
224        &self.0
225    }
226}
227
228impl<const SIZE: usize> Display for Bytes<SIZE> {
229    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
230        let str = unsafe {
231            CStr::from_ptr(self.0.as_ptr() as *const c_char)
232            .to_str()
233            .unwrap_or("Conversion error")
234        };
235        
236        write!(f, "{}", str.to_string())
237    }
238}
239
240
241impl<const SIZE: usize> Bytes<SIZE> {
242    pub const fn new() -> Self {
243        Self( [0u8; SIZE] )
244    }
245
246    pub fn new_by_str(str: &str) -> Self {
247
248        let mut array = [0u8; SIZE];
249        
250        let mut i = 0usize ;
251        for byte in str.as_bytes() {
252            if i > SIZE - 1{
253                break;
254            }
255            array[i] = *byte;
256            i += 1;
257        }  
258
259        Self( array )
260    }
261
262    pub fn new_by_string(str: &impl ToString) -> Self {
263        Self::new_by_str(&str.to_string())
264    }
265
266    pub fn fill_str(&mut self, dest: &mut str) {
267        match from_utf8_mut(&mut self.0) {
268            Ok(str) => {
269                let len = core::cmp::min(str.len(), dest.len());
270                unsafe {
271                    dest.as_bytes_mut()[..len].copy_from_slice(&str.as_bytes()[..len]);
272                }
273            }
274            Err(_) => todo!(),
275        }
276    }
277}