1use core::fmt::Debug;
19
20use embassy_time::Instant;
21
22use crate::acl::Accessor;
23use crate::dm::{ClusterId, EndptId, EventId, Node};
24use crate::error::{Error, ErrorCode};
25use crate::im::{
26 EventData, EventDataTag, EventDataTimestamp, EventFilter, EventNumber, EventPath,
27 EventPriority, EventResp, EventRespTag,
28};
29use crate::persist::{KvBlobStore, KvBlobStoreAccess, Persist, EVENT_EPOCH_KEY};
30use crate::tlv::{
31 FromTLV, TLVArray, TLVBuilderParent, TLVElement, TLVSequence, TLVSequenceIter, TLVTag,
32 TLVWrite, TagType, ToTLV,
33};
34use crate::utils::cell::RefCell;
35use crate::utils::init::{init, Init};
36use crate::utils::storage::WriteBuf;
37use crate::utils::sync::blocking::Mutex;
38
39pub const DEFAULT_MAX_EVENTS_BUF_SIZE: usize = 256;
42
43pub const NO_EVENTS_BUF_SIZE: usize = 0;
45
46pub type NoEvents = Events<NO_EVENTS_BUF_SIZE>;
48
49const EVENT_NUMBER_EPOCH_SIZE: EventNumber = 10000;
51
52pub struct Events<const N: usize = DEFAULT_MAX_EVENTS_BUF_SIZE> {
64 inner: Mutex<RefCell<EventsInner<N>>>,
65}
66
67impl<const N: usize> Events<N> {
68 #[inline(always)]
69 pub const fn new() -> Self {
70 Self {
71 inner: Mutex::new(RefCell::new(EventsInner::new())),
72 }
73 }
74
75 pub fn init() -> impl Init<Self> {
76 init!(Self {
77 inner <- Mutex::init(RefCell::init(EventsInner::init())),
78 })
79 }
80
81 pub fn reset(&mut self) {
82 self.inner.get_mut().borrow_mut().reset();
83 }
84
85 pub(crate) fn load_persist(
90 &self,
91 kv: &mut dyn KvBlobStore,
92 buf: &mut [u8],
93 ) -> Result<(), Error> {
94 self.inner
95 .lock(|state| state.borrow_mut().load_persist(kv, buf))
96 }
97
98 pub(crate) fn reset_persist(
103 &self,
104 kv: &mut dyn KvBlobStore,
105 buf: &mut [u8],
106 ) -> Result<(), Error> {
107 self.inner
108 .lock(|state| state.borrow_mut().reset_persist(kv, buf))
109 }
110
111 pub(crate) fn fetch<F, R>(&self, f: F) -> R
112 where
113 F: FnOnce(EventsIter<'_, N>) -> R,
114 {
115 self.inner.lock(|state| {
116 let state = state.borrow();
117
118 f(state.iter())
119 })
120 }
121
122 pub(crate) fn watermark(&self) -> EventNumber {
123 self.inner
124 .lock(|state| state.borrow().next_event_number.wrapping_sub(1))
125 }
126
127 pub fn push<S, F>(
142 &self,
143 endpoint_id: EndptId,
144 cluster_id: ClusterId,
145 event_id: EventId,
146 priority: EventPriority,
147 kv: S,
148 f: F,
149 ) -> Result<EventNumber, Error>
150 where
151 S: KvBlobStoreAccess,
152 F: FnOnce(EventTLVWrite<'_>) -> Result<(), Error>,
153 {
154 let mut persist = Persist::new(kv);
155
156 let event_number = self.inner.lock(|state| {
157 let mut state = state.borrow_mut();
158
159 let event_number = state.next_event_number(&mut persist)?;
160
161 let timestamp = EventDataTimestamp::SystemTimestamp(Instant::now().as_millis());
167
168 state.push(
169 endpoint_id,
170 cluster_id,
171 event_id,
172 event_number,
173 priority,
174 timestamp,
175 f,
176 )?;
177
178 Ok::<_, Error>(event_number)
179 })?;
180
181 persist.run()?;
182
183 Ok(event_number)
184 }
185}
186
187impl<const N: usize> Default for Events<N> {
188 fn default() -> Self {
189 Self::new()
190 }
191}
192
193#[derive(Debug)]
210#[cfg_attr(feature = "defmt", derive(defmt::Format))]
211pub(crate) struct EventsInner<const N: usize> {
212 buf_debug: EventsBuf<N>,
214 buf_info: EventsBuf<N>,
215 buf_critical: EventsBuf<N>,
216 next_event_number: EventNumber,
219}
220
221impl<const N: usize> EventsInner<N> {
222 const fn new() -> Self {
223 Self {
224 buf_debug: EventsBuf::new(),
225 buf_info: EventsBuf::new(),
226 buf_critical: EventsBuf::new(),
227 next_event_number: 1,
228 }
229 }
230
231 fn init() -> impl Init<Self> {
232 init!(Self {
233 buf_debug <- EventsBuf::init(),
234 buf_info <- EventsBuf::init(),
235 buf_critical <- EventsBuf::init(),
236 next_event_number: 1,
237 })
238 }
239
240 fn reset(&mut self) {
241 self.buf_debug.reset();
242 self.buf_info.reset();
243 self.buf_critical.reset();
244 self.next_event_number = 1;
245 }
246
247 pub(crate) fn reset_persist(
249 &mut self,
250 kv: &mut dyn KvBlobStore,
251 buf: &mut [u8],
252 ) -> Result<(), Error> {
253 self.reset();
254
255 kv.remove(EVENT_EPOCH_KEY, buf)?;
256
257 info!("Removed events counter from storage");
258
259 Ok(())
260 }
261
262 pub(crate) fn load_persist(
264 &mut self,
265 kv: &mut dyn KvBlobStore,
266 buf: &mut [u8],
267 ) -> Result<(), Error> {
268 self.reset();
269
270 if let Some(data) = kv.load(EVENT_EPOCH_KEY, buf)? {
271 self.load(data)?;
272
273 info!("Loaded events counter from storage");
274 }
275
276 Ok(())
277 }
278
279 fn load(&mut self, data: &[u8]) -> Result<(), Error> {
281 self.next_event_number = TLVElement::new(data).u64()?;
282
283 Ok(())
284 }
285
286 #[allow(clippy::too_many_arguments)]
287 fn push<F>(
288 &mut self,
289 endpoint_id: EndptId,
290 cluster_id: ClusterId,
291 event_id: EventId,
292 event_number: EventNumber,
293 priority: EventPriority,
294 timestamp: EventDataTimestamp,
295 f: F,
296 ) -> Result<(), Error>
297 where
298 F: FnOnce(EventTLVWrite<'_>) -> Result<(), Error>,
299 {
300 let mut event_writer = EventWriter::new(self);
301
302 let pos = event_writer.get_tail();
303
304 let result = (|| {
305 EventData {
306 path: EventPath {
307 endpoint: Some(endpoint_id),
308 cluster: Some(cluster_id),
309 event: Some(event_id),
310 ..Default::default()
311 },
312 event_number,
313 priority,
314 timestamp,
315 data: TLVElement::new(&[]),
316 }
317 .write_preamble(&EVENT_TAG, event_writer.tw())?;
318
319 f(event_writer.tw())?;
320
321 event_writer.tw().end_container()
322 })();
323
324 if result.is_err() {
325 event_writer.rewind_to(pos);
326 }
327
328 result
329 }
330
331 fn next_event_number<S>(&mut self, persist: &mut Persist<S>) -> Result<EventNumber, Error>
332 where
333 S: KvBlobStoreAccess,
334 {
335 let event_number = self.next_event_number;
336
337 if event_number == 1 || event_number.is_multiple_of(EVENT_NUMBER_EPOCH_SIZE) {
338 persist.store_tlv(
341 EVENT_EPOCH_KEY,
342 if event_number == 1 {
343 EVENT_NUMBER_EPOCH_SIZE
344 } else {
345 event_number.wrapping_add(EVENT_NUMBER_EPOCH_SIZE).max(1)
346 },
347 )?;
348 }
349
350 self.next_event_number = event_number.wrapping_add(1).max(1);
351
352 Ok(event_number)
353 }
354
355 fn iter(&self) -> EventsIter<'_, N> {
356 EventsIter {
357 events: self,
358 buf_ref: EventPriority::Critical,
359 buf_iter: self.buf_critical.iter(),
360 }
361 }
362
363 fn buf(&self, priority: EventPriority) -> &EventsBuf<N> {
365 match priority {
366 EventPriority::Debug => &self.buf_debug,
367 EventPriority::Info => &self.buf_info,
368 EventPriority::Critical => &self.buf_critical,
369 }
370 }
371
372 fn buf_mut(&mut self, priority: EventPriority) -> &mut EventsBuf<N> {
374 match priority {
375 EventPriority::Debug => &mut self.buf_debug,
376 EventPriority::Info => &mut self.buf_info,
377 EventPriority::Critical => &mut self.buf_critical,
378 }
379 }
380
381 fn buf_and_next_mut(
383 &mut self,
384 priority: EventPriority,
385 ) -> (&EventsBuf<N>, Option<&mut EventsBuf<N>>) {
386 match priority {
387 EventPriority::Debug => (&self.buf_debug, Some(&mut self.buf_info)),
388 EventPriority::Info => (&self.buf_info, Some(&mut self.buf_critical)),
389 EventPriority::Critical => (&self.buf_critical, None),
390 }
391 }
392}
393
394pub struct EventsIter<'a, const N: usize> {
396 events: &'a EventsInner<N>,
397 buf_ref: EventPriority,
398 buf_iter: TLVSequenceIter<'a>,
399}
400
401impl<'a, const N: usize> Iterator for EventsIter<'a, N> {
402 type Item = EventData<'a>;
403
404 fn next(&mut self) -> Option<Self::Item> {
405 if let Some(res) = self.buf_iter.next() {
406 let event = unwrap!(
407 res,
408 "Should not have iter errors as we only put well-formed TLVs in the buffer"
409 );
410 let event = unwrap!(
411 EventData::from_tlv(&event),
412 "Should not have parsing errors as we only put well-formed TLVs in the buffer"
413 );
414
415 return Some(event);
416 }
417
418 if let Some(next_buf_ref) = self.buf_ref.prev() {
419 self.buf_iter = self.events.buf(next_buf_ref).iter();
420 self.buf_ref = next_buf_ref;
421
422 self.next()
423 } else {
424 None
425 }
426 }
427}
428
429struct EventWriter<'a, const N: usize> {
431 events: &'a mut EventsInner<N>,
432 bytes_written: usize,
433}
434
435impl<'a, const N: usize> EventWriter<'a, N> {
436 const OPER_BUF: EventPriority = EventPriority::Debug;
439
440 #[inline(always)]
442 const fn new(events: &'a mut EventsInner<N>) -> Self {
443 Self {
444 events,
445 bytes_written: 0,
446 }
447 }
448
449 #[inline(always)]
452 fn tw(&mut self) -> EventTLVWrite<'_> {
453 EventTLVWrite(self)
454 }
455
456 fn write(&mut self, byte: u8) -> Result<(), Error> {
458 if N == 0 {
459 return Ok(());
461 }
462
463 if self.bytes_written == N {
464 return Err(Error::new(ErrorCode::ResourceExhausted));
466 }
467
468 while self.events.buf_mut(Self::OPER_BUF).append(byte).is_err() {
469 self.evict(Self::OPER_BUF);
473 }
474
475 self.bytes_written += 1;
476
477 Ok(())
478 }
479
480 fn rewind_to(&mut self, bytes_written: usize) {
482 assert!(self.bytes_written >= bytes_written);
483
484 self.events
485 .buf_mut(Self::OPER_BUF)
486 .rewind_by(self.bytes_written - bytes_written);
487 self.bytes_written = bytes_written;
488 }
489
490 fn evict(&mut self, buf_ref: EventPriority) {
493 let event_len = self.events.buf(buf_ref).first_event_len();
494
495 if let Some(next_buf_ref) = buf_ref.next() {
496 let event_prio = self.events.buf(buf_ref).first_event_prio();
497
498 if next_buf_ref as u8 <= event_prio {
499 self.promote(buf_ref, next_buf_ref, event_len);
501 }
502 }
503
504 self.events.buf_mut(buf_ref).evict_first_event();
506 }
507
508 fn promote(&mut self, src_buf: EventPriority, dst_buf: EventPriority, event_len: usize) {
512 while self.events.buf(dst_buf).capacity() < event_len {
514 self.evict(dst_buf);
515 }
516
517 let (src, dst) = self.events.buf_and_next_mut(src_buf);
518
519 let dst = unwrap!(
520 dst,
521 "Dst buffer should always exist as this is checked in evict()"
522 );
523
524 unwrap!(
525 dst.append_slice(src.slice(event_len)),
526 "Should not overflow as eviction should have cleared space"
527 );
528 }
529}
530
531trait DynEventWriter {
534 fn write(&mut self, byte: u8) -> Result<(), Error>;
535
536 fn get_tail(&self) -> usize;
537
538 fn rewind_to(&mut self, pos: usize);
539}
540
541impl<'a, const N: usize> DynEventWriter for EventWriter<'a, N> {
542 fn write(&mut self, byte: u8) -> Result<(), Error> {
543 EventWriter::write(self, byte)
544 }
545
546 fn get_tail(&self) -> usize {
547 self.bytes_written
548 }
549
550 fn rewind_to(&mut self, pos: usize) {
551 EventWriter::rewind_to(self, pos)
552 }
553}
554
555pub struct EventTLVWrite<'a>(&'a mut dyn DynEventWriter);
558
559impl core::fmt::Debug for EventTLVWrite<'_> {
560 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
561 f.debug_tuple("EventTLVWrite").finish()
562 }
563}
564
565#[cfg(feature = "defmt")]
566impl defmt::Format for EventTLVWrite<'_> {
567 fn format(&self, fmt: defmt::Formatter) {
568 defmt::write!(fmt, "EventTLVWrite")
569 }
570}
571
572impl TLVWrite for EventTLVWrite<'_> {
573 type Position = usize;
574
575 fn write(&mut self, byte: u8) -> Result<(), Error> {
576 self.0.write(byte)
577 }
578
579 fn get_tail(&self) -> Self::Position {
580 self.0.get_tail()
581 }
582
583 fn rewind_to(&mut self, pos: Self::Position) {
584 self.0.rewind_to(pos)
585 }
586}
587
588impl TLVBuilderParent for EventTLVWrite<'_> {
589 type Write = Self;
590
591 fn writer(&mut self) -> &mut Self::Write {
592 self
593 }
594}
595
596const EVENT_TAG: TLVTag = TLVTag::Context(EventRespTag::Data as _);
597
598pub const EVENT_DATA_TAG: TLVTag = TLVTag::Context(EventDataTag::Data as _);
600
601#[derive(Debug, Clone)]
614#[cfg_attr(feature = "defmt", derive(defmt::Format))]
615struct EventsBuf<const N: usize> {
616 data: [u8; N],
617 head: usize,
618}
619
620impl<const N: usize> EventsBuf<N> {
621 const fn new() -> Self {
622 Self {
623 data: [0; N],
624 head: 0,
625 }
626 }
627
628 fn init() -> impl Init<Self> {
629 init!(Self {
630 data <- crate::utils::init::zeroed(),
631 head: 0,
632 })
633 }
634
635 fn reset(&mut self) {
636 self.head = 0;
637 }
638
639 fn rewind_by(&mut self, bytes_written: usize) {
640 assert!(self.head >= bytes_written);
641
642 self.head -= bytes_written;
643 }
644
645 fn slice(&self, len: usize) -> &[u8] {
646 assert!(self.head >= len);
647 &self.data[..len]
648 }
649
650 fn append(&mut self, byte: u8) -> Result<(), OverflowError> {
651 if self.capacity() == 0 {
652 return Err(OverflowError);
653 }
654
655 self.data[self.head] = byte;
656 self.head += 1;
657 Ok(())
658 }
659
660 fn append_slice(&mut self, data: &[u8]) -> Result<(), OverflowError> {
661 if self.capacity() < data.len() {
662 return Err(OverflowError);
663 }
664
665 self.data[self.head..self.head + data.len()].copy_from_slice(data);
666 self.head += data.len();
667
668 Ok(())
669 }
670
671 fn capacity(&self) -> usize {
672 self.data.len() - self.head
673 }
674
675 fn first_event_len(&self) -> usize {
679 assert!(self.head > 0);
680 unwrap!(TLVSequence(&self.data[..self.head]).container_len())
681 }
682
683 fn first_event_prio(&self) -> u8 {
687 unwrap!(unwrap!(
688 unwrap!(TLVElement::new(&self.data[..self.head]).structure())
689 .find_ctx(EventDataTag::Priority as _)
690 )
691 .u8())
692 }
693
694 fn evict_first_event(&mut self) {
695 let tlv_len = self.first_event_len();
696
697 self.data.copy_within(tlv_len..self.head, 0);
698 self.head -= tlv_len;
699 }
700
701 fn iter(&self) -> TLVSequenceIter<'_> {
702 TLVSequence(&self.data[0..self.head]).iter()
703 }
704}
705
706#[derive(Debug)]
707#[cfg_attr(feature = "defmt", derive(defmt::Format))]
708struct OverflowError;
709
710pub struct EventReader {
711 max_seen_event_number: u64,
712 next_max_seen_event_number: u64,
713 fabric_filtered: bool,
718}
719
720impl EventReader {
721 pub const fn new(
722 max_seen_event_number: u64,
723 next_max_seen_event_number: u64,
724 fabric_filtered: bool,
725 ) -> Self {
726 Self {
727 max_seen_event_number,
728 next_max_seen_event_number,
729 fabric_filtered,
730 }
731 }
732
733 pub fn process_read(
734 &mut self,
735 event: EventData<'_>,
736 paths: &TLVArray<'_, EventPath>,
737 event_filters: &Option<TLVArray<'_, EventFilter>>,
738 node: &Node<'_>,
739 accessor: &Accessor<'_>,
740 tw: &mut WriteBuf<'_>,
741 ) -> Result<bool, Error> {
742 let event_number = event.event_number;
743 if !(event_number > self.max_seen_event_number
744 && event_number <= self.next_max_seen_event_number)
745 {
746 return Ok(false);
748 }
749
750 let tail = tw.get_tail();
751
752 let result = self.do_process_read(event, paths, event_filters, node, accessor, &mut *tw);
753
754 if result.is_err() {
755 tw.rewind_to(tail);
759 } else {
760 self.max_seen_event_number = event_number;
765 }
766
767 result
768 }
769
770 fn do_process_read(
771 &mut self,
772 event: EventData<'_>,
773 paths: &TLVArray<'_, EventPath>,
774 event_filters: &Option<TLVArray<'_, EventFilter>>,
775 node: &Node<'_>,
776 accessor: &Accessor<'_>,
777 tw: &mut WriteBuf<'_>,
778 ) -> Result<bool, Error> {
779 if self.fabric_filtered && !Self::matches_fabric(&event, accessor) {
780 return Ok(false);
781 }
782
783 if Self::matches_paths(&event, paths, node, accessor)?
784 && Self::matches_filters(&event, event_filters)?
785 && Self::matches_access(&event, node, accessor)?
786 {
787 EventResp::Data(event).to_tlv(&TagType::Anonymous, &mut *tw)?;
788
789 Ok(true)
790 } else {
791 Ok(false)
792 }
793 }
794
795 fn matches_fabric(event: &EventData<'_>, accessor: &Accessor<'_>) -> bool {
804 let Ok(payload) = event.data.structure() else {
806 return true;
808 };
809
810 let Ok(elem) = payload.find_ctx(crate::im::encoding::FABRIC_INDEX_TAG) else {
811 return true;
813 };
814
815 match elem.non_empty().and_then(|e| e.u8().ok()) {
816 Some(fab_idx) => fab_idx == accessor.fab_idx,
817 None => true,
819 }
820 }
821
822 fn matches_paths(
823 event: &EventData<'_>,
824 paths: &TLVArray<'_, EventPath>,
825 node: &Node<'_>,
826 accessor: &Accessor<'_>,
827 ) -> Result<bool, Error> {
828 for path in paths {
829 let path = path?;
830
831 if Self::matches_path(event, path, node, accessor) {
832 return Ok(true);
833 }
834 }
835
836 Ok(false)
837 }
838
839 fn matches_path(
840 event: &EventData<'_>,
841 path: EventPath,
842 node: &Node<'_>,
843 accessor: &Accessor<'_>,
844 ) -> bool {
845 if node.validate_event_path(&path, accessor).is_err() {
846 return false;
847 }
848
849 let epath = &event.path;
850
851 epath
852 .node
853 .is_none_or(|node| path.node.is_none_or(|expected_node| expected_node == node))
854 && epath.endpoint.is_none_or(|endpoint| {
855 path.endpoint
856 .is_none_or(|expected_endpoint| expected_endpoint == endpoint)
857 })
858 && epath.cluster.is_none_or(|cluster| {
859 path.cluster
860 .is_none_or(|expected_cluster| expected_cluster == cluster)
861 })
862 && epath.event.is_none_or(|event| {
863 path.event
864 .is_none_or(|expected_event| expected_event == event)
865 })
866 }
867
868 fn matches_filters(
869 event: &EventData<'_>,
870 event_filters: &Option<TLVArray<'_, EventFilter>>,
871 ) -> Result<bool, Error> {
872 if let Some(filters) = &event_filters {
873 for filter in filters {
876 if let Some(event_min) = filter?.event_min {
877 if event.event_number < event_min {
878 return Ok(false);
879 }
880 }
881 }
882 }
883
884 Ok(true)
885 }
886
887 fn matches_access(
888 event: &EventData<'_>,
889 node: &Node<'_>,
890 accessor: &Accessor<'_>,
891 ) -> Result<bool, Error> {
892 Ok(node.validate_event_path(&event.path, accessor).is_ok())
893 }
894}
895
896#[cfg(test)]
897mod tests {
898 use crate::tlv::ToTLV;
899
900 use super::*;
901
902 #[test]
903 fn one_entry() {
904 let crit1 = TestEvent::new(1, EventPriority::Critical);
905 let mut q: EventsInner<32> = EventsInner::new();
906
907 crit1.push_into(&mut q).unwrap();
908
909 assert_eq!(TestEvent::vec_from(&q.buf_debug).unwrap(), &[crit1]);
910 }
911
912 #[test]
913 fn critical_is_promoted() {
914 let crit1 = TestEvent::new(1, EventPriority::Critical);
915 let crit2 = TestEvent::new(2, EventPriority::Info);
916 let crit3 = TestEvent::new(3, EventPriority::Info);
917 let mut q: EventsInner<32> = EventsInner::new();
918
919 crit1.push_into(&mut q).unwrap();
920 crit2.push_into(&mut q).unwrap();
921 crit3.push_into(&mut q).unwrap();
922
923 assert_eq!(TestEvent::vec_from(&q.buf_debug).unwrap(), &[crit3]);
924 assert_eq!(TestEvent::vec_from(&q.buf_info).unwrap(), &[crit2]);
925 assert_eq!(TestEvent::vec_from(&q.buf_critical).unwrap(), &[crit1]);
926 }
927
928 #[test]
929 fn debug_is_dropped() {
930 let crit1 = TestEvent::new(1, EventPriority::Critical);
931 let dbg2 = TestEvent::new(2, EventPriority::Debug);
932 let crit3: TestEvent = TestEvent::new(3, EventPriority::Critical);
933 let mut q: EventsInner<32> = EventsInner::new();
934
935 crit1.push_into(&mut q).unwrap();
936 dbg2.push_into(&mut q).unwrap();
937 crit3.push_into(&mut q).unwrap();
938
939 assert_eq!(TestEvent::vec_from(&q.buf_debug).unwrap(), &[crit3]);
941 assert_eq!(TestEvent::vec_from(&q.buf_info).unwrap(), &[crit1]);
944 assert_eq!(TestEvent::vec_from(&q.buf_critical).unwrap(), &[]);
946 }
947
948 #[test]
949 fn event_larger_than_buffer() {
950 let crit1 = TestEvent::new(1, EventPriority::Critical);
951 let mut q: EventsInner<8> = EventsInner::new();
952
953 assert_eq!(
954 crit1.push_into(&mut q).expect_err("").code(),
955 ErrorCode::ResourceExhausted
956 );
957 }
958
959 #[derive(PartialEq, Clone, Debug)]
962 struct TestEvent {
963 endpoint: EndptId,
964 cluster: ClusterId,
965 event: EventId,
966 event_number: EventNumber,
967 priority: EventPriority,
968 timestamp: EventDataTimestamp,
969 data: u64,
970 }
971
972 impl TestEvent {
973 const fn new(event_number: EventNumber, priority: EventPriority) -> Self {
974 Self {
975 endpoint: 42,
976 cluster: 1,
977 event: 0xB33F,
978 event_number,
979 priority,
980 timestamp: EventDataTimestamp::EpochTimestamp(10_000 + event_number),
981 data: 1337,
982 }
983 }
984
985 fn vec_from<const N: usize>(
986 buf: &EventsBuf<N>,
987 ) -> Result<heapless::Vec<TestEvent, N>, Error> {
988 let mut out = heapless::Vec::new();
989 for tr in buf.iter() {
990 let e = EventData::from_tlv(&tr?)?;
991 out.push(TestEvent {
992 endpoint: e.path.endpoint.unwrap(),
993 cluster: e.path.cluster.unwrap(),
994 event: e.path.event.unwrap(),
995 event_number: e.event_number,
996 priority: e.priority,
997 timestamp: e.timestamp,
998 data: e.data.u64()?,
999 })
1000 .unwrap();
1001 }
1002
1003 Ok(out)
1004 }
1005
1006 fn push_into<const N: usize>(&self, q: &mut EventsInner<N>) -> Result<(), Error> {
1007 q.push(
1008 self.endpoint,
1009 self.cluster,
1010 self.event,
1011 self.event_number,
1012 self.priority,
1013 self.timestamp.clone(),
1014 |tw| self.data.to_tlv(&EVENT_DATA_TAG, tw),
1015 )
1016 }
1017 }
1018}