Skip to main content

rustmeter_beacon_core/
tracing.rs

1use critical_section::Mutex;
2
3use crate::{
4    buffer::{BufferReader, BufferWriter},
5    protocol::EventPayload,
6    time_delta::TimeDelta,
7};
8
9unsafe extern "Rust" {
10    /// Low-level function to write tracing data. Implemented in the target crate.
11    pub fn write_tracing_data(data: &[u8]);
12}
13
14static TRACE_WRITING: Mutex<()> = Mutex::new(());
15
16/// Serializes and writes a tracing event with timestamp to the tracing channel
17pub fn write_tracing_event(event: EventPayload) {
18    // Ensure only one tracing event is written at a time
19    critical_section::with(|cs| {
20        let _lock = TRACE_WRITING.borrow(cs);
21
22        let timestamp = TimeDelta::from_now();
23
24        // Write event data
25        let mut buffer = BufferWriter::new();
26        event.write_bytes(&mut buffer);
27        timestamp.write_bytes(&mut buffer);
28
29        // Send the data over RTT
30        unsafe { write_tracing_data(buffer.as_slice()) };
31    });
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ReadTracingError {
36    InvalidEventType,
37    InvalidTypedefID,
38    InvalidValueTypeID,
39    VarIntOverflow,
40    FloatConversionError,
41    StringConversionError(core::str::Utf8Error),
42    InsufficientData,
43}
44
45impl From<core::str::Utf8Error> for ReadTracingError {
46    fn from(err: core::str::Utf8Error) -> Self {
47        ReadTracingError::StringConversionError(err)
48    }
49}
50
51/// Reads a tracing event with timestamp from the provided buffer
52pub fn read_tracing_event(buffer: &mut BufferReader) -> Result<(TimeDelta, EventPayload), ReadTracingError> {
53    let event_type = buffer.read_byte()?;
54    let event = EventPayload::from_bytes(event_type, buffer)?;
55    let timestamp = TimeDelta::read_bytes(buffer)?;
56
57    Ok((timestamp, event))
58}
59
60#[cfg(test)]
61mod tests {
62    use arbitrary_int::u3;
63
64    use super::*;
65    use crate::{
66        mocks::test_mocks::{mock_time_provider, mock_trace_writer, with_mocks},
67        protocol::TypeDefinitionPayload,
68    };
69
70    #[test]
71    fn test_tracing_event_write_and_read() {
72        let events = vec![
73            EventPayload::EmbassyTaskReady {
74                task_id: 1234,
75                executor_id: u3::new(2),
76            },
77            EventPayload::EmbassyExecutorPollStart {
78                executor_id: u3::new(5),
79            },
80            EventPayload::TypeDefinition(TypeDefinitionPayload::FunctionMonitor {
81                monitor_id: 42,
82                fn_address: 0xDEADBEEF,
83            }),
84            EventPayload::TypeDefinition(TypeDefinitionPayload::ScopeMonitor {
85                monitor_id: 7,
86                name: "TestScope".to_string(),
87            }),
88            EventPayload::MonitorValue {
89                value_id: 1,
90                value: 456i16.into(),
91            },
92        ];
93
94        for event in events {
95            with_mocks(
96                mock_trace_writer(event.clone()),
97                mock_time_provider,
98                || 0,
99                || {
100                    write_tracing_event(event);
101                },
102            );
103        }
104    }
105}