Skip to main content

rustmeter_beacon_core/protocol/
event_payload.rs

1use crate::{
2    buffer::{BufferReader, BufferWriter},
3    protocol::{MonitorValuePayload, TypeDefinitionPayload},
4    tracing::ReadTracingError,
5};
6use arbitrary_int::{traits::Integer, u3, u5};
7
8#[derive(Debug, Clone, PartialEq)]
9pub enum EventPayload {
10    /// Embassy Task is ready to be polled (Waker called).
11    /// ExecutorID will also be included
12    EmbassyTaskReady { task_id: u16, executor_id: u3 },
13    /// Embassy Task execution began (poll called).
14    /// ExecutorID will also be included
15    EmbassyTaskExecBegin { task_id: u16, executor_id: u3 },
16    /// Embassy Task execution ended (returned Poll::Ready or yielded Poll::Pending).
17    /// ExecutorID is included because it is shorter to transmit than TaskID and we know the executor from the TaskExecBegin event.
18    EmbassyTaskExecEnd { executor_id: u3 },
19    /// Embassy Executor started polling tasks.
20    /// ExecutorID is included because it is the only identifier for the executor.
21    EmbassyExecutorPollStart { executor_id: u3 },
22    /// Embassy Executor is idle (no tasks to poll).
23    /// ExecutorID is included because it is the only identifier for the executor.
24    EmbassyExecutorIdle { executor_id: u3 },
25    /// Function or Scope Monitor started
26    /// MonitorID identifies the monitor instance (was assigned via previous TypeDefinition event).
27    MonitorStart { monitor_id: u8 },
28    /// Function or Scope Monitor ended
29    /// MonitorID are not included here because they can be inferred from the corresponding MonitorStart event
30    MonitorEnd,
31    /// Value Monitor reported a value
32    /// ValueID identifies the monitor instance (was assigned via previous TypeDefinition event).
33    /// Value is the reported value payload.
34    MonitorValue {
35        value_id: u8,
36        value: MonitorValuePayload,
37    },
38    /// Type Definition Event
39    TypeDefinition(TypeDefinitionPayload),
40    /// Data Loss Event because of buffer full situation
41    DataLossEvent { dropped_events: u32 },
42    DefmtData {
43        len: u8,
44        #[cfg(not(feature = "std"))]
45        data: *const u8,
46        #[cfg(feature = "std")]
47        data: Vec<u8>,
48    },
49}
50
51impl EventPayload {
52    pub const fn event_id(&self) -> u5 {
53        use crate::protocol::raw_writers::event_ids::*;
54        let id = match self {
55            EventPayload::EmbassyTaskReady { .. } => EMBASSY_TASK_READY,
56            EventPayload::EmbassyTaskExecBegin { .. } => EMBASSY_TASK_EXEC_BEGIN,
57            EventPayload::EmbassyTaskExecEnd { .. } => EMBASSY_TASK_EXEC_END,
58            EventPayload::EmbassyExecutorPollStart { .. } => EMBASSY_EXECUTOR_POLL_START,
59            EventPayload::EmbassyExecutorIdle { .. } => EMBASSY_EXECUTOR_IDLE,
60            EventPayload::MonitorStart { .. } => MONITOR_START,
61            EventPayload::MonitorEnd => MONITOR_END,
62            EventPayload::MonitorValue { .. } => MONITOR_VALUE,
63            EventPayload::TypeDefinition(_) => TYPE_DEFINITION,
64            EventPayload::DataLossEvent { .. } => DATA_LOSS_EVENT,
65            EventPayload::DefmtData { .. } => DEFMT_DATA_EVENT,
66        };
67
68        u5::new(id)
69    }
70
71    /// Returns the executor ID if the event is related to an embassy executor
72    pub const fn get_executor_id(&self) -> Option<u3> {
73        match self {
74            EventPayload::EmbassyTaskReady { executor_id, .. } => Some(*executor_id),
75            EventPayload::EmbassyTaskExecBegin { executor_id, .. } => Some(*executor_id),
76            EventPayload::EmbassyTaskExecEnd { executor_id, .. } => Some(*executor_id),
77            EventPayload::EmbassyExecutorPollStart { executor_id, .. } => Some(*executor_id),
78            EventPayload::EmbassyExecutorIdle { executor_id, .. } => Some(*executor_id),
79            _ => None,
80        }
81    }
82
83    /// Returns the MonitorValuePayload type ID if the event is a MonitorValue event
84    pub const fn get_monitor_value_type_id(&self) -> Option<u3> {
85        match self {
86            EventPayload::MonitorValue { value, .. } => Some(value.type_id()),
87            _ => None,
88        }
89    }
90
91    /// Returns the sub ID (executor ID or MonitorValue type ID) if applicable
92    pub const fn get_sub_id(&self) -> Option<u3> {
93        // Check for executor ID
94        if let Some(executor_id) = self.get_executor_id() {
95            return Some(executor_id);
96        }
97        // Check for MonitorValue type ID
98        if let Some(type_id) = self.get_monitor_value_type_id() {
99            return Some(type_id);
100        }
101
102        None
103    }
104
105    pub fn write_bytes(&self, writer: &mut BufferWriter) {
106        // Write the event ID (5 bits) and sub event id (3 bits) as a single byte
107        let sub_id = self.get_sub_id().unwrap_or(u3::new(0));
108        let event_type = u8::from(self.event_id()) << 3 | sub_id.as_u8();
109        writer.write_byte(event_type);
110
111        // Write event-specific data
112        match self {
113            EventPayload::EmbassyTaskReady {
114                task_id,
115                executor_id: _,
116            } => {
117                writer.write_bytes(&task_id.to_le_bytes());
118            }
119            EventPayload::EmbassyTaskExecBegin {
120                task_id,
121                executor_id: _,
122            } => {
123                writer.write_bytes(&task_id.to_le_bytes());
124            }
125            EventPayload::EmbassyTaskExecEnd { executor_id: _ } => {}
126            EventPayload::EmbassyExecutorPollStart { executor_id: _ } => {}
127            EventPayload::EmbassyExecutorIdle { executor_id: _ } => {}
128            EventPayload::MonitorStart { monitor_id } => {
129                writer.write_byte(*monitor_id);
130            }
131            EventPayload::MonitorEnd => {}
132            EventPayload::MonitorValue { value_id, value } => {
133                writer.write_byte(*value_id);
134                value.write_bytes(writer);
135            }
136            EventPayload::TypeDefinition(def) => {
137                def.write_bytes(writer);
138            }
139            EventPayload::DataLossEvent { dropped_events } => {
140                writer.write_bytes(&dropped_events.to_le_bytes());
141            }
142            EventPayload::DefmtData { data, len } => {
143                writer.write_byte(*len);
144                #[cfg(not(feature = "std"))]
145                unsafe {
146                    writer.write_bytes(core::slice::from_raw_parts(*data, *len as usize));
147                }
148                #[cfg(feature = "std")]
149                {
150                    writer.write_bytes(&data[..*len as usize]);
151                }
152            }
153        }
154    }
155
156    /// Reads an EventPayload from the provided buffer based on the given type ID. Params:
157    /// - event_type: The combined event type byte containing event ID and executor short ID.
158    /// - buffer: The buffer reader to read additional event data from.
159    pub fn from_bytes(
160        event_type: u8,
161        buffer: &mut BufferReader,
162    ) -> Result<EventPayload, ReadTracingError> {
163        let event_id = u5::new(event_type >> 3);
164        let sub_id = u3::new(event_type & 0x07);
165
166        use crate::protocol::raw_writers::event_ids::*;
167        match event_id.as_u8() {
168            // EmbassyTaskReady
169            EMBASSY_TASK_READY => {
170                let task_id = buffer.read_u16()?;
171                Ok(EventPayload::EmbassyTaskReady {
172                    task_id,
173                    executor_id: sub_id,
174                })
175            }
176            // EmbassyTaskExecBegin
177            EMBASSY_TASK_EXEC_BEGIN => {
178                let task_id = buffer.read_u16()?;
179                Ok(EventPayload::EmbassyTaskExecBegin {
180                    task_id,
181                    executor_id: sub_id,
182                })
183            }
184            // EmbassyTaskExecEnd
185            EMBASSY_TASK_EXEC_END => Ok(EventPayload::EmbassyTaskExecEnd {
186                executor_id: sub_id,
187            }),
188            // EmbassyExecutorPollStart
189            EMBASSY_EXECUTOR_POLL_START => Ok(EventPayload::EmbassyExecutorPollStart {
190                executor_id: sub_id,
191            }),
192            // EmbassyExecutorIdle
193            EMBASSY_EXECUTOR_IDLE => Ok(EventPayload::EmbassyExecutorIdle {
194                executor_id: sub_id,
195            }),
196            // MonitorStart
197            MONITOR_START => {
198                let monitor_id = buffer.read_byte()?;
199                Ok(EventPayload::MonitorStart { monitor_id })
200            }
201            // MonitorEnd
202            MONITOR_END => Ok(EventPayload::MonitorEnd),
203            // MonitorValue
204            MONITOR_VALUE => {
205                let value_id = buffer.read_byte()?;
206                let value = MonitorValuePayload::from_bytes(sub_id, buffer)?;
207
208                Ok(EventPayload::MonitorValue { value_id, value })
209            }
210            // TypeDefinition
211            TYPE_DEFINITION => {
212                let typedef_it = buffer.read_byte()?;
213                let def = TypeDefinitionPayload::from_bytes(typedef_it, buffer)?;
214                Ok(EventPayload::TypeDefinition(def))
215            }
216            // DataLossEvent
217            DATA_LOSS_EVENT => {
218                let dropped_events = buffer.read_u32()?;
219                Ok(EventPayload::DataLossEvent { dropped_events })
220            }
221            // DefmtDataEvent
222            DEFMT_DATA_EVENT => {
223                #[cfg(not(feature = "std"))]
224                {
225                    panic!("DefmtDataEvent decoding requires the 'std' feature to be enabled.");
226                }
227                #[cfg(feature = "std")]
228                {
229                    let len = buffer.read_byte()?;
230                    let data = buffer.read_bytes(len as usize)?.to_vec();
231                    Ok(EventPayload::DefmtData { len, data })
232                }
233            }
234            _ => return Err(ReadTracingError::InvalidEventType),
235        }
236    }
237}
238
239#[cfg(test)]
240#[cfg(feature = "std")]
241mod tests {
242    use super::*;
243    use crate::buffer::{BufferReader, BufferWriter};
244
245    #[test]
246    fn test_event_payload_write_and_read() {
247        let events = vec![
248            EventPayload::EmbassyTaskReady {
249                task_id: 42,
250                executor_id: u3::new(5),
251            },
252            EventPayload::EmbassyTaskExecBegin {
253                task_id: 44,
254                executor_id: u3::new(6),
255            },
256            EventPayload::EmbassyTaskExecEnd {
257                executor_id: u3::new(1),
258            },
259            EventPayload::EmbassyExecutorPollStart {
260                executor_id: u3::new(3),
261            },
262            EventPayload::EmbassyExecutorIdle {
263                executor_id: u3::new(4),
264            },
265            EventPayload::MonitorStart { monitor_id: 5 },
266            EventPayload::MonitorEnd,
267            EventPayload::MonitorValue {
268                value_id: 7,
269                value: 456u16.into(),
270            },
271            EventPayload::TypeDefinition(TypeDefinitionPayload::ScopeMonitor {
272                monitor_id: 8,
273                name: "test_scope".to_string(),
274            }),
275            EventPayload::DataLossEvent { dropped_events: 10 },
276            EventPayload::DefmtData {
277                len: 4,
278                data: vec![1, 2, 3, 4],
279            },
280        ];
281
282        for event in events {
283            // Write the event to bytes
284            let mut writer = BufferWriter::new();
285            event.write_bytes(&mut writer);
286            let bytes = writer.as_slice();
287
288            // Read the event back from bytes
289            let mut reader = BufferReader::new(bytes);
290            let read_event =
291                EventPayload::from_bytes(reader.read_byte().unwrap(), &mut reader).unwrap();
292
293            assert_eq!(event, read_event);
294        }
295    }
296}