1use num_enum::TryFromPrimitive;
19
20use crate::error::{Error, ErrorCode};
21use crate::tlv::{FromTLV, TLVElement, TLVTag, TLVWrite, TagType, ToTLV, TLV};
22
23use super::{ClusterId, EndptId, EventId, EventNumber, GenericPath, IMStatusCode, NodeId, Status};
24
25#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, FromTLV, ToTLV)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30pub struct EventFilter {
31 pub node: Option<NodeId>,
32 pub event_min: Option<EventNumber>,
33}
34
35#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, FromTLV, ToTLV)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40#[tlvargs(datatype = "list")]
41pub struct EventPath {
42 pub node: Option<NodeId>,
43 pub endpoint: Option<EndptId>,
44 pub cluster: Option<ClusterId>,
45 pub event: Option<EventId>,
46 pub is_urgent: Option<bool>,
47}
48
49impl EventPath {
50 pub const fn from_gp(path: &GenericPath) -> Self {
53 Self {
54 node: None,
55 endpoint: path.endpoint,
56 cluster: path.cluster,
57 event: path.leaf,
58 is_urgent: None,
59 }
60 }
61
62 pub const fn to_gp(&self) -> GenericPath {
64 GenericPath::new(self.endpoint, self.cluster, self.event)
65 }
66
67 pub const fn is_wildcard(&self) -> bool {
69 self.endpoint.is_none() || self.cluster.is_none() || self.event.is_none()
70 }
71}
72
73#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
79#[repr(u8)]
80pub enum EventRespTag {
81 Status = 0,
82 Data = 1,
83}
84
85#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, TryFromPrimitive)]
90#[cfg_attr(feature = "defmt", derive(defmt::Format))]
91#[repr(u8)]
92pub enum EventDataTag {
93 Path = 0,
94 EventNumber = 1,
95 Priority = 2,
96 EpochTimestamp = 3,
97 SystemTimestamp = 4,
98 DeltaEpochTimestamp = 5,
99 DeltaSystemTimestamp = 6,
100 Data = 7,
101}
102
103#[derive(Debug, Clone, PartialEq, Eq, Hash, FromTLV, ToTLV)]
107#[cfg_attr(feature = "defmt", derive(defmt::Format))]
108pub struct EventStatus {
109 pub path: EventPath,
111 pub status: Status,
113}
114
115impl EventStatus {
116 pub const fn new(path: EventPath, status: IMStatusCode, cluster_status: Option<u16>) -> Self {
118 Self {
119 path,
120 status: Status::new(status, cluster_status),
121 }
122 }
123
124 pub const fn from_gp(
131 path: &GenericPath,
132 status: IMStatusCode,
133 cluster_status: Option<u16>,
134 ) -> Self {
135 Self::new(EventPath::from_gp(path), status, cluster_status)
136 }
137}
138
139#[derive(Clone, FromTLV, ToTLV, PartialEq, Debug)]
143#[cfg_attr(feature = "defmt", derive(defmt::Format))]
144#[tlvargs(lifetime = "'a")]
145pub enum EventResp<'a> {
146 Status(EventStatus),
147 Data(EventData<'a>),
148}
149
150#[derive(Debug, Clone, PartialEq)]
154#[cfg_attr(feature = "defmt", derive(defmt::Format))]
155pub struct EventData<'a> {
156 pub path: EventPath,
158 pub event_number: EventNumber,
162 pub priority: EventPriority,
164 pub timestamp: EventDataTimestamp,
166 pub data: TLVElement<'a>,
168}
169
170impl<'a> EventData<'a> {
171 pub const fn new(
173 path: EventPath,
174 event_number: EventNumber,
175 priority: EventPriority,
176 timestamp: EventDataTimestamp,
177 data: TLVElement<'a>,
178 ) -> Self {
179 Self {
180 path,
181 event_number,
182 priority,
183 timestamp,
184 data,
185 }
186 }
187
188 pub fn write_preamble<T: TLVWrite>(&self, tag: &TLVTag, mut tw: T) -> Result<(), Error> {
189 tw.start_struct(tag)?;
190
191 self.path
192 .to_tlv(&TagType::Context(EventDataTag::Path as _), &mut tw)?;
193
194 tw.u64(
195 &TagType::Context(EventDataTag::EventNumber as _),
196 self.event_number,
197 )?;
198
199 tw.u8(
200 &TagType::Context(EventDataTag::Priority as _),
201 self.priority as _,
202 )?;
203
204 match self.timestamp {
205 EventDataTimestamp::EpochTimestamp(ts) => {
206 tw.u64(&TagType::Context(EventDataTag::EpochTimestamp as _), ts)?
207 }
208 EventDataTimestamp::SystemTimestamp(ts) => {
209 tw.u64(&TagType::Context(EventDataTag::SystemTimestamp as _), ts)?
210 }
211 EventDataTimestamp::DeltaEpochTimestamp(ts) => tw.u64(
212 &TagType::Context(EventDataTag::DeltaEpochTimestamp as _),
213 ts,
214 )?,
215 EventDataTimestamp::DeltaSystemTimestamp(ts) => tw.u64(
216 &TagType::Context(EventDataTag::DeltaSystemTimestamp as _),
217 ts,
218 )?,
219 }
220
221 Ok(())
222 }
223}
224
225impl<'a> ToTLV for EventData<'a> {
227 fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, mut tw: W) -> Result<(), Error> {
228 self.write_preamble(tag, &mut tw)?;
229
230 self.data
231 .to_tlv(&TagType::Context(EventDataTag::Data as _), &mut tw)?;
232
233 tw.end_container()
234 }
235
236 fn tlv_iter(&self, tag: crate::tlv::TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
237 let (timestamp_tag, timestamp_val) = match self.timestamp {
238 EventDataTimestamp::EpochTimestamp(ts) => (EventDataTag::EpochTimestamp, ts),
239 EventDataTimestamp::SystemTimestamp(ts) => (EventDataTag::SystemTimestamp, ts),
240 EventDataTimestamp::DeltaEpochTimestamp(ts) => (EventDataTag::DeltaEpochTimestamp, ts),
241 EventDataTimestamp::DeltaSystemTimestamp(ts) => {
242 (EventDataTag::DeltaSystemTimestamp, ts)
243 }
244 };
245
246 let header = [Ok(TLV::structure(tag))].into_iter();
247 let middle_fields = [
248 Ok(TLV::u64(
249 TLVTag::Context(EventDataTag::EventNumber as _),
250 self.event_number,
251 )),
252 Ok(TLV::u8(
253 TLVTag::Context(EventDataTag::Priority as _),
254 self.priority as _,
255 )),
256 Ok(TLV::u64(TLVTag::Context(timestamp_tag as _), timestamp_val)),
257 ]
258 .into_iter();
259 let trailer = [Ok(TLV::end_container())].into_iter();
260
261 header
262 .chain(self.path.tlv_iter(TLVTag::Context(EventDataTag::Path as _)))
263 .chain(middle_fields)
264 .chain(self.data.tlv_iter(TLVTag::Context(EventDataTag::Data as _)))
265 .chain(trailer)
266 }
267}
268
269impl<'a> FromTLV<'a> for EventData<'a> {
270 fn from_tlv(element: &TLVElement<'a>) -> Result<Self, Error> {
271 let mut path = None;
272 let mut event_number = None;
273 let mut priority = None;
274 let mut timestamp = None;
275 let mut data = None;
276
277 for field in element.structure()?.iter() {
278 let el = field?;
279
280 match el.tag()? {
281 TLVTag::Context(tag) => match EventDataTag::try_from(tag)? {
282 EventDataTag::Path => path = Some(EventPath::from_tlv(&el)?),
283 EventDataTag::EventNumber => event_number = Some(el.u64()?),
284 EventDataTag::Priority => priority = Some(EventPriority::from_tlv(&el)?),
285 EventDataTag::EpochTimestamp => {
286 timestamp = Some(EventDataTimestamp::EpochTimestamp(el.u64()?))
287 }
288 EventDataTag::SystemTimestamp => {
289 timestamp = Some(EventDataTimestamp::SystemTimestamp(el.u64()?))
290 }
291 EventDataTag::DeltaEpochTimestamp => {
292 timestamp = Some(EventDataTimestamp::DeltaEpochTimestamp(el.u64()?))
293 }
294 EventDataTag::DeltaSystemTimestamp => {
295 timestamp = Some(EventDataTimestamp::DeltaSystemTimestamp(el.u64()?))
296 }
297 EventDataTag::Data => data = Some(el),
298 },
299 _ => return Err(Error::new(ErrorCode::Invalid)),
300 }
301 }
302
303 Ok(EventData::new(
304 path.ok_or(Error::new(ErrorCode::Invalid))?,
305 event_number.ok_or(Error::new(ErrorCode::Invalid))?,
306 priority.ok_or(Error::new(ErrorCode::Invalid))?,
307 timestamp.ok_or(Error::new(ErrorCode::Invalid))?,
308 data.ok_or(Error::new(ErrorCode::Invalid))?,
309 ))
310 }
311}
312
313#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, FromTLV, ToTLV)]
315#[cfg_attr(feature = "defmt", derive(defmt::Format))]
316#[tlvargs(datatype = "u8")]
317#[repr(u8)]
318pub enum EventPriority {
319 Debug = 0,
320 Info = 1,
321 Critical = 2,
322}
323
324impl EventPriority {
325 pub const fn next(&self) -> Option<Self> {
327 match self {
328 Self::Debug => Some(Self::Info),
329 Self::Info => Some(Self::Critical),
330 Self::Critical => None,
331 }
332 }
333
334 pub const fn prev(&self) -> Option<Self> {
336 match self {
337 Self::Debug => None,
338 Self::Info => Some(Self::Debug),
339 Self::Critical => Some(Self::Info),
340 }
341 }
342}
343
344#[derive(Debug, Clone, PartialEq)]
347#[cfg_attr(feature = "defmt", derive(defmt::Format))]
348pub enum EventDataTimestamp {
349 EpochTimestamp(u64),
351 SystemTimestamp(u64),
353 DeltaEpochTimestamp(u64),
356 DeltaSystemTimestamp(u64),
359}