Skip to main content

matter_clusters/gen/
general_diagnostics.rs

1//! GeneralDiagnostics cluster (0x0033).
2//! @generated by `cargo xtask codegen` — do not edit.
3
4#![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
17/// Cluster ID.
18pub const CLUSTER_ID: u32 = 0x0033;
19/// Cluster revision.
20pub const CLUSTER_REVISION: u16 = 2;
21
22/// Command IDs (requests and responses).
23pub mod command_id {
24    /// `TestEventTrigger` (request).
25    pub const TEST_EVENT_TRIGGER: u32 = 0x00;
26    /// `TimeSnapshot` (request).
27    pub const TIME_SNAPSHOT: u32 = 0x01;
28    /// `TimeSnapshotResponse` (response).
29    pub const TIME_SNAPSHOT_RESPONSE: u32 = 0x02;
30    /// `PayloadTestRequest` (request).
31    pub const PAYLOAD_TEST_REQUEST: u32 = 0x03;
32    /// `PayloadTestResponse` (response).
33    pub const PAYLOAD_TEST_RESPONSE: u32 = 0x04;
34}
35
36/// Attribute IDs (cluster-specific).
37pub mod attribute_id {
38    /// `NetworkInterfaces`.
39    pub const NETWORK_INTERFACES: u32 = 0x0000;
40    /// `RebootCount`.
41    pub const REBOOT_COUNT: u32 = 0x0001;
42    /// `UpTime`.
43    pub const UP_TIME: u32 = 0x0002;
44    /// `TotalOperationalHours`.
45    pub const TOTAL_OPERATIONAL_HOURS: u32 = 0x0003;
46    /// `BootReason`.
47    pub const BOOT_REASON: u32 = 0x0004;
48    /// `ActiveHardwareFaults`.
49    pub const ACTIVE_HARDWARE_FAULTS: u32 = 0x0005;
50    /// `ActiveRadioFaults`.
51    pub const ACTIVE_RADIO_FAULTS: u32 = 0x0006;
52    /// `ActiveNetworkFaults`.
53    pub const ACTIVE_NETWORK_FAULTS: u32 = 0x0007;
54    /// `TestEventTriggersEnabled`.
55    pub const TEST_EVENT_TRIGGERS_ENABLED: u32 = 0x0008;
56}
57
58bitflags::bitflags! {
59    /// `GeneralDiagnostics` feature bits (FeatureMap).
60    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
61    pub struct Feature: u32 {
62        /// DataModelTest (DMTEST).
63        const DMTEST = 1 << 0;
64    }
65}
66
67/// `BootReasonEnum` (enum8).
68#[derive(Copy, Clone, Debug, PartialEq, Eq)]
69pub enum BootReasonEnum {
70    /// Unspecified = 0.
71    Unspecified,
72    /// PowerOnReboot = 1.
73    PowerOnReboot,
74    /// BrownOutReset = 2.
75    BrownOutReset,
76    /// SoftwareWatchdogReset = 3.
77    SoftwareWatchdogReset,
78    /// HardwareWatchdogReset = 4.
79    HardwareWatchdogReset,
80    /// SoftwareUpdateCompleted = 5.
81    SoftwareUpdateCompleted,
82    /// SoftwareReset = 6.
83    SoftwareReset,
84    /// A value not known to this codegen revision.
85    Unknown(u8),
86}
87
88impl BootReasonEnum {
89    /// Decode from its raw discriminant (unknown → `Unknown`).
90    #[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    /// The raw discriminant.
104    #[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/// `HardwareFaultEnum` (enum8).
120#[derive(Copy, Clone, Debug, PartialEq, Eq)]
121pub enum HardwareFaultEnum {
122    /// Unspecified = 0.
123    Unspecified,
124    /// Radio = 1.
125    Radio,
126    /// Sensor = 2.
127    Sensor,
128    /// ResettableOverTemp = 3.
129    ResettableOverTemp,
130    /// NonResettableOverTemp = 4.
131    NonResettableOverTemp,
132    /// PowerSource = 5.
133    PowerSource,
134    /// VisualDisplayFault = 6.
135    VisualDisplayFault,
136    /// AudioOutputFault = 7.
137    AudioOutputFault,
138    /// UserInterfaceFault = 8.
139    UserInterfaceFault,
140    /// NonVolatileMemoryError = 9.
141    NonVolatileMemoryError,
142    /// TamperDetected = 10.
143    TamperDetected,
144    /// A value not known to this codegen revision.
145    Unknown(u8),
146}
147
148impl HardwareFaultEnum {
149    /// Decode from its raw discriminant (unknown → `Unknown`).
150    #[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    /// The raw discriminant.
168    #[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/// `InterfaceTypeEnum` (enum8).
188#[derive(Copy, Clone, Debug, PartialEq, Eq)]
189pub enum InterfaceTypeEnum {
190    /// Unspecified = 0.
191    Unspecified,
192    /// WiFi = 1.
193    WiFi,
194    /// Ethernet = 2.
195    Ethernet,
196    /// Cellular = 3.
197    Cellular,
198    /// Thread = 4.
199    Thread,
200    /// A value not known to this codegen revision.
201    Unknown(u8),
202}
203
204impl InterfaceTypeEnum {
205    /// Decode from its raw discriminant (unknown → `Unknown`).
206    #[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    /// The raw discriminant.
218    #[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/// `NetworkFaultEnum` (enum8).
232#[derive(Copy, Clone, Debug, PartialEq, Eq)]
233pub enum NetworkFaultEnum {
234    /// Unspecified = 0.
235    Unspecified,
236    /// HardwareFailure = 1.
237    HardwareFailure,
238    /// NetworkJammed = 2.
239    NetworkJammed,
240    /// ConnectionFailed = 3.
241    ConnectionFailed,
242    /// A value not known to this codegen revision.
243    Unknown(u8),
244}
245
246impl NetworkFaultEnum {
247    /// Decode from its raw discriminant (unknown → `Unknown`).
248    #[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    /// The raw discriminant.
259    #[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/// `NetworkInterface` struct.
272#[derive(Clone, Debug, PartialEq)]
273#[non_exhaustive]
274pub struct NetworkInterface {
275    /// Field Name (tag 0).
276    pub name: String,
277    /// Field IsOperational (tag 1).
278    pub is_operational: bool,
279    /// Field OffPremiseServicesReachableIPv4 (tag 2).
280    pub off_premise_services_reachable_i_pv4: Nullable<bool>,
281    /// Field OffPremiseServicesReachableIPv6 (tag 3).
282    pub off_premise_services_reachable_i_pv6: Nullable<bool>,
283    /// Field HardwareAddress (tag 4).
284    pub hardware_address: Vec<u8>,
285    /// Field IPv4Addresses (tag 5).
286    pub i_pv4_addresses: Vec<Vec<u8>>,
287    /// Field IPv6Addresses (tag 6).
288    pub i_pv6_addresses: Vec<Vec<u8>>,
289    /// Field Type (tag 7).
290    pub r#type: InterfaceTypeEnum,
291}
292
293/// `RadioFaultEnum` (enum8).
294#[derive(Copy, Clone, Debug, PartialEq, Eq)]
295pub enum RadioFaultEnum {
296    /// Unspecified = 0.
297    Unspecified,
298    /// WiFiFault = 1.
299    WiFiFault,
300    /// CellularFault = 2.
301    CellularFault,
302    /// ThreadFault = 3.
303    ThreadFault,
304    /// NfcFault = 4.
305    NfcFault,
306    /// BleFault = 5.
307    BleFault,
308    /// EthernetFault = 6.
309    EthernetFault,
310    /// A value not known to this codegen revision.
311    Unknown(u8),
312}
313
314impl RadioFaultEnum {
315    /// Decode from its raw discriminant (unknown → `Unknown`).
316    #[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    /// The raw discriminant.
330    #[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    /// Decode the fields of an already-opened anonymous structure
347    /// (reader positioned after the struct start; consumes to its end).
348    ///
349    /// # Errors
350    /// Returns [`ClusterError`] on a malformed structure or missing required field.
351    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(_) => {} // skip unknown scalar
410                        }
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(_) => {} // skip unknown scalar
433                        }
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(_) => {} // unknown/future scalar — skip
448            }
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    /// Decode from a standalone anonymous TLV structure.
469    ///
470    /// # Errors
471    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
472    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
489/// Decode the `NetworkInterfaces` attribute value.
490///
491/// # Errors
492/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
493pub 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(_) => {} // skip unknown scalar
520        }
521    }
522    Ok(out)
523}
524
525/// Decode the `RebootCount` attribute value.
526///
527/// # Errors
528/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
529pub 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
542/// Decode the `UpTime` attribute value.
543///
544/// # Errors
545/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
546pub 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
557/// Decode the `TotalOperationalHours` attribute value.
558///
559/// # Errors
560/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
561pub 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
577/// Decode the `BootReason` attribute value.
578///
579/// # Errors
580/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
581pub 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
596/// Decode the `ActiveHardwareFaults` attribute value.
597///
598/// # Errors
599/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
600pub 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(_) => {} // skip unknown scalar
627        }
628    }
629    Ok(out)
630}
631
632/// Decode the `ActiveRadioFaults` attribute value.
633///
634/// # Errors
635/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
636pub 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(_) => {} // skip unknown scalar
663        }
664    }
665    Ok(out)
666}
667
668/// Decode the `ActiveNetworkFaults` attribute value.
669///
670/// # Errors
671/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
672pub 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(_) => {} // skip unknown scalar
699        }
700    }
701    Ok(out)
702}
703
704/// Decode the `TestEventTriggersEnabled` attribute value.
705///
706/// # Errors
707/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
708pub 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/// Encode the `TestEventTrigger` command request payload.
722#[must_use]
723#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
724pub 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/// Encode the `TimeSnapshot` command request payload.
738#[must_use]
739#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
740pub 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/// Decoded `TimeSnapshotResponse` payload.
750#[derive(Clone, Debug, PartialEq)]
751#[non_exhaustive]
752pub struct TimeSnapshotResponse {
753    /// Field SystemTimeMs (tag 0).
754    pub system_time_ms: u64,
755    /// Field PosixTimeMs (tag 1).
756    pub posix_time_ms: Nullable<u64>,
757}
758
759impl TimeSnapshotResponse {
760    /// Decode the fields of an already-opened anonymous structure
761    /// (reader positioned after the struct start; consumes to its end).
762    ///
763    /// # Errors
764    /// Returns [`ClusterError`] on a malformed structure or missing required field.
765    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(_) => {} // unknown/future scalar — skip
795            }
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    /// Decode from a standalone anonymous TLV structure.
803    ///
804    /// # Errors
805    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
806    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/// Encode the `PayloadTestRequest` command request payload.
824#[must_use]
825#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
826pub 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/// Decoded `PayloadTestResponse` payload.
842#[derive(Clone, Debug, PartialEq)]
843#[non_exhaustive]
844pub struct PayloadTestResponse {
845    /// Field Payload (tag 0).
846    pub payload: Vec<u8>,
847}
848
849impl PayloadTestResponse {
850    /// Decode the fields of an already-opened anonymous structure
851    /// (reader positioned after the struct start; consumes to its end).
852    ///
853    /// # Errors
854    /// Returns [`ClusterError`] on a malformed structure or missing required field.
855    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(_) => {} // unknown/future scalar — skip
867            }
868        }
869        Ok(Self {
870            payload: f_payload.ok_or(ClusterError::MissingField("Payload"))?,
871        })
872    }
873    /// Decode from a standalone anonymous TLV structure.
874    ///
875    /// # Errors
876    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
877    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}