Skip to main content

leodos_libcfs/cfe/es/
counter.rs

1//! Safe, idiomatic wrappers for the CFE Executive Services Generic Counter API.
2//!
3//! This module provides a `Counter` struct that is a thread-safe, RAII-based
4//! handle for creating, incrementing, and managing generic counters.
5
6use crate::error::{CfsError, OsalError, Result};
7use crate::ffi;
8use crate::cstring;
9use crate::status::check;
10use core::mem::MaybeUninit;
11use heapless::String;
12
13/// A handle to a cFE generic counter.
14///
15/// The counter can be shared across tasks. The underlying cFE
16/// resource is automatically deleted when the `Counter` is dropped.
17#[derive(Debug)]
18pub struct Counter {
19    id: CounterId,
20}
21
22/// A type-safe, zero-cost wrapper for a cFE Generic Counter ID.
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct CounterId(ffi::CFE_ES_CounterId_t);
25
26impl Counter {
27    /// Registers a new generic counter with cFE.
28    ///
29    /// The counter is initialized to 0.
30    ///
31    /// # Arguments
32    /// * `name`: A unique string to identify the counter.
33    pub fn new(name: &str) -> Result<Self> {
34        let c_name = cstring::<{ ffi::OS_MAX_API_NAME as usize }>(name)?;
35
36        let mut counter_id = MaybeUninit::uninit();
37        check(unsafe { ffi::CFE_ES_RegisterGenCounter(counter_id.as_mut_ptr(), c_name.as_ptr()) })?;
38        Ok(Self {
39            id: CounterId(unsafe { counter_id.assume_init() }),
40        })
41    }
42
43    /// Increments the counter's value by one.
44    ///
45    /// Note: the C header does not guarantee atomicity for this
46    /// operation.
47    pub fn inc(&self) -> Result<()> {
48        check(unsafe { ffi::CFE_ES_IncrementGenCounter(self.id.0) })?;
49        Ok(())
50    }
51
52    /// Sets the counter's value to a specific number.
53    pub fn set(&self, count: u32) -> Result<()> {
54        check(unsafe { ffi::CFE_ES_SetGenCount(self.id.0, count) })?;
55        Ok(())
56    }
57
58    /// Retrieves the current value of the counter.
59    pub fn get(&self) -> Result<u32> {
60        let mut count = 0;
61        check(unsafe { ffi::CFE_ES_GetGenCount(self.id.0, &mut count) })?;
62        Ok(count)
63    }
64
65    /// Returns the underlying cFE ID of the counter.
66    pub fn id(&self) -> CounterId {
67        self.id
68    }
69
70    /// Gets the cFE ID for a generic counter by its registered name.
71    pub fn get_id_by_name(name: &str) -> Result<CounterId> {
72        let c_name = cstring::<{ ffi::OS_MAX_API_NAME as usize }>(name)?;
73
74        let mut counter_id = MaybeUninit::uninit();
75        check(unsafe {
76            ffi::CFE_ES_GetGenCounterIDByName(counter_id.as_mut_ptr(), c_name.as_ptr())
77        })?;
78        Ok(CounterId(unsafe { counter_id.assume_init() }))
79    }
80}
81
82impl Drop for Counter {
83    /// Deletes the generic counter when the `Counter` object goes out of scope.
84    fn drop(&mut self) {
85        let _ = unsafe { ffi::CFE_ES_DeleteGenCounter(self.id.0) };
86    }
87}
88
89impl CounterId {
90    /// Gets the cFE registered name for this generic counter ID.
91    pub fn name(&self) -> Result<String<{ ffi::OS_MAX_API_NAME as usize }>> {
92        let mut buffer = [0u8; ffi::OS_MAX_API_NAME as usize];
93        check(unsafe {
94            ffi::CFE_ES_GetGenCounterName(
95                buffer.as_mut_ptr() as *mut libc::c_char,
96                self.0,
97                buffer.len(),
98            )
99        })?;
100        let len = buffer.iter().position(|&b| b == 0).unwrap_or(buffer.len());
101        let vec = heapless::Vec::from_slice(&buffer[..len]).map_err(|_| CfsError::Osal(OsalError::NameTooLong))?;
102        String::from_utf8(vec).map_err(|_| CfsError::InvalidString)
103    }
104
105    /// Converts the Counter ID into a zero-based integer suitable for array indexing.
106    pub fn to_index(&self) -> Result<u32> {
107        let mut index = MaybeUninit::uninit();
108        check(unsafe { ffi::CFE_ES_CounterID_ToIndex(self.0, index.as_mut_ptr()) })?;
109        Ok(unsafe { index.assume_init() })
110    }
111}