#![allow(
clippy::all,
clippy::pedantic,
dead_code,
unreachable_pub,
unused_imports
)]
use crate::datatypes::SemanticTagStruct;
use crate::error::ClusterError;
use crate::types::Nullable;
use matter_codec::{ContainerKind, Element, Tag, TlvReader, TlvWriter, Value};
pub const CLUSTER_ID: u32 = 0x0033;
pub const CLUSTER_REVISION: u16 = 2;
pub mod command_id {
pub const TEST_EVENT_TRIGGER: u32 = 0x00;
pub const TIME_SNAPSHOT: u32 = 0x01;
pub const TIME_SNAPSHOT_RESPONSE: u32 = 0x02;
pub const PAYLOAD_TEST_REQUEST: u32 = 0x03;
pub const PAYLOAD_TEST_RESPONSE: u32 = 0x04;
}
pub mod attribute_id {
pub const NETWORK_INTERFACES: u32 = 0x0000;
pub const REBOOT_COUNT: u32 = 0x0001;
pub const UP_TIME: u32 = 0x0002;
pub const TOTAL_OPERATIONAL_HOURS: u32 = 0x0003;
pub const BOOT_REASON: u32 = 0x0004;
pub const ACTIVE_HARDWARE_FAULTS: u32 = 0x0005;
pub const ACTIVE_RADIO_FAULTS: u32 = 0x0006;
pub const ACTIVE_NETWORK_FAULTS: u32 = 0x0007;
pub const TEST_EVENT_TRIGGERS_ENABLED: u32 = 0x0008;
}
bitflags::bitflags! {
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Feature: u32 {
const DMTEST = 1 << 0;
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum BootReasonEnum {
Unspecified,
PowerOnReboot,
BrownOutReset,
SoftwareWatchdogReset,
HardwareWatchdogReset,
SoftwareUpdateCompleted,
SoftwareReset,
Unknown(u8),
}
impl BootReasonEnum {
#[must_use]
pub fn from_raw(v: u8) -> Self {
match v {
0 => Self::Unspecified,
1 => Self::PowerOnReboot,
2 => Self::BrownOutReset,
3 => Self::SoftwareWatchdogReset,
4 => Self::HardwareWatchdogReset,
5 => Self::SoftwareUpdateCompleted,
6 => Self::SoftwareReset,
other => Self::Unknown(other),
}
}
#[must_use]
pub fn to_raw(self) -> u8 {
match self {
Self::Unspecified => 0,
Self::PowerOnReboot => 1,
Self::BrownOutReset => 2,
Self::SoftwareWatchdogReset => 3,
Self::HardwareWatchdogReset => 4,
Self::SoftwareUpdateCompleted => 5,
Self::SoftwareReset => 6,
Self::Unknown(v) => v,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum HardwareFaultEnum {
Unspecified,
Radio,
Sensor,
ResettableOverTemp,
NonResettableOverTemp,
PowerSource,
VisualDisplayFault,
AudioOutputFault,
UserInterfaceFault,
NonVolatileMemoryError,
TamperDetected,
Unknown(u8),
}
impl HardwareFaultEnum {
#[must_use]
pub fn from_raw(v: u8) -> Self {
match v {
0 => Self::Unspecified,
1 => Self::Radio,
2 => Self::Sensor,
3 => Self::ResettableOverTemp,
4 => Self::NonResettableOverTemp,
5 => Self::PowerSource,
6 => Self::VisualDisplayFault,
7 => Self::AudioOutputFault,
8 => Self::UserInterfaceFault,
9 => Self::NonVolatileMemoryError,
10 => Self::TamperDetected,
other => Self::Unknown(other),
}
}
#[must_use]
pub fn to_raw(self) -> u8 {
match self {
Self::Unspecified => 0,
Self::Radio => 1,
Self::Sensor => 2,
Self::ResettableOverTemp => 3,
Self::NonResettableOverTemp => 4,
Self::PowerSource => 5,
Self::VisualDisplayFault => 6,
Self::AudioOutputFault => 7,
Self::UserInterfaceFault => 8,
Self::NonVolatileMemoryError => 9,
Self::TamperDetected => 10,
Self::Unknown(v) => v,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InterfaceTypeEnum {
Unspecified,
WiFi,
Ethernet,
Cellular,
Thread,
Unknown(u8),
}
impl InterfaceTypeEnum {
#[must_use]
pub fn from_raw(v: u8) -> Self {
match v {
0 => Self::Unspecified,
1 => Self::WiFi,
2 => Self::Ethernet,
3 => Self::Cellular,
4 => Self::Thread,
other => Self::Unknown(other),
}
}
#[must_use]
pub fn to_raw(self) -> u8 {
match self {
Self::Unspecified => 0,
Self::WiFi => 1,
Self::Ethernet => 2,
Self::Cellular => 3,
Self::Thread => 4,
Self::Unknown(v) => v,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum NetworkFaultEnum {
Unspecified,
HardwareFailure,
NetworkJammed,
ConnectionFailed,
Unknown(u8),
}
impl NetworkFaultEnum {
#[must_use]
pub fn from_raw(v: u8) -> Self {
match v {
0 => Self::Unspecified,
1 => Self::HardwareFailure,
2 => Self::NetworkJammed,
3 => Self::ConnectionFailed,
other => Self::Unknown(other),
}
}
#[must_use]
pub fn to_raw(self) -> u8 {
match self {
Self::Unspecified => 0,
Self::HardwareFailure => 1,
Self::NetworkJammed => 2,
Self::ConnectionFailed => 3,
Self::Unknown(v) => v,
}
}
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct NetworkInterface {
pub name: String,
pub is_operational: bool,
pub off_premise_services_reachable_i_pv4: Nullable<bool>,
pub off_premise_services_reachable_i_pv6: Nullable<bool>,
pub hardware_address: Vec<u8>,
pub i_pv4_addresses: Vec<Vec<u8>>,
pub i_pv6_addresses: Vec<Vec<u8>>,
pub r#type: InterfaceTypeEnum,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum RadioFaultEnum {
Unspecified,
WiFiFault,
CellularFault,
ThreadFault,
NfcFault,
BleFault,
EthernetFault,
Unknown(u8),
}
impl RadioFaultEnum {
#[must_use]
pub fn from_raw(v: u8) -> Self {
match v {
0 => Self::Unspecified,
1 => Self::WiFiFault,
2 => Self::CellularFault,
3 => Self::ThreadFault,
4 => Self::NfcFault,
5 => Self::BleFault,
6 => Self::EthernetFault,
other => Self::Unknown(other),
}
}
#[must_use]
pub fn to_raw(self) -> u8 {
match self {
Self::Unspecified => 0,
Self::WiFiFault => 1,
Self::CellularFault => 2,
Self::ThreadFault => 3,
Self::NfcFault => 4,
Self::BleFault => 5,
Self::EthernetFault => 6,
Self::Unknown(v) => v,
}
}
}
impl NetworkInterface {
pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
let mut f_name: Option<String> = None;
let mut f_is_operational: Option<bool> = None;
let mut f_off_premise_services_reachable_i_pv4: Option<Nullable<bool>> = None;
let mut f_off_premise_services_reachable_i_pv6: Option<Nullable<bool>> = None;
let mut f_hardware_address: Option<Vec<u8>> = None;
let mut f_i_pv4_addresses: Option<Vec<Vec<u8>>> = None;
let mut f_i_pv6_addresses: Option<Vec<Vec<u8>>> = None;
let mut f_type: Option<InterfaceTypeEnum> = None;
loop {
match r.next()? {
Some(Element::ContainerEnd) => break,
Some(Element::Scalar {
tag: Tag::Context(0),
value: Value::Utf8(v),
}) => f_name = Some(v),
Some(Element::Scalar {
tag: Tag::Context(1),
value: Value::Bool(v),
}) => f_is_operational = Some(v),
Some(Element::Scalar {
tag: Tag::Context(2),
value: Value::Null,
}) => f_off_premise_services_reachable_i_pv4 = Some(Nullable::Null),
Some(Element::Scalar {
tag: Tag::Context(2),
value: Value::Bool(v),
}) => f_off_premise_services_reachable_i_pv4 = Some(Nullable::Value(v)),
Some(Element::Scalar {
tag: Tag::Context(3),
value: Value::Null,
}) => f_off_premise_services_reachable_i_pv6 = Some(Nullable::Null),
Some(Element::Scalar {
tag: Tag::Context(3),
value: Value::Bool(v),
}) => f_off_premise_services_reachable_i_pv6 = Some(Nullable::Value(v)),
Some(Element::Scalar {
tag: Tag::Context(4),
value: Value::Bytes(v),
}) => f_hardware_address = Some(v),
Some(Element::ContainerStart {
tag: Tag::Context(5),
kind: ContainerKind::Array,
}) => {
let mut out = Vec::new();
loop {
match r.next()? {
Some(Element::ContainerEnd) => break,
Some(Element::Scalar {
value: Value::Bytes(v),
..
}) => out.push(v),
None => {
return Err(ClusterError::Tlv(
matter_codec::Error::UnclosedContainer,
))
}
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
f_i_pv4_addresses = Some(out);
}
Some(Element::ContainerStart {
tag: Tag::Context(6),
kind: ContainerKind::Array,
}) => {
let mut out = Vec::new();
loop {
match r.next()? {
Some(Element::ContainerEnd) => break,
Some(Element::Scalar {
value: Value::Bytes(v),
..
}) => out.push(v),
None => {
return Err(ClusterError::Tlv(
matter_codec::Error::UnclosedContainer,
))
}
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
f_i_pv6_addresses = Some(out);
}
Some(Element::Scalar {
tag: Tag::Context(7),
value: Value::Uint(v),
}) => {
f_type = Some(InterfaceTypeEnum::from_raw(
u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Type"))?,
))
}
None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
Ok(Self {
name: f_name.ok_or(ClusterError::MissingField("Name"))?,
is_operational: f_is_operational.ok_or(ClusterError::MissingField("IsOperational"))?,
off_premise_services_reachable_i_pv4: f_off_premise_services_reachable_i_pv4.ok_or(
ClusterError::MissingField("OffPremiseServicesReachableIPv4"),
)?,
off_premise_services_reachable_i_pv6: f_off_premise_services_reachable_i_pv6.ok_or(
ClusterError::MissingField("OffPremiseServicesReachableIPv6"),
)?,
hardware_address: f_hardware_address
.ok_or(ClusterError::MissingField("HardwareAddress"))?,
i_pv4_addresses: f_i_pv4_addresses
.ok_or(ClusterError::MissingField("IPv4Addresses"))?,
i_pv6_addresses: f_i_pv6_addresses
.ok_or(ClusterError::MissingField("IPv6Addresses"))?,
r#type: f_type.ok_or(ClusterError::MissingField("Type"))?,
})
}
pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::ContainerStart {
kind: ContainerKind::Structure,
..
}) => {}
_ => {
return Err(ClusterError::UnexpectedType {
context: "NetworkInterface",
})
}
}
Self::decode_from(&mut r)
}
}
pub fn decode_network_interfaces(tlv: &[u8]) -> Result<Vec<NetworkInterface>, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::ContainerStart {
kind: ContainerKind::Array,
..
}) => {}
_ => {
return Err(ClusterError::UnexpectedType {
context: "NetworkInterfaces",
})
}
}
let r = &mut r;
let mut out = Vec::new();
loop {
match r.next()? {
Some(Element::ContainerEnd) => break,
Some(Element::ContainerStart {
kind: ContainerKind::Structure,
..
}) => {
out.push(NetworkInterface::decode_from(r)?);
}
None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
Ok(out)
}
pub fn decode_reboot_count(tlv: &[u8]) -> Result<u16, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::Scalar {
value: Value::Uint(v),
..
}) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("RebootCount"))?),
_ => Err(ClusterError::UnexpectedType {
context: "RebootCount",
}),
}
}
pub fn decode_up_time(tlv: &[u8]) -> Result<u64, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::Scalar {
value: Value::Uint(v),
..
}) => Ok(u64::try_from(v).map_err(|_| ClusterError::InvalidLength("UpTime"))?),
_ => Err(ClusterError::UnexpectedType { context: "UpTime" }),
}
}
pub fn decode_total_operational_hours(tlv: &[u8]) -> Result<u32, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::Scalar {
value: Value::Uint(v),
..
}) => {
Ok(u32::try_from(v)
.map_err(|_| ClusterError::InvalidLength("TotalOperationalHours"))?)
}
_ => Err(ClusterError::UnexpectedType {
context: "TotalOperationalHours",
}),
}
}
pub fn decode_boot_reason(tlv: &[u8]) -> Result<BootReasonEnum, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::Scalar {
value: Value::Uint(v),
..
}) => Ok(BootReasonEnum::from_raw(
u8::try_from(v).map_err(|_| ClusterError::InvalidLength("BootReason"))?,
)),
_ => Err(ClusterError::UnexpectedType {
context: "BootReason",
}),
}
}
pub fn decode_active_hardware_faults(tlv: &[u8]) -> Result<Vec<HardwareFaultEnum>, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::ContainerStart {
kind: ContainerKind::Array,
..
}) => {}
_ => {
return Err(ClusterError::UnexpectedType {
context: "ActiveHardwareFaults",
})
}
}
let r = &mut r;
let mut out = Vec::new();
loop {
match r.next()? {
Some(Element::ContainerEnd) => break,
Some(Element::Scalar {
value: Value::Uint(v),
..
}) => out.push(HardwareFaultEnum::from_raw(
u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ActiveHardwareFaults"))?,
)),
None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
Ok(out)
}
pub fn decode_active_radio_faults(tlv: &[u8]) -> Result<Vec<RadioFaultEnum>, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::ContainerStart {
kind: ContainerKind::Array,
..
}) => {}
_ => {
return Err(ClusterError::UnexpectedType {
context: "ActiveRadioFaults",
})
}
}
let r = &mut r;
let mut out = Vec::new();
loop {
match r.next()? {
Some(Element::ContainerEnd) => break,
Some(Element::Scalar {
value: Value::Uint(v),
..
}) => out.push(RadioFaultEnum::from_raw(
u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ActiveRadioFaults"))?,
)),
None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
Ok(out)
}
pub fn decode_active_network_faults(tlv: &[u8]) -> Result<Vec<NetworkFaultEnum>, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::ContainerStart {
kind: ContainerKind::Array,
..
}) => {}
_ => {
return Err(ClusterError::UnexpectedType {
context: "ActiveNetworkFaults",
})
}
}
let r = &mut r;
let mut out = Vec::new();
loop {
match r.next()? {
Some(Element::ContainerEnd) => break,
Some(Element::Scalar {
value: Value::Uint(v),
..
}) => out.push(NetworkFaultEnum::from_raw(
u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ActiveNetworkFaults"))?,
)),
None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
Ok(out)
}
pub fn decode_test_event_triggers_enabled(tlv: &[u8]) -> Result<bool, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::Scalar {
value: Value::Bool(v),
..
}) => Ok(v),
_ => Err(ClusterError::UnexpectedType {
context: "TestEventTriggersEnabled",
}),
}
}
#[must_use]
#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_test_event_trigger(enable_key: &Vec<u8>, event_trigger: u64) -> Vec<u8> {
let mut buf = Vec::new();
let mut w = TlvWriter::new(&mut buf);
w.start_structure(Tag::Anonymous)
.expect("infallible: vec writer");
w.put_bytes(Tag::Context(0), &enable_key)
.expect("infallible: vec writer");
w.put_uint(Tag::Context(1), u64::from(event_trigger))
.expect("infallible: vec writer");
w.end_container().expect("infallible: vec writer");
buf
}
#[must_use]
#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_time_snapshot() -> Vec<u8> {
let mut buf = Vec::new();
let mut w = TlvWriter::new(&mut buf);
w.start_structure(Tag::Anonymous)
.expect("infallible: vec writer");
w.end_container().expect("infallible: vec writer");
buf
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct TimeSnapshotResponse {
pub system_time_ms: u64,
pub posix_time_ms: Nullable<u64>,
}
impl TimeSnapshotResponse {
pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
let mut f_system_time_ms: Option<u64> = None;
let mut f_posix_time_ms: Option<Nullable<u64>> = None;
loop {
match r.next()? {
Some(Element::ContainerEnd) => break,
Some(Element::Scalar {
tag: Tag::Context(0),
value: Value::Uint(v),
}) => {
f_system_time_ms = Some(
u64::try_from(v)
.map_err(|_| ClusterError::InvalidLength("SystemTimeMs"))?,
)
}
Some(Element::Scalar {
tag: Tag::Context(1),
value: Value::Null,
}) => f_posix_time_ms = Some(Nullable::Null),
Some(Element::Scalar {
tag: Tag::Context(1),
value: Value::Uint(v),
}) => {
f_posix_time_ms = Some(Nullable::Value(
u64::try_from(v).map_err(|_| ClusterError::InvalidLength("PosixTimeMs"))?,
))
}
None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
Ok(Self {
system_time_ms: f_system_time_ms.ok_or(ClusterError::MissingField("SystemTimeMs"))?,
posix_time_ms: f_posix_time_ms.ok_or(ClusterError::MissingField("PosixTimeMs"))?,
})
}
pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::ContainerStart {
kind: ContainerKind::Structure,
..
}) => {}
_ => {
return Err(ClusterError::UnexpectedType {
context: "TimeSnapshotResponse",
})
}
}
Self::decode_from(&mut r)
}
}
#[must_use]
#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_payload_test_request(enable_key: &Vec<u8>, value: u8, count: u16) -> Vec<u8> {
let mut buf = Vec::new();
let mut w = TlvWriter::new(&mut buf);
w.start_structure(Tag::Anonymous)
.expect("infallible: vec writer");
w.put_bytes(Tag::Context(0), &enable_key)
.expect("infallible: vec writer");
w.put_uint(Tag::Context(1), u64::from(value))
.expect("infallible: vec writer");
w.put_uint(Tag::Context(2), u64::from(count))
.expect("infallible: vec writer");
w.end_container().expect("infallible: vec writer");
buf
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct PayloadTestResponse {
pub payload: Vec<u8>,
}
impl PayloadTestResponse {
pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
let mut f_payload: Option<Vec<u8>> = None;
loop {
match r.next()? {
Some(Element::ContainerEnd) => break,
Some(Element::Scalar {
tag: Tag::Context(0),
value: Value::Bytes(v),
}) => f_payload = Some(v),
None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
Ok(Self {
payload: f_payload.ok_or(ClusterError::MissingField("Payload"))?,
})
}
pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::ContainerStart {
kind: ContainerKind::Structure,
..
}) => {}
_ => {
return Err(ClusterError::UnexpectedType {
context: "PayloadTestResponse",
})
}
}
Self::decode_from(&mut r)
}
}