Skip to main content

leodos_libcfs/cfe/evs/
event.rs

1//! Event generation and management APIs.
2use crate::cfe::es::app::AppId;
3use crate::cfe::time::SysTime;
4use crate::error::{CfsError, Result};
5use crate::ffi::{self, CFE_EVS_BinFilter_t};
6use crate::status::check;
7
8/// The type of a cFE event message, indicating its severity.
9#[derive(Debug, Clone, Copy)]
10#[repr(u16)]
11pub enum EventType {
12    /// A low-priority event for debugging purposes.
13    Debug = ffi::CFE_EVS_EventType_CFE_EVS_EventType_DEBUG as u16,
14    /// An informational event about a nominal state or action.
15    Info = ffi::CFE_EVS_EventType_CFE_EVS_EventType_INFORMATION as u16,
16    /// An error event that is not catastrophic.
17    Error = ffi::CFE_EVS_EventType_CFE_EVS_EventType_ERROR as u16,
18    /// A critical error event that may require intervention.
19    Critical = ffi::CFE_EVS_EventType_CFE_EVS_EventType_CRITICAL as u16,
20}
21
22/// A binary event filter for controlling event reporting.
23#[repr(transparent)]
24pub struct BinFilter(CFE_EVS_BinFilter_t);
25
26impl BinFilter {
27    /// Creates a new binary filter for the specified event ID and mask.
28    ///
29    /// # Arguments
30    /// * `event_id` - The event ID to filter.
31    /// * `mask` - The filter mask to apply.
32    pub fn new(event_id: u16, mask: u16) -> Self {
33        BinFilter(CFE_EVS_BinFilter_t {
34            EventID: event_id,
35            Mask: mask,
36        })
37    }
38
39    /// Returns the event ID of the filter.
40    pub fn event_id(&self) -> u16 {
41        self.0.EventID
42    }
43
44    /// Returns the mask of the filter.
45    pub fn mask(&self) -> u16 {
46        self.0.Mask
47    }
48}
49
50/// Registers the calling application with the Event Services.
51/// Must be called before sending events.
52///
53/// Calling more than once wipes all previous filter settings.
54/// Filter registration is NOT cumulative.
55///
56/// # Arguments
57/// * `filters` - A slice of binary filters to register. Can be empty.
58pub fn register(filters: &[BinFilter]) -> Result<()> {
59    // For simplicity, not registering any filters initially. This can be expanded.
60    let status = if filters.is_empty() {
61        unsafe {
62            ffi::CFE_EVS_Register(
63                core::ptr::null(),
64                0,
65                ffi::CFE_EVS_EventFilter_CFE_EVS_EventFilter_BINARY as u16,
66            )
67        }
68    } else {
69        unsafe {
70            ffi::CFE_EVS_Register(
71                filters.as_ptr() as *const core::ffi::c_void,
72                filters.len() as u16,
73                ffi::CFE_EVS_EventFilter_CFE_EVS_EventFilter_BINARY as u16,
74            )
75        }
76    };
77    check(status)?;
78    Ok(())
79}
80
81/// Sends a formatted software event.
82///
83/// This is a safe wrapper around `CFE_EVS_SendEvent`. It handles creating a
84/// C-style format string and passing the arguments.
85///
86/// Only works within the context of a registered application (after
87/// calling [`register`]). For messages outside that context (e.g.
88/// early in init), use `CFE_ES_WriteToSysLog` instead.
89///
90/// NOTE: Due to the varargs nature of the underlying C function, this wrapper uses `core::fmt`
91/// and a temporary buffer. Ensure the buffer is large enough for your event messages.
92pub fn send(event_id: u16, event_type: EventType, message: &str) -> Result<()> {
93    // Create a heapless CString for the message.
94    // The max length comes from the CFE mission config.
95    let mut c_message: heapless::CString<{ ffi::CFE_MISSION_EVS_MAX_MESSAGE_LENGTH as usize }> =
96        heapless::CString::new();
97
98    c_message
99        .extend_from_bytes(message.as_bytes())
100        .map_err(|_| CfsError::ValidationFailure)?;
101
102    let status = unsafe {
103        // We pass the string as a single argument to a "%s" format specifier.
104        ffi::CFE_EVS_SendEvent(
105            event_id,
106            event_type as ffi::CFE_EVS_EventType_Enum_t,
107            "%s\0".as_ptr() as *const libc::c_char,
108            c_message.as_ptr(),
109        )
110    };
111    check(status)?;
112    Ok(())
113}
114
115/// Sends a debug-level software event.
116pub fn debug(event_id: u16, message: &str) -> Result<()> {
117    send(event_id, EventType::Debug, message)
118}
119
120/// Sends an info-level software event.
121pub fn info(event_id: u16, message: &str) -> Result<()> {
122    send(event_id, EventType::Info, message)
123}
124
125/// Sends an error-level software event.
126pub fn error(event_id: u16, message: &str) -> Result<()> {
127    send(event_id, EventType::Error, message)
128}
129
130/// Sends a critical-level software event.
131pub fn critical(event_id: u16, message: &str) -> Result<()> {
132    send(event_id, EventType::Critical, message)
133}
134
135impl AppId {
136    /// Sends a formatted software event that appears to originate from this application.
137    ///
138    /// This allows a library or shared service to send an event on behalf of
139    /// another application.
140    ///
141    /// # Errors
142    ///
143    /// Returns an error if the underlying `CFE_EVS_SendEventWithAppID` call fails.
144    pub fn send_event(&self, event_id: u16, event_type: EventType, message: &str) -> Result<()> {
145        let mut c_message: heapless::CString<{ ffi::CFE_MISSION_EVS_MAX_MESSAGE_LENGTH as usize }> =
146            heapless::CString::new();
147
148        c_message
149            .extend_from_bytes(message.as_bytes())
150            .map_err(|_| CfsError::ValidationFailure)?;
151
152        let status = unsafe {
153            ffi::CFE_EVS_SendEventWithAppID(
154                event_id,
155                event_type as ffi::CFE_EVS_EventType_Enum_t,
156                self.0,
157                "%s\0".as_ptr() as *const libc::c_char,
158                c_message.as_ptr(),
159            )
160        };
161        check(status)?;
162        Ok(())
163    }
164}
165
166/// Sends a formatted software event with a specific time tag.
167pub fn send_timed_event(
168    time: SysTime,
169    event_id: u16,
170    event_type: EventType,
171    message: &str,
172) -> Result<()> {
173    let mut c_message: heapless::CString<{ ffi::CFE_MISSION_EVS_MAX_MESSAGE_LENGTH as usize }> =
174        heapless::CString::new();
175
176    c_message
177        .extend_from_bytes(message.as_bytes())
178        .map_err(|_| CfsError::ValidationFailure)?;
179
180    let status = unsafe {
181        ffi::CFE_EVS_SendTimedEvent(
182            time.0,
183            event_id,
184            event_type as ffi::CFE_EVS_EventType_Enum_t,
185            "%s\0".as_ptr() as *const libc::c_char,
186            c_message.as_ptr(),
187        )
188    };
189    check(status)?;
190    Ok(())
191}
192
193/// Resets the filter for a single event ID for the calling application.
194pub fn reset_filter(event_id: u16) -> Result<()> {
195    check(unsafe { ffi::CFE_EVS_ResetFilter(event_id) })?;
196    Ok(())
197}
198
199/// Resets all event filters for the calling application.
200pub fn reset_all_filters() -> Result<()> {
201    check(unsafe { ffi::CFE_EVS_ResetAllFilters() })?;
202    Ok(())
203}