1#![allow(
5 clippy::all,
6 clippy::pedantic,
7 dead_code,
8 unreachable_pub,
9 unused_imports
10)]
11
12use crate::datatypes::SemanticTagStruct;
13use crate::error::ClusterError;
14use crate::types::Nullable;
15use matter_codec::{ContainerKind, Element, Tag, TlvReader, TlvWriter, Value};
16
17pub const CLUSTER_ID: u32 = 0x0033;
19pub const CLUSTER_REVISION: u16 = 2;
21
22pub mod command_id {
24 pub const TEST_EVENT_TRIGGER: u32 = 0x00;
26 pub const TIME_SNAPSHOT: u32 = 0x01;
28 pub const TIME_SNAPSHOT_RESPONSE: u32 = 0x02;
30 pub const PAYLOAD_TEST_REQUEST: u32 = 0x03;
32 pub const PAYLOAD_TEST_RESPONSE: u32 = 0x04;
34}
35
36pub mod attribute_id {
38 pub const NETWORK_INTERFACES: u32 = 0x0000;
40 pub const REBOOT_COUNT: u32 = 0x0001;
42 pub const UP_TIME: u32 = 0x0002;
44 pub const TOTAL_OPERATIONAL_HOURS: u32 = 0x0003;
46 pub const BOOT_REASON: u32 = 0x0004;
48 pub const ACTIVE_HARDWARE_FAULTS: u32 = 0x0005;
50 pub const ACTIVE_RADIO_FAULTS: u32 = 0x0006;
52 pub const ACTIVE_NETWORK_FAULTS: u32 = 0x0007;
54 pub const TEST_EVENT_TRIGGERS_ENABLED: u32 = 0x0008;
56}
57
58bitflags::bitflags! {
59 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
61 pub struct Feature: u32 {
62 const DMTEST = 1 << 0;
64 }
65}
66
67#[derive(Copy, Clone, Debug, PartialEq, Eq)]
69pub enum BootReasonEnum {
70 Unspecified,
72 PowerOnReboot,
74 BrownOutReset,
76 SoftwareWatchdogReset,
78 HardwareWatchdogReset,
80 SoftwareUpdateCompleted,
82 SoftwareReset,
84 Unknown(u8),
86}
87
88impl BootReasonEnum {
89 #[must_use]
91 pub fn from_raw(v: u8) -> Self {
92 match v {
93 0 => Self::Unspecified,
94 1 => Self::PowerOnReboot,
95 2 => Self::BrownOutReset,
96 3 => Self::SoftwareWatchdogReset,
97 4 => Self::HardwareWatchdogReset,
98 5 => Self::SoftwareUpdateCompleted,
99 6 => Self::SoftwareReset,
100 other => Self::Unknown(other),
101 }
102 }
103 #[must_use]
105 pub fn to_raw(self) -> u8 {
106 match self {
107 Self::Unspecified => 0,
108 Self::PowerOnReboot => 1,
109 Self::BrownOutReset => 2,
110 Self::SoftwareWatchdogReset => 3,
111 Self::HardwareWatchdogReset => 4,
112 Self::SoftwareUpdateCompleted => 5,
113 Self::SoftwareReset => 6,
114 Self::Unknown(v) => v,
115 }
116 }
117}
118
119#[derive(Copy, Clone, Debug, PartialEq, Eq)]
121pub enum HardwareFaultEnum {
122 Unspecified,
124 Radio,
126 Sensor,
128 ResettableOverTemp,
130 NonResettableOverTemp,
132 PowerSource,
134 VisualDisplayFault,
136 AudioOutputFault,
138 UserInterfaceFault,
140 NonVolatileMemoryError,
142 TamperDetected,
144 Unknown(u8),
146}
147
148impl HardwareFaultEnum {
149 #[must_use]
151 pub fn from_raw(v: u8) -> Self {
152 match v {
153 0 => Self::Unspecified,
154 1 => Self::Radio,
155 2 => Self::Sensor,
156 3 => Self::ResettableOverTemp,
157 4 => Self::NonResettableOverTemp,
158 5 => Self::PowerSource,
159 6 => Self::VisualDisplayFault,
160 7 => Self::AudioOutputFault,
161 8 => Self::UserInterfaceFault,
162 9 => Self::NonVolatileMemoryError,
163 10 => Self::TamperDetected,
164 other => Self::Unknown(other),
165 }
166 }
167 #[must_use]
169 pub fn to_raw(self) -> u8 {
170 match self {
171 Self::Unspecified => 0,
172 Self::Radio => 1,
173 Self::Sensor => 2,
174 Self::ResettableOverTemp => 3,
175 Self::NonResettableOverTemp => 4,
176 Self::PowerSource => 5,
177 Self::VisualDisplayFault => 6,
178 Self::AudioOutputFault => 7,
179 Self::UserInterfaceFault => 8,
180 Self::NonVolatileMemoryError => 9,
181 Self::TamperDetected => 10,
182 Self::Unknown(v) => v,
183 }
184 }
185}
186
187#[derive(Copy, Clone, Debug, PartialEq, Eq)]
189pub enum InterfaceTypeEnum {
190 Unspecified,
192 WiFi,
194 Ethernet,
196 Cellular,
198 Thread,
200 Unknown(u8),
202}
203
204impl InterfaceTypeEnum {
205 #[must_use]
207 pub fn from_raw(v: u8) -> Self {
208 match v {
209 0 => Self::Unspecified,
210 1 => Self::WiFi,
211 2 => Self::Ethernet,
212 3 => Self::Cellular,
213 4 => Self::Thread,
214 other => Self::Unknown(other),
215 }
216 }
217 #[must_use]
219 pub fn to_raw(self) -> u8 {
220 match self {
221 Self::Unspecified => 0,
222 Self::WiFi => 1,
223 Self::Ethernet => 2,
224 Self::Cellular => 3,
225 Self::Thread => 4,
226 Self::Unknown(v) => v,
227 }
228 }
229}
230
231#[derive(Copy, Clone, Debug, PartialEq, Eq)]
233pub enum NetworkFaultEnum {
234 Unspecified,
236 HardwareFailure,
238 NetworkJammed,
240 ConnectionFailed,
242 Unknown(u8),
244}
245
246impl NetworkFaultEnum {
247 #[must_use]
249 pub fn from_raw(v: u8) -> Self {
250 match v {
251 0 => Self::Unspecified,
252 1 => Self::HardwareFailure,
253 2 => Self::NetworkJammed,
254 3 => Self::ConnectionFailed,
255 other => Self::Unknown(other),
256 }
257 }
258 #[must_use]
260 pub fn to_raw(self) -> u8 {
261 match self {
262 Self::Unspecified => 0,
263 Self::HardwareFailure => 1,
264 Self::NetworkJammed => 2,
265 Self::ConnectionFailed => 3,
266 Self::Unknown(v) => v,
267 }
268 }
269}
270
271#[derive(Clone, Debug, PartialEq)]
273#[non_exhaustive]
274pub struct NetworkInterface {
275 pub name: String,
277 pub is_operational: bool,
279 pub off_premise_services_reachable_i_pv4: Nullable<bool>,
281 pub off_premise_services_reachable_i_pv6: Nullable<bool>,
283 pub hardware_address: Vec<u8>,
285 pub i_pv4_addresses: Vec<Vec<u8>>,
287 pub i_pv6_addresses: Vec<Vec<u8>>,
289 pub r#type: InterfaceTypeEnum,
291}
292
293#[derive(Copy, Clone, Debug, PartialEq, Eq)]
295pub enum RadioFaultEnum {
296 Unspecified,
298 WiFiFault,
300 CellularFault,
302 ThreadFault,
304 NfcFault,
306 BleFault,
308 EthernetFault,
310 Unknown(u8),
312}
313
314impl RadioFaultEnum {
315 #[must_use]
317 pub fn from_raw(v: u8) -> Self {
318 match v {
319 0 => Self::Unspecified,
320 1 => Self::WiFiFault,
321 2 => Self::CellularFault,
322 3 => Self::ThreadFault,
323 4 => Self::NfcFault,
324 5 => Self::BleFault,
325 6 => Self::EthernetFault,
326 other => Self::Unknown(other),
327 }
328 }
329 #[must_use]
331 pub fn to_raw(self) -> u8 {
332 match self {
333 Self::Unspecified => 0,
334 Self::WiFiFault => 1,
335 Self::CellularFault => 2,
336 Self::ThreadFault => 3,
337 Self::NfcFault => 4,
338 Self::BleFault => 5,
339 Self::EthernetFault => 6,
340 Self::Unknown(v) => v,
341 }
342 }
343}
344
345impl NetworkInterface {
346 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
352 let mut f_name: Option<String> = None;
353 let mut f_is_operational: Option<bool> = None;
354 let mut f_off_premise_services_reachable_i_pv4: Option<Nullable<bool>> = None;
355 let mut f_off_premise_services_reachable_i_pv6: Option<Nullable<bool>> = None;
356 let mut f_hardware_address: Option<Vec<u8>> = None;
357 let mut f_i_pv4_addresses: Option<Vec<Vec<u8>>> = None;
358 let mut f_i_pv6_addresses: Option<Vec<Vec<u8>>> = None;
359 let mut f_type: Option<InterfaceTypeEnum> = None;
360 loop {
361 match r.next()? {
362 Some(Element::ContainerEnd) => break,
363 Some(Element::Scalar {
364 tag: Tag::Context(0),
365 value: Value::Utf8(v),
366 }) => f_name = Some(v),
367 Some(Element::Scalar {
368 tag: Tag::Context(1),
369 value: Value::Bool(v),
370 }) => f_is_operational = Some(v),
371 Some(Element::Scalar {
372 tag: Tag::Context(2),
373 value: Value::Null,
374 }) => f_off_premise_services_reachable_i_pv4 = Some(Nullable::Null),
375 Some(Element::Scalar {
376 tag: Tag::Context(2),
377 value: Value::Bool(v),
378 }) => f_off_premise_services_reachable_i_pv4 = Some(Nullable::Value(v)),
379 Some(Element::Scalar {
380 tag: Tag::Context(3),
381 value: Value::Null,
382 }) => f_off_premise_services_reachable_i_pv6 = Some(Nullable::Null),
383 Some(Element::Scalar {
384 tag: Tag::Context(3),
385 value: Value::Bool(v),
386 }) => f_off_premise_services_reachable_i_pv6 = Some(Nullable::Value(v)),
387 Some(Element::Scalar {
388 tag: Tag::Context(4),
389 value: Value::Bytes(v),
390 }) => f_hardware_address = Some(v),
391 Some(Element::ContainerStart {
392 tag: Tag::Context(5),
393 kind: ContainerKind::Array,
394 }) => {
395 let mut out = Vec::new();
396 loop {
397 match r.next()? {
398 Some(Element::ContainerEnd) => break,
399 Some(Element::Scalar {
400 value: Value::Bytes(v),
401 ..
402 }) => out.push(v),
403 None => {
404 return Err(ClusterError::Tlv(
405 matter_codec::Error::UnclosedContainer,
406 ))
407 }
408 Some(Element::ContainerStart { .. }) => r.skip_container()?,
409 Some(_) => {} }
411 }
412 f_i_pv4_addresses = Some(out);
413 }
414 Some(Element::ContainerStart {
415 tag: Tag::Context(6),
416 kind: ContainerKind::Array,
417 }) => {
418 let mut out = Vec::new();
419 loop {
420 match r.next()? {
421 Some(Element::ContainerEnd) => break,
422 Some(Element::Scalar {
423 value: Value::Bytes(v),
424 ..
425 }) => out.push(v),
426 None => {
427 return Err(ClusterError::Tlv(
428 matter_codec::Error::UnclosedContainer,
429 ))
430 }
431 Some(Element::ContainerStart { .. }) => r.skip_container()?,
432 Some(_) => {} }
434 }
435 f_i_pv6_addresses = Some(out);
436 }
437 Some(Element::Scalar {
438 tag: Tag::Context(7),
439 value: Value::Uint(v),
440 }) => {
441 f_type = Some(InterfaceTypeEnum::from_raw(
442 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Type"))?,
443 ))
444 }
445 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
446 Some(Element::ContainerStart { .. }) => r.skip_container()?,
447 Some(_) => {} }
449 }
450 Ok(Self {
451 name: f_name.ok_or(ClusterError::MissingField("Name"))?,
452 is_operational: f_is_operational.ok_or(ClusterError::MissingField("IsOperational"))?,
453 off_premise_services_reachable_i_pv4: f_off_premise_services_reachable_i_pv4.ok_or(
454 ClusterError::MissingField("OffPremiseServicesReachableIPv4"),
455 )?,
456 off_premise_services_reachable_i_pv6: f_off_premise_services_reachable_i_pv6.ok_or(
457 ClusterError::MissingField("OffPremiseServicesReachableIPv6"),
458 )?,
459 hardware_address: f_hardware_address
460 .ok_or(ClusterError::MissingField("HardwareAddress"))?,
461 i_pv4_addresses: f_i_pv4_addresses
462 .ok_or(ClusterError::MissingField("IPv4Addresses"))?,
463 i_pv6_addresses: f_i_pv6_addresses
464 .ok_or(ClusterError::MissingField("IPv6Addresses"))?,
465 r#type: f_type.ok_or(ClusterError::MissingField("Type"))?,
466 })
467 }
468 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
473 let mut r = TlvReader::new(tlv);
474 match r.next()? {
475 Some(Element::ContainerStart {
476 kind: ContainerKind::Structure,
477 ..
478 }) => {}
479 _ => {
480 return Err(ClusterError::UnexpectedType {
481 context: "NetworkInterface",
482 })
483 }
484 }
485 Self::decode_from(&mut r)
486 }
487}
488
489pub fn decode_network_interfaces(tlv: &[u8]) -> Result<Vec<NetworkInterface>, ClusterError> {
494 let mut r = TlvReader::new(tlv);
495 match r.next()? {
496 Some(Element::ContainerStart {
497 kind: ContainerKind::Array,
498 ..
499 }) => {}
500 _ => {
501 return Err(ClusterError::UnexpectedType {
502 context: "NetworkInterfaces",
503 })
504 }
505 }
506 let r = &mut r;
507 let mut out = Vec::new();
508 loop {
509 match r.next()? {
510 Some(Element::ContainerEnd) => break,
511 Some(Element::ContainerStart {
512 kind: ContainerKind::Structure,
513 ..
514 }) => {
515 out.push(NetworkInterface::decode_from(r)?);
516 }
517 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
518 Some(Element::ContainerStart { .. }) => r.skip_container()?,
519 Some(_) => {} }
521 }
522 Ok(out)
523}
524
525pub fn decode_reboot_count(tlv: &[u8]) -> Result<u16, ClusterError> {
530 let mut r = TlvReader::new(tlv);
531 match r.next()? {
532 Some(Element::Scalar {
533 value: Value::Uint(v),
534 ..
535 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("RebootCount"))?),
536 _ => Err(ClusterError::UnexpectedType {
537 context: "RebootCount",
538 }),
539 }
540}
541
542pub fn decode_up_time(tlv: &[u8]) -> Result<u64, ClusterError> {
547 let mut r = TlvReader::new(tlv);
548 match r.next()? {
549 Some(Element::Scalar {
550 value: Value::Uint(v),
551 ..
552 }) => Ok(u64::try_from(v).map_err(|_| ClusterError::InvalidLength("UpTime"))?),
553 _ => Err(ClusterError::UnexpectedType { context: "UpTime" }),
554 }
555}
556
557pub fn decode_total_operational_hours(tlv: &[u8]) -> Result<u32, ClusterError> {
562 let mut r = TlvReader::new(tlv);
563 match r.next()? {
564 Some(Element::Scalar {
565 value: Value::Uint(v),
566 ..
567 }) => {
568 Ok(u32::try_from(v)
569 .map_err(|_| ClusterError::InvalidLength("TotalOperationalHours"))?)
570 }
571 _ => Err(ClusterError::UnexpectedType {
572 context: "TotalOperationalHours",
573 }),
574 }
575}
576
577pub fn decode_boot_reason(tlv: &[u8]) -> Result<BootReasonEnum, ClusterError> {
582 let mut r = TlvReader::new(tlv);
583 match r.next()? {
584 Some(Element::Scalar {
585 value: Value::Uint(v),
586 ..
587 }) => Ok(BootReasonEnum::from_raw(
588 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("BootReason"))?,
589 )),
590 _ => Err(ClusterError::UnexpectedType {
591 context: "BootReason",
592 }),
593 }
594}
595
596pub fn decode_active_hardware_faults(tlv: &[u8]) -> Result<Vec<HardwareFaultEnum>, ClusterError> {
601 let mut r = TlvReader::new(tlv);
602 match r.next()? {
603 Some(Element::ContainerStart {
604 kind: ContainerKind::Array,
605 ..
606 }) => {}
607 _ => {
608 return Err(ClusterError::UnexpectedType {
609 context: "ActiveHardwareFaults",
610 })
611 }
612 }
613 let r = &mut r;
614 let mut out = Vec::new();
615 loop {
616 match r.next()? {
617 Some(Element::ContainerEnd) => break,
618 Some(Element::Scalar {
619 value: Value::Uint(v),
620 ..
621 }) => out.push(HardwareFaultEnum::from_raw(
622 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ActiveHardwareFaults"))?,
623 )),
624 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
625 Some(Element::ContainerStart { .. }) => r.skip_container()?,
626 Some(_) => {} }
628 }
629 Ok(out)
630}
631
632pub fn decode_active_radio_faults(tlv: &[u8]) -> Result<Vec<RadioFaultEnum>, ClusterError> {
637 let mut r = TlvReader::new(tlv);
638 match r.next()? {
639 Some(Element::ContainerStart {
640 kind: ContainerKind::Array,
641 ..
642 }) => {}
643 _ => {
644 return Err(ClusterError::UnexpectedType {
645 context: "ActiveRadioFaults",
646 })
647 }
648 }
649 let r = &mut r;
650 let mut out = Vec::new();
651 loop {
652 match r.next()? {
653 Some(Element::ContainerEnd) => break,
654 Some(Element::Scalar {
655 value: Value::Uint(v),
656 ..
657 }) => out.push(RadioFaultEnum::from_raw(
658 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ActiveRadioFaults"))?,
659 )),
660 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
661 Some(Element::ContainerStart { .. }) => r.skip_container()?,
662 Some(_) => {} }
664 }
665 Ok(out)
666}
667
668pub fn decode_active_network_faults(tlv: &[u8]) -> Result<Vec<NetworkFaultEnum>, ClusterError> {
673 let mut r = TlvReader::new(tlv);
674 match r.next()? {
675 Some(Element::ContainerStart {
676 kind: ContainerKind::Array,
677 ..
678 }) => {}
679 _ => {
680 return Err(ClusterError::UnexpectedType {
681 context: "ActiveNetworkFaults",
682 })
683 }
684 }
685 let r = &mut r;
686 let mut out = Vec::new();
687 loop {
688 match r.next()? {
689 Some(Element::ContainerEnd) => break,
690 Some(Element::Scalar {
691 value: Value::Uint(v),
692 ..
693 }) => out.push(NetworkFaultEnum::from_raw(
694 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ActiveNetworkFaults"))?,
695 )),
696 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
697 Some(Element::ContainerStart { .. }) => r.skip_container()?,
698 Some(_) => {} }
700 }
701 Ok(out)
702}
703
704pub fn decode_test_event_triggers_enabled(tlv: &[u8]) -> Result<bool, ClusterError> {
709 let mut r = TlvReader::new(tlv);
710 match r.next()? {
711 Some(Element::Scalar {
712 value: Value::Bool(v),
713 ..
714 }) => Ok(v),
715 _ => Err(ClusterError::UnexpectedType {
716 context: "TestEventTriggersEnabled",
717 }),
718 }
719}
720
721#[must_use]
723#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_test_event_trigger(enable_key: &Vec<u8>, event_trigger: u64) -> Vec<u8> {
725 let mut buf = Vec::new();
726 let mut w = TlvWriter::new(&mut buf);
727 w.start_structure(Tag::Anonymous)
728 .expect("infallible: vec writer");
729 w.put_bytes(Tag::Context(0), &enable_key)
730 .expect("infallible: vec writer");
731 w.put_uint(Tag::Context(1), u64::from(event_trigger))
732 .expect("infallible: vec writer");
733 w.end_container().expect("infallible: vec writer");
734 buf
735}
736
737#[must_use]
739#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_time_snapshot() -> Vec<u8> {
741 let mut buf = Vec::new();
742 let mut w = TlvWriter::new(&mut buf);
743 w.start_structure(Tag::Anonymous)
744 .expect("infallible: vec writer");
745 w.end_container().expect("infallible: vec writer");
746 buf
747}
748
749#[derive(Clone, Debug, PartialEq)]
751#[non_exhaustive]
752pub struct TimeSnapshotResponse {
753 pub system_time_ms: u64,
755 pub posix_time_ms: Nullable<u64>,
757}
758
759impl TimeSnapshotResponse {
760 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
766 let mut f_system_time_ms: Option<u64> = None;
767 let mut f_posix_time_ms: Option<Nullable<u64>> = None;
768 loop {
769 match r.next()? {
770 Some(Element::ContainerEnd) => break,
771 Some(Element::Scalar {
772 tag: Tag::Context(0),
773 value: Value::Uint(v),
774 }) => {
775 f_system_time_ms = Some(
776 u64::try_from(v)
777 .map_err(|_| ClusterError::InvalidLength("SystemTimeMs"))?,
778 )
779 }
780 Some(Element::Scalar {
781 tag: Tag::Context(1),
782 value: Value::Null,
783 }) => f_posix_time_ms = Some(Nullable::Null),
784 Some(Element::Scalar {
785 tag: Tag::Context(1),
786 value: Value::Uint(v),
787 }) => {
788 f_posix_time_ms = Some(Nullable::Value(
789 u64::try_from(v).map_err(|_| ClusterError::InvalidLength("PosixTimeMs"))?,
790 ))
791 }
792 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
793 Some(Element::ContainerStart { .. }) => r.skip_container()?,
794 Some(_) => {} }
796 }
797 Ok(Self {
798 system_time_ms: f_system_time_ms.ok_or(ClusterError::MissingField("SystemTimeMs"))?,
799 posix_time_ms: f_posix_time_ms.ok_or(ClusterError::MissingField("PosixTimeMs"))?,
800 })
801 }
802 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
807 let mut r = TlvReader::new(tlv);
808 match r.next()? {
809 Some(Element::ContainerStart {
810 kind: ContainerKind::Structure,
811 ..
812 }) => {}
813 _ => {
814 return Err(ClusterError::UnexpectedType {
815 context: "TimeSnapshotResponse",
816 })
817 }
818 }
819 Self::decode_from(&mut r)
820 }
821}
822
823#[must_use]
825#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_payload_test_request(enable_key: &Vec<u8>, value: u8, count: u16) -> Vec<u8> {
827 let mut buf = Vec::new();
828 let mut w = TlvWriter::new(&mut buf);
829 w.start_structure(Tag::Anonymous)
830 .expect("infallible: vec writer");
831 w.put_bytes(Tag::Context(0), &enable_key)
832 .expect("infallible: vec writer");
833 w.put_uint(Tag::Context(1), u64::from(value))
834 .expect("infallible: vec writer");
835 w.put_uint(Tag::Context(2), u64::from(count))
836 .expect("infallible: vec writer");
837 w.end_container().expect("infallible: vec writer");
838 buf
839}
840
841#[derive(Clone, Debug, PartialEq)]
843#[non_exhaustive]
844pub struct PayloadTestResponse {
845 pub payload: Vec<u8>,
847}
848
849impl PayloadTestResponse {
850 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
856 let mut f_payload: Option<Vec<u8>> = None;
857 loop {
858 match r.next()? {
859 Some(Element::ContainerEnd) => break,
860 Some(Element::Scalar {
861 tag: Tag::Context(0),
862 value: Value::Bytes(v),
863 }) => f_payload = Some(v),
864 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
865 Some(Element::ContainerStart { .. }) => r.skip_container()?,
866 Some(_) => {} }
868 }
869 Ok(Self {
870 payload: f_payload.ok_or(ClusterError::MissingField("Payload"))?,
871 })
872 }
873 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
878 let mut r = TlvReader::new(tlv);
879 match r.next()? {
880 Some(Element::ContainerStart {
881 kind: ContainerKind::Structure,
882 ..
883 }) => {}
884 _ => {
885 return Err(ClusterError::UnexpectedType {
886 context: "PayloadTestResponse",
887 })
888 }
889 }
890 Self::decode_from(&mut r)
891 }
892}