Skip to main content

leodos_libcfs/psp/
exception.rs

1//! Safe wrappers for PSP exception log functions.
2//!
3//! These functions allow an application to read and process the log of
4//! processor exceptions captured by the PSP. This is useful for advanced
5//! health monitoring or crash analysis tools.
6
7use crate::error::{CfsError, OsalError, Result};
8use crate::ffi;
9use crate::os::task::TaskId;
10use crate::status::check;
11use core::mem::MaybeUninit;
12use heapless::String;
13
14/// A summary of an exception log entry.
15#[derive(Debug, Clone)]
16pub struct ExceptionSummary {
17    /// The ID of the exception log entry.
18    pub context_log_id: u32,
19    /// The OSAL task ID of the task that caused the exception.
20    pub task_id: TaskId,
21    /// A descriptive reason for the exception.
22    pub reason: String<{ ffi::OS_ERROR_NAME_LENGTH as usize }>,
23}
24
25/// Returns the number of unread exceptions in the log.
26pub fn get_count() -> u32 {
27    unsafe { ffi::CFE_PSP_Exception_GetCount() }
28}
29
30/// Retrieves and **pops** the next exception log entry
31/// (destructive read).
32///
33/// Success does not guarantee all output fields contain valid
34/// data — only that they have been initialized.
35pub fn get_summary() -> Result<ExceptionSummary> {
36    let mut context_id = MaybeUninit::uninit();
37    let mut task_id = MaybeUninit::uninit();
38    let mut reason_buf = [0u8; ffi::OS_ERROR_NAME_LENGTH as usize];
39
40    check(unsafe {
41        ffi::CFE_PSP_Exception_GetSummary(
42            context_id.as_mut_ptr(),
43            task_id.as_mut_ptr(),
44            reason_buf.as_mut_ptr() as *mut libc::c_char,
45            reason_buf.len() as u32,
46        )
47    })?;
48
49    let len = reason_buf
50        .iter()
51        .position(|&b| b == 0)
52        .unwrap_or(reason_buf.len());
53    let reason_vec =
54        heapless::Vec::from_slice(&reason_buf[..len]).map_err(|_| CfsError::Osal(OsalError::NameTooLong))?;
55    let reason = String::from_utf8(reason_vec).map_err(|_| CfsError::InvalidString)?;
56
57    Ok(ExceptionSummary {
58        context_log_id: unsafe { context_id.assume_init() },
59        task_id: TaskId(unsafe { task_id.assume_init() }),
60        reason,
61    })
62}
63
64/// Copies the processor context of a specific exception log entry
65/// into a buffer.
66///
67/// Returns the number of bytes copied. May return
68/// `NO_EXCEPTION_DATA` if the context data has expired from
69/// the circular memory log.
70///
71/// # Safety
72/// The `context_buf` must be a valid, writable buffer of at least `context_buf.len()` bytes.
73pub unsafe fn copy_context(context_log_id: u32, context_buf: &mut [u8]) -> Result<usize> {
74    let bytes_copied = ffi::CFE_PSP_Exception_CopyContext(
75        context_log_id,
76        context_buf.as_mut_ptr() as *mut _,
77        context_buf.len() as u32,
78    );
79
80    if bytes_copied < 0 {
81        Err(CfsError::from(bytes_copied))
82    } else {
83        Ok(bytes_copied as usize)
84    }
85}