#![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 = 0x002A;
pub const CLUSTER_REVISION: u16 = 1;
pub mod command_id {
pub const ANNOUNCE_OTA_PROVIDER: u32 = 0x00;
}
pub mod attribute_id {
pub const DEFAULT_OTA_PROVIDERS: u32 = 0x0000;
pub const UPDATE_POSSIBLE: u32 = 0x0001;
pub const UPDATE_STATE: u32 = 0x0002;
pub const UPDATE_STATE_PROGRESS: u32 = 0x0003;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum AnnouncementReasonEnum {
SimpleAnnouncement,
UpdateAvailable,
UrgentUpdateAvailable,
Unknown(u8),
}
impl AnnouncementReasonEnum {
#[must_use]
pub fn from_raw(v: u8) -> Self {
match v {
0 => Self::SimpleAnnouncement,
1 => Self::UpdateAvailable,
2 => Self::UrgentUpdateAvailable,
other => Self::Unknown(other),
}
}
#[must_use]
pub fn to_raw(self) -> u8 {
match self {
Self::SimpleAnnouncement => 0,
Self::UpdateAvailable => 1,
Self::UrgentUpdateAvailable => 2,
Self::Unknown(v) => v,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ChangeReasonEnum {
Unknown,
Success,
Failure,
TimeOut,
DelayByProvider,
Unrecognized(u8),
}
impl ChangeReasonEnum {
#[must_use]
pub fn from_raw(v: u8) -> Self {
match v {
0 => Self::Unknown,
1 => Self::Success,
2 => Self::Failure,
3 => Self::TimeOut,
4 => Self::DelayByProvider,
other => Self::Unrecognized(other),
}
}
#[must_use]
pub fn to_raw(self) -> u8 {
match self {
Self::Unknown => 0,
Self::Success => 1,
Self::Failure => 2,
Self::TimeOut => 3,
Self::DelayByProvider => 4,
Self::Unrecognized(v) => v,
}
}
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct ProviderLocation {
pub provider_node_id: u64,
pub endpoint: u16,
pub fabric_index: u8,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum UpdateStateEnum {
Unknown,
Idle,
Querying,
DelayedOnQuery,
Downloading,
Applying,
DelayedOnApply,
RollingBack,
DelayedOnUserConsent,
Unrecognized(u8),
}
impl UpdateStateEnum {
#[must_use]
pub fn from_raw(v: u8) -> Self {
match v {
0 => Self::Unknown,
1 => Self::Idle,
2 => Self::Querying,
3 => Self::DelayedOnQuery,
4 => Self::Downloading,
5 => Self::Applying,
6 => Self::DelayedOnApply,
7 => Self::RollingBack,
8 => Self::DelayedOnUserConsent,
other => Self::Unrecognized(other),
}
}
#[must_use]
pub fn to_raw(self) -> u8 {
match self {
Self::Unknown => 0,
Self::Idle => 1,
Self::Querying => 2,
Self::DelayedOnQuery => 3,
Self::Downloading => 4,
Self::Applying => 5,
Self::DelayedOnApply => 6,
Self::RollingBack => 7,
Self::DelayedOnUserConsent => 8,
Self::Unrecognized(v) => v,
}
}
}
impl ProviderLocation {
pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
let mut f_provider_node_id: Option<u64> = None;
let mut f_endpoint: Option<u16> = None;
let mut f_fabric_index: Option<u8> = None;
loop {
match r.next()? {
Some(Element::ContainerEnd) => break,
Some(Element::Scalar {
tag: Tag::Context(1),
value: Value::Uint(v),
}) => {
f_provider_node_id = Some(
u64::try_from(v)
.map_err(|_| ClusterError::InvalidLength("ProviderNodeId"))?,
)
}
Some(Element::Scalar {
tag: Tag::Context(2),
value: Value::Uint(v),
}) => {
f_endpoint = Some(
u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Endpoint"))?,
)
}
Some(Element::Scalar {
tag: Tag::Context(254),
value: Value::Uint(v),
}) => {
f_fabric_index = Some(
u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
)
}
None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
Ok(Self {
provider_node_id: f_provider_node_id
.ok_or(ClusterError::MissingField("ProviderNodeId"))?,
endpoint: f_endpoint.ok_or(ClusterError::MissingField("Endpoint"))?,
fabric_index: f_fabric_index.ok_or(ClusterError::MissingField("FabricIndex"))?,
})
}
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: "ProviderLocation",
})
}
}
Self::decode_from(&mut r)
}
#[allow(clippy::expect_used)] pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
w.put_uint(Tag::Context(1), u64::from(self.provider_node_id))
.expect("infallible: vec writer");
w.put_uint(Tag::Context(2), u64::from(self.endpoint))
.expect("infallible: vec writer");
w.put_uint(Tag::Context(254), u64::from(self.fabric_index))
.expect("infallible: vec writer");
}
#[must_use]
#[allow(clippy::expect_used)] pub fn encode(&self) -> Vec<u8> {
let mut buf = Vec::new();
let mut w = TlvWriter::new(&mut buf);
w.start_structure(Tag::Anonymous)
.expect("infallible: vec writer");
self.write_fields(&mut w);
w.end_container().expect("infallible: vec writer");
buf
}
}
pub fn decode_default_ota_providers(tlv: &[u8]) -> Result<Vec<ProviderLocation>, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::ContainerStart {
kind: ContainerKind::Array,
..
}) => {}
_ => {
return Err(ClusterError::UnexpectedType {
context: "DefaultOtaProviders",
})
}
}
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(ProviderLocation::decode_from(r)?);
}
None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
Some(Element::ContainerStart { .. }) => r.skip_container()?,
Some(_) => {} }
}
Ok(out)
}
pub fn decode_update_possible(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: "UpdatePossible",
}),
}
}
pub fn decode_update_state(tlv: &[u8]) -> Result<UpdateStateEnum, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::Scalar {
value: Value::Uint(v),
..
}) => Ok(UpdateStateEnum::from_raw(
u8::try_from(v).map_err(|_| ClusterError::InvalidLength("UpdateState"))?,
)),
_ => Err(ClusterError::UnexpectedType {
context: "UpdateState",
}),
}
}
pub fn decode_update_state_progress(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
let mut r = TlvReader::new(tlv);
match r.next()? {
Some(Element::Scalar {
value: Value::Null, ..
}) => Ok(Nullable::Null),
Some(Element::Scalar {
value: Value::Uint(v),
..
}) => Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
ClusterError::InvalidLength("UpdateStateProgress")
})?)),
_ => Err(ClusterError::UnexpectedType {
context: "UpdateStateProgress",
}),
}
}
#[must_use]
#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_announce_ota_provider(
provider_node_id: u64,
vendor_id: u16,
announcement_reason: AnnouncementReasonEnum,
metadata_for_node: Option<Vec<u8>>,
endpoint: 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_uint(Tag::Context(0), u64::from(provider_node_id))
.expect("infallible: vec writer");
w.put_uint(Tag::Context(1), u64::from(vendor_id))
.expect("infallible: vec writer");
w.put_uint(Tag::Context(2), u64::from(announcement_reason.to_raw()))
.expect("infallible: vec writer");
if let Some(metadata_for_node) = metadata_for_node {
w.put_bytes(Tag::Context(3), &metadata_for_node)
.expect("infallible: vec writer");
}
w.put_uint(Tag::Context(4), u64::from(endpoint))
.expect("infallible: vec writer");
w.end_container().expect("infallible: vec writer");
buf
}