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 = 0x002A;
19pub const CLUSTER_REVISION: u16 = 1;
21
22pub mod command_id {
24 pub const ANNOUNCE_OTA_PROVIDER: u32 = 0x00;
26}
27
28pub mod attribute_id {
30 pub const DEFAULT_OTA_PROVIDERS: u32 = 0x0000;
32 pub const UPDATE_POSSIBLE: u32 = 0x0001;
34 pub const UPDATE_STATE: u32 = 0x0002;
36 pub const UPDATE_STATE_PROGRESS: u32 = 0x0003;
38}
39
40#[derive(Copy, Clone, Debug, PartialEq, Eq)]
42pub enum AnnouncementReasonEnum {
43 SimpleAnnouncement,
45 UpdateAvailable,
47 UrgentUpdateAvailable,
49 Unknown(u8),
51}
52
53impl AnnouncementReasonEnum {
54 #[must_use]
56 pub fn from_raw(v: u8) -> Self {
57 match v {
58 0 => Self::SimpleAnnouncement,
59 1 => Self::UpdateAvailable,
60 2 => Self::UrgentUpdateAvailable,
61 other => Self::Unknown(other),
62 }
63 }
64 #[must_use]
66 pub fn to_raw(self) -> u8 {
67 match self {
68 Self::SimpleAnnouncement => 0,
69 Self::UpdateAvailable => 1,
70 Self::UrgentUpdateAvailable => 2,
71 Self::Unknown(v) => v,
72 }
73 }
74}
75
76#[derive(Copy, Clone, Debug, PartialEq, Eq)]
78pub enum ChangeReasonEnum {
79 Unknown,
81 Success,
83 Failure,
85 TimeOut,
87 DelayByProvider,
89 Unrecognized(u8),
91}
92
93impl ChangeReasonEnum {
94 #[must_use]
96 pub fn from_raw(v: u8) -> Self {
97 match v {
98 0 => Self::Unknown,
99 1 => Self::Success,
100 2 => Self::Failure,
101 3 => Self::TimeOut,
102 4 => Self::DelayByProvider,
103 other => Self::Unrecognized(other),
104 }
105 }
106 #[must_use]
108 pub fn to_raw(self) -> u8 {
109 match self {
110 Self::Unknown => 0,
111 Self::Success => 1,
112 Self::Failure => 2,
113 Self::TimeOut => 3,
114 Self::DelayByProvider => 4,
115 Self::Unrecognized(v) => v,
116 }
117 }
118}
119
120#[derive(Clone, Debug, PartialEq)]
122#[non_exhaustive]
123pub struct ProviderLocation {
124 pub provider_node_id: u64,
126 pub endpoint: u16,
128 pub fabric_index: u8,
130}
131
132#[derive(Copy, Clone, Debug, PartialEq, Eq)]
134pub enum UpdateStateEnum {
135 Unknown,
137 Idle,
139 Querying,
141 DelayedOnQuery,
143 Downloading,
145 Applying,
147 DelayedOnApply,
149 RollingBack,
151 DelayedOnUserConsent,
153 Unrecognized(u8),
155}
156
157impl UpdateStateEnum {
158 #[must_use]
160 pub fn from_raw(v: u8) -> Self {
161 match v {
162 0 => Self::Unknown,
163 1 => Self::Idle,
164 2 => Self::Querying,
165 3 => Self::DelayedOnQuery,
166 4 => Self::Downloading,
167 5 => Self::Applying,
168 6 => Self::DelayedOnApply,
169 7 => Self::RollingBack,
170 8 => Self::DelayedOnUserConsent,
171 other => Self::Unrecognized(other),
172 }
173 }
174 #[must_use]
176 pub fn to_raw(self) -> u8 {
177 match self {
178 Self::Unknown => 0,
179 Self::Idle => 1,
180 Self::Querying => 2,
181 Self::DelayedOnQuery => 3,
182 Self::Downloading => 4,
183 Self::Applying => 5,
184 Self::DelayedOnApply => 6,
185 Self::RollingBack => 7,
186 Self::DelayedOnUserConsent => 8,
187 Self::Unrecognized(v) => v,
188 }
189 }
190}
191
192impl ProviderLocation {
193 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
199 let mut f_provider_node_id: Option<u64> = None;
200 let mut f_endpoint: Option<u16> = None;
201 let mut f_fabric_index: Option<u8> = None;
202 loop {
203 match r.next()? {
204 Some(Element::ContainerEnd) => break,
205 Some(Element::Scalar {
206 tag: Tag::Context(1),
207 value: Value::Uint(v),
208 }) => {
209 f_provider_node_id = Some(
210 u64::try_from(v)
211 .map_err(|_| ClusterError::InvalidLength("ProviderNodeId"))?,
212 )
213 }
214 Some(Element::Scalar {
215 tag: Tag::Context(2),
216 value: Value::Uint(v),
217 }) => {
218 f_endpoint = Some(
219 u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Endpoint"))?,
220 )
221 }
222 Some(Element::Scalar {
223 tag: Tag::Context(254),
224 value: Value::Uint(v),
225 }) => {
226 f_fabric_index = Some(
227 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
228 )
229 }
230 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
231 Some(Element::ContainerStart { .. }) => r.skip_container()?,
232 Some(_) => {} }
234 }
235 Ok(Self {
236 provider_node_id: f_provider_node_id
237 .ok_or(ClusterError::MissingField("ProviderNodeId"))?,
238 endpoint: f_endpoint.ok_or(ClusterError::MissingField("Endpoint"))?,
239 fabric_index: f_fabric_index.ok_or(ClusterError::MissingField("FabricIndex"))?,
240 })
241 }
242 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
247 let mut r = TlvReader::new(tlv);
248 match r.next()? {
249 Some(Element::ContainerStart {
250 kind: ContainerKind::Structure,
251 ..
252 }) => {}
253 _ => {
254 return Err(ClusterError::UnexpectedType {
255 context: "ProviderLocation",
256 })
257 }
258 }
259 Self::decode_from(&mut r)
260 }
261 #[allow(clippy::expect_used)] pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
264 w.put_uint(Tag::Context(1), u64::from(self.provider_node_id))
265 .expect("infallible: vec writer");
266 w.put_uint(Tag::Context(2), u64::from(self.endpoint))
267 .expect("infallible: vec writer");
268 w.put_uint(Tag::Context(254), u64::from(self.fabric_index))
269 .expect("infallible: vec writer");
270 }
271 #[must_use]
273 #[allow(clippy::expect_used)] pub fn encode(&self) -> Vec<u8> {
275 let mut buf = Vec::new();
276 let mut w = TlvWriter::new(&mut buf);
277 w.start_structure(Tag::Anonymous)
278 .expect("infallible: vec writer");
279 self.write_fields(&mut w);
280 w.end_container().expect("infallible: vec writer");
281 buf
282 }
283}
284
285pub fn decode_default_ota_providers(tlv: &[u8]) -> Result<Vec<ProviderLocation>, ClusterError> {
290 let mut r = TlvReader::new(tlv);
291 match r.next()? {
292 Some(Element::ContainerStart {
293 kind: ContainerKind::Array,
294 ..
295 }) => {}
296 _ => {
297 return Err(ClusterError::UnexpectedType {
298 context: "DefaultOtaProviders",
299 })
300 }
301 }
302 let r = &mut r;
303 let mut out = Vec::new();
304 loop {
305 match r.next()? {
306 Some(Element::ContainerEnd) => break,
307 Some(Element::ContainerStart {
308 kind: ContainerKind::Structure,
309 ..
310 }) => {
311 out.push(ProviderLocation::decode_from(r)?);
312 }
313 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
314 Some(Element::ContainerStart { .. }) => r.skip_container()?,
315 Some(_) => {} }
317 }
318 Ok(out)
319}
320
321pub fn decode_update_possible(tlv: &[u8]) -> Result<bool, ClusterError> {
326 let mut r = TlvReader::new(tlv);
327 match r.next()? {
328 Some(Element::Scalar {
329 value: Value::Bool(v),
330 ..
331 }) => Ok(v),
332 _ => Err(ClusterError::UnexpectedType {
333 context: "UpdatePossible",
334 }),
335 }
336}
337
338pub fn decode_update_state(tlv: &[u8]) -> Result<UpdateStateEnum, ClusterError> {
343 let mut r = TlvReader::new(tlv);
344 match r.next()? {
345 Some(Element::Scalar {
346 value: Value::Uint(v),
347 ..
348 }) => Ok(UpdateStateEnum::from_raw(
349 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("UpdateState"))?,
350 )),
351 _ => Err(ClusterError::UnexpectedType {
352 context: "UpdateState",
353 }),
354 }
355}
356
357pub fn decode_update_state_progress(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
362 let mut r = TlvReader::new(tlv);
363 match r.next()? {
364 Some(Element::Scalar {
365 value: Value::Null, ..
366 }) => Ok(Nullable::Null),
367 Some(Element::Scalar {
368 value: Value::Uint(v),
369 ..
370 }) => Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
371 ClusterError::InvalidLength("UpdateStateProgress")
372 })?)),
373 _ => Err(ClusterError::UnexpectedType {
374 context: "UpdateStateProgress",
375 }),
376 }
377}
378
379#[must_use]
381#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_announce_ota_provider(
383 provider_node_id: u64,
384 vendor_id: u16,
385 announcement_reason: AnnouncementReasonEnum,
386 metadata_for_node: Option<Vec<u8>>,
387 endpoint: u16,
388) -> Vec<u8> {
389 let mut buf = Vec::new();
390 let mut w = TlvWriter::new(&mut buf);
391 w.start_structure(Tag::Anonymous)
392 .expect("infallible: vec writer");
393 w.put_uint(Tag::Context(0), u64::from(provider_node_id))
394 .expect("infallible: vec writer");
395 w.put_uint(Tag::Context(1), u64::from(vendor_id))
396 .expect("infallible: vec writer");
397 w.put_uint(Tag::Context(2), u64::from(announcement_reason.to_raw()))
398 .expect("infallible: vec writer");
399 if let Some(metadata_for_node) = metadata_for_node {
400 w.put_bytes(Tag::Context(3), &metadata_for_node)
401 .expect("infallible: vec writer");
402 }
403 w.put_uint(Tag::Context(4), u64::from(endpoint))
404 .expect("infallible: vec writer");
405 w.end_container().expect("infallible: vec writer");
406 buf
407}