use crate::{
buffer::{BufferReader, BufferWriter},
protocol::{MonitorValuePayload, TypeDefinitionPayload},
tracing::ReadTracingError,
};
use arbitrary_int::{traits::Integer, u3, u5};
#[derive(Debug, Clone, PartialEq)]
pub enum EventPayload {
EmbassyTaskReady { task_id: u16, executor_id: u3 },
EmbassyTaskExecBegin { task_id: u16, executor_id: u3 },
EmbassyTaskExecEnd { executor_id: u3 },
EmbassyExecutorPollStart { executor_id: u3 },
EmbassyExecutorIdle { executor_id: u3 },
MonitorStart { monitor_id: u8 },
MonitorEnd,
MonitorValue {
value_id: u8,
value: MonitorValuePayload,
},
TypeDefinition(TypeDefinitionPayload),
DataLossEvent { dropped_events: u32 },
DefmtData {
len: u8,
#[cfg(not(feature = "std"))]
data: *const u8,
#[cfg(feature = "std")]
data: Vec<u8>,
},
}
impl EventPayload {
pub const fn event_id(&self) -> u5 {
use crate::protocol::raw_writers::event_ids::*;
let id = match self {
EventPayload::EmbassyTaskReady { .. } => EMBASSY_TASK_READY,
EventPayload::EmbassyTaskExecBegin { .. } => EMBASSY_TASK_EXEC_BEGIN,
EventPayload::EmbassyTaskExecEnd { .. } => EMBASSY_TASK_EXEC_END,
EventPayload::EmbassyExecutorPollStart { .. } => EMBASSY_EXECUTOR_POLL_START,
EventPayload::EmbassyExecutorIdle { .. } => EMBASSY_EXECUTOR_IDLE,
EventPayload::MonitorStart { .. } => MONITOR_START,
EventPayload::MonitorEnd => MONITOR_END,
EventPayload::MonitorValue { .. } => MONITOR_VALUE,
EventPayload::TypeDefinition(_) => TYPE_DEFINITION,
EventPayload::DataLossEvent { .. } => DATA_LOSS_EVENT,
EventPayload::DefmtData { .. } => DEFMT_DATA_EVENT,
};
u5::new(id)
}
pub const fn get_executor_id(&self) -> Option<u3> {
match self {
EventPayload::EmbassyTaskReady { executor_id, .. } => Some(*executor_id),
EventPayload::EmbassyTaskExecBegin { executor_id, .. } => Some(*executor_id),
EventPayload::EmbassyTaskExecEnd { executor_id, .. } => Some(*executor_id),
EventPayload::EmbassyExecutorPollStart { executor_id, .. } => Some(*executor_id),
EventPayload::EmbassyExecutorIdle { executor_id, .. } => Some(*executor_id),
_ => None,
}
}
pub const fn get_monitor_value_type_id(&self) -> Option<u3> {
match self {
EventPayload::MonitorValue { value, .. } => Some(value.type_id()),
_ => None,
}
}
pub const fn get_sub_id(&self) -> Option<u3> {
if let Some(executor_id) = self.get_executor_id() {
return Some(executor_id);
}
if let Some(type_id) = self.get_monitor_value_type_id() {
return Some(type_id);
}
None
}
pub fn write_bytes(&self, writer: &mut BufferWriter) {
let sub_id = self.get_sub_id().unwrap_or(u3::new(0));
let event_type = u8::from(self.event_id()) << 3 | sub_id.as_u8();
writer.write_byte(event_type);
match self {
EventPayload::EmbassyTaskReady {
task_id,
executor_id: _,
} => {
writer.write_bytes(&task_id.to_le_bytes());
}
EventPayload::EmbassyTaskExecBegin {
task_id,
executor_id: _,
} => {
writer.write_bytes(&task_id.to_le_bytes());
}
EventPayload::EmbassyTaskExecEnd { executor_id: _ } => {}
EventPayload::EmbassyExecutorPollStart { executor_id: _ } => {}
EventPayload::EmbassyExecutorIdle { executor_id: _ } => {}
EventPayload::MonitorStart { monitor_id } => {
writer.write_byte(*monitor_id);
}
EventPayload::MonitorEnd => {}
EventPayload::MonitorValue { value_id, value } => {
writer.write_byte(*value_id);
value.write_bytes(writer);
}
EventPayload::TypeDefinition(def) => {
def.write_bytes(writer);
}
EventPayload::DataLossEvent { dropped_events } => {
writer.write_bytes(&dropped_events.to_le_bytes());
}
EventPayload::DefmtData { data, len } => {
writer.write_byte(*len);
#[cfg(not(feature = "std"))]
unsafe {
writer.write_bytes(core::slice::from_raw_parts(*data, *len as usize));
}
#[cfg(feature = "std")]
{
writer.write_bytes(&data[..*len as usize]);
}
}
}
}
pub fn from_bytes(
event_type: u8,
buffer: &mut BufferReader,
) -> Result<EventPayload, ReadTracingError> {
let event_id = u5::new(event_type >> 3);
let sub_id = u3::new(event_type & 0x07);
use crate::protocol::raw_writers::event_ids::*;
match event_id.as_u8() {
EMBASSY_TASK_READY => {
let task_id = buffer.read_u16()?;
Ok(EventPayload::EmbassyTaskReady {
task_id,
executor_id: sub_id,
})
}
EMBASSY_TASK_EXEC_BEGIN => {
let task_id = buffer.read_u16()?;
Ok(EventPayload::EmbassyTaskExecBegin {
task_id,
executor_id: sub_id,
})
}
EMBASSY_TASK_EXEC_END => Ok(EventPayload::EmbassyTaskExecEnd {
executor_id: sub_id,
}),
EMBASSY_EXECUTOR_POLL_START => Ok(EventPayload::EmbassyExecutorPollStart {
executor_id: sub_id,
}),
EMBASSY_EXECUTOR_IDLE => Ok(EventPayload::EmbassyExecutorIdle {
executor_id: sub_id,
}),
MONITOR_START => {
let monitor_id = buffer.read_byte()?;
Ok(EventPayload::MonitorStart { monitor_id })
}
MONITOR_END => Ok(EventPayload::MonitorEnd),
MONITOR_VALUE => {
let value_id = buffer.read_byte()?;
let value = MonitorValuePayload::from_bytes(sub_id, buffer)?;
Ok(EventPayload::MonitorValue { value_id, value })
}
TYPE_DEFINITION => {
let typedef_it = buffer.read_byte()?;
let def = TypeDefinitionPayload::from_bytes(typedef_it, buffer)?;
Ok(EventPayload::TypeDefinition(def))
}
DATA_LOSS_EVENT => {
let dropped_events = buffer.read_u32()?;
Ok(EventPayload::DataLossEvent { dropped_events })
}
DEFMT_DATA_EVENT => {
#[cfg(not(feature = "std"))]
{
panic!("DefmtDataEvent decoding requires the 'std' feature to be enabled.");
}
#[cfg(feature = "std")]
{
let len = buffer.read_byte()?;
let data = buffer.read_bytes(len as usize)?.to_vec();
Ok(EventPayload::DefmtData { len, data })
}
}
_ => return Err(ReadTracingError::InvalidEventType),
}
}
}
#[cfg(test)]
#[cfg(feature = "std")]
mod tests {
use super::*;
use crate::buffer::{BufferReader, BufferWriter};
#[test]
fn test_event_payload_write_and_read() {
let events = vec![
EventPayload::EmbassyTaskReady {
task_id: 42,
executor_id: u3::new(5),
},
EventPayload::EmbassyTaskExecBegin {
task_id: 44,
executor_id: u3::new(6),
},
EventPayload::EmbassyTaskExecEnd {
executor_id: u3::new(1),
},
EventPayload::EmbassyExecutorPollStart {
executor_id: u3::new(3),
},
EventPayload::EmbassyExecutorIdle {
executor_id: u3::new(4),
},
EventPayload::MonitorStart { monitor_id: 5 },
EventPayload::MonitorEnd,
EventPayload::MonitorValue {
value_id: 7,
value: 456u16.into(),
},
EventPayload::TypeDefinition(TypeDefinitionPayload::ScopeMonitor {
monitor_id: 8,
name: "test_scope".to_string(),
}),
EventPayload::DataLossEvent { dropped_events: 10 },
EventPayload::DefmtData {
len: 4,
data: vec![1, 2, 3, 4],
},
];
for event in events {
let mut writer = BufferWriter::new();
event.write_bytes(&mut writer);
let bytes = writer.as_slice();
let mut reader = BufferReader::new(bytes);
let read_event =
EventPayload::from_bytes(reader.read_byte().unwrap(), &mut reader).unwrap();
assert_eq!(event, read_event);
}
}
}