Skip to main content

leodos_libcfs/os/
id.rs

1//! Generic OSAL object ID APIs.
2//!
3//! This module provides utilities for working with generic `OsalId`s, which
4//! are the underlying type for all OSAL resources (tasks, queues, mutexes, etc.).
5
6use crate::error::Result;
7use crate::ffi::{self, OS_OBJECT_CREATOR_ANY};
8use crate::status::check;
9use crate::string_from_c_buf;
10use core::mem::MaybeUninit;
11use heapless::String;
12
13/// A generic, type-safe wrapper for an OSAL object ID.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[repr(transparent)]
16pub struct OsalId(pub ffi::osal_id_t);
17
18impl From<ffi::osal_id_t> for OsalId {
19    fn from(id: ffi::osal_id_t) -> Self {
20        Self(id)
21    }
22}
23
24impl OsalId {
25    /// Retrieves the name of this OSAL object.
26    ///
27    /// # Errors
28    ///
29    /// Returns an error if the object ID is invalid, the buffer is too small
30    /// (unlikely with `heapless`), or the name is not valid UTF-8.
31    pub fn name(&self) -> Result<String<{ ffi::OS_MAX_API_NAME as usize }>> {
32        let mut buffer = [0 as core::ffi::c_char; ffi::OS_MAX_API_NAME as usize];
33        check(unsafe {
34            ffi::OS_GetResourceName(
35                self.0,
36                buffer.as_mut_ptr(),
37                buffer.len(),
38            )
39        })?;
40        string_from_c_buf(&buffer)
41    }
42
43    /// Identifies the type of this OSAL object.
44    pub fn object_type(&self) -> ObjectType {
45        let type_val = unsafe { ffi::OS_IdentifyObject(self.0) };
46        ObjectType::from(type_val)
47    }
48
49    /// Converts this abstract ID into a zero-based integer suitable
50    /// for use as an array index.
51    ///
52    /// This does NOT verify that the ID refers to a currently valid
53    /// or active resource — it only performs the numeric conversion.
54    pub fn to_index(&self) -> Result<u32> {
55        let mut index = MaybeUninit::uninit();
56        check(unsafe { ffi::OS_ConvertToArrayIndex(self.0, index.as_mut_ptr()) })?;
57        Ok(unsafe { index.assume_init() })
58    }
59
60    /// Converts this abstract ID of a specific type into a zero-based integer.
61    ///
62    /// # Errors
63    ///
64    /// Returns `Error::OsErrInvalidId` if this ID is not of the
65    /// specified `obj_type` or does not map to a valid index.
66    pub fn to_index_as_type(&self, obj_type: ObjectType) -> Result<u32> {
67        let mut index = MaybeUninit::uninit();
68        check(unsafe {
69            ffi::OS_ObjectIdToArrayIndex(obj_type.into(), self.0, index.as_mut_ptr())
70        })?;
71        Ok(unsafe { index.assume_init() })
72    }
73}
74
75/// The type of an OSAL object.
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77#[repr(u32)]
78pub enum ObjectType {
79    /// An undefined or invalid object type.
80    Undefined = ffi::OS_OBJECT_TYPE_UNDEFINED,
81    /// An OSAL task.
82    Task = ffi::OS_OBJECT_TYPE_OS_TASK,
83    /// An OSAL message queue.
84    Queue = ffi::OS_OBJECT_TYPE_OS_QUEUE,
85    /// An OSAL counting semaphore.
86    CountSem = ffi::OS_OBJECT_TYPE_OS_COUNTSEM,
87    /// An OSAL binary semaphore.
88    BinSem = ffi::OS_OBJECT_TYPE_OS_BINSEM,
89    /// An OSAL mutex.
90    Mutex = ffi::OS_OBJECT_TYPE_OS_MUTEX,
91    /// An OSAL stream (file descriptor).
92    Stream = ffi::OS_OBJECT_TYPE_OS_STREAM,
93    /// An OSAL directory handle.
94    Dir = ffi::OS_OBJECT_TYPE_OS_DIR,
95    /// An OSAL time base.
96    TimeBase = ffi::OS_OBJECT_TYPE_OS_TIMEBASE,
97    /// An OSAL timer callback.
98    TimerCb = ffi::OS_OBJECT_TYPE_OS_TIMECB,
99    /// An OSAL loadable module.
100    Module = ffi::OS_OBJECT_TYPE_OS_MODULE,
101    /// An OSAL file system.
102    FileSys = ffi::OS_OBJECT_TYPE_OS_FILESYS,
103    /// An OSAL console device.
104    Console = ffi::OS_OBJECT_TYPE_OS_CONSOLE,
105    /// An OSAL condition variable.
106    CondVar = ffi::OS_OBJECT_TYPE_OS_CONDVAR,
107    /// A user-defined object type.
108    User = ffi::OS_OBJECT_TYPE_USER,
109    /// An unknown or unhandled object type.
110    Unknown(u32),
111}
112
113impl From<u32> for ObjectType {
114    fn from(val: u32) -> Self {
115        match val {
116            ffi::OS_OBJECT_TYPE_UNDEFINED => Self::Undefined,
117            ffi::OS_OBJECT_TYPE_OS_TASK => Self::Task,
118            ffi::OS_OBJECT_TYPE_OS_QUEUE => Self::Queue,
119            ffi::OS_OBJECT_TYPE_OS_COUNTSEM => Self::CountSem,
120            ffi::OS_OBJECT_TYPE_OS_BINSEM => Self::BinSem,
121            ffi::OS_OBJECT_TYPE_OS_MUTEX => Self::Mutex,
122            ffi::OS_OBJECT_TYPE_OS_STREAM => Self::Stream,
123            ffi::OS_OBJECT_TYPE_OS_DIR => Self::Dir,
124            ffi::OS_OBJECT_TYPE_OS_TIMEBASE => Self::TimeBase,
125            ffi::OS_OBJECT_TYPE_OS_TIMECB => Self::TimerCb,
126            ffi::OS_OBJECT_TYPE_OS_MODULE => Self::Module,
127            ffi::OS_OBJECT_TYPE_OS_FILESYS => Self::FileSys,
128            ffi::OS_OBJECT_TYPE_OS_CONSOLE => Self::Console,
129            ffi::OS_OBJECT_TYPE_OS_CONDVAR => Self::CondVar,
130            ffi::OS_OBJECT_TYPE_USER => Self::User,
131            other => Self::Unknown(other),
132        }
133    }
134}
135
136impl Into<u32> for ObjectType {
137    fn into(self) -> u32 {
138        match self {
139            Self::Undefined => ffi::OS_OBJECT_TYPE_UNDEFINED,
140            Self::Task => ffi::OS_OBJECT_TYPE_OS_TASK,
141            Self::Queue => ffi::OS_OBJECT_TYPE_OS_QUEUE,
142            Self::CountSem => ffi::OS_OBJECT_TYPE_OS_COUNTSEM,
143            Self::BinSem => ffi::OS_OBJECT_TYPE_OS_BINSEM,
144            Self::Mutex => ffi::OS_OBJECT_TYPE_OS_MUTEX,
145            Self::Stream => ffi::OS_OBJECT_TYPE_OS_STREAM,
146            Self::Dir => ffi::OS_OBJECT_TYPE_OS_DIR,
147            Self::TimeBase => ffi::OS_OBJECT_TYPE_OS_TIMEBASE,
148            Self::TimerCb => ffi::OS_OBJECT_TYPE_OS_TIMECB,
149            Self::Module => ffi::OS_OBJECT_TYPE_OS_MODULE,
150            Self::FileSys => ffi::OS_OBJECT_TYPE_OS_FILESYS,
151            Self::Console => ffi::OS_OBJECT_TYPE_OS_CONSOLE,
152            Self::CondVar => ffi::OS_OBJECT_TYPE_OS_CONDVAR,
153            Self::User => ffi::OS_OBJECT_TYPE_USER,
154            Self::Unknown(val) => val,
155        }
156    }
157}
158
159/// A generic trampoline function to bridge a C callback to a Rust closure.
160///
161/// This function is not meant to be called directly. It's a helper to allow
162/// passing closures to C APIs that expect a function pointer and a `void *` context.
163unsafe extern "C" fn trampoline<F>(id: ffi::osal_id_t, arg: *mut core::ffi::c_void)
164where
165    F: FnMut(OsalId),
166{
167    // Cast the `void *` argument back into a mutable reference to our closure.
168    let callback = &mut *(arg as *mut F);
169    // Call the closure with the provided ID.
170    callback(OsalId(id));
171}
172
173/// Iterates over all OSAL objects and calls a closure for each one.
174///
175/// # Arguments
176/// * `creator_id`: If `Some(id)`, only objects created by that task ID are processed.
177///   If `None`, all objects are processed.
178/// * `callback`: A closure that will be called with the ID of each object.
179pub fn for_each_object<F>(creator_id: Option<OsalId>, mut callback: F)
180where
181    F: FnMut(OsalId),
182{
183    unsafe {
184        ffi::OS_ForEachObject(
185            creator_id.map_or(OS_OBJECT_CREATOR_ANY, |id| id.0),
186            // Pass the generic trampoline function pointer.
187            Some(trampoline::<F>),
188            // Pass a pointer to our closure as the `void *` context.
189            &mut callback as *mut F as *mut core::ffi::c_void,
190        );
191    }
192}
193
194/// Iterates over all OSAL objects of a specific type and calls a closure for each one.
195///
196/// # Arguments
197/// * `obj_type`: The type of object to iterate over.
198/// * `creator_id`: If `Some(id)`, only objects created by that task ID are processed.
199///   If `None`, all objects are processed.
200/// * `callback`: A closure that will be called with the ID of each object.
201pub fn for_each_object_of_type<F>(obj_type: ObjectType, creator_id: Option<OsalId>, mut callback: F)
202where
203    F: FnMut(OsalId),
204{
205    unsafe {
206        ffi::OS_ForEachObjectOfType(
207            obj_type.into(),
208            creator_id.map_or(OS_OBJECT_CREATOR_ANY, |id| id.0),
209            // Reuse the same generic trampoline function pointer.
210            Some(trampoline::<F>),
211            // Pass a pointer to our closure as the `void *` context.
212            &mut callback as *mut F as *mut core::ffi::c_void,
213        );
214    }
215}