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 = 0x0029;
19pub const CLUSTER_REVISION: u16 = 1;
21
22pub mod command_id {
24 pub const QUERY_IMAGE: u32 = 0x00;
26 pub const QUERY_IMAGE_RESPONSE: u32 = 0x01;
28 pub const APPLY_UPDATE_REQUEST: u32 = 0x02;
30 pub const APPLY_UPDATE_RESPONSE: u32 = 0x03;
32 pub const NOTIFY_UPDATE_APPLIED: u32 = 0x04;
34}
35
36pub mod attribute_id {}
38
39#[derive(Copy, Clone, Debug, PartialEq, Eq)]
41pub enum ApplyUpdateActionEnum {
42 Proceed,
44 AwaitNextAction,
46 Discontinue,
48 Unknown(u8),
50}
51
52impl ApplyUpdateActionEnum {
53 #[must_use]
55 pub fn from_raw(v: u8) -> Self {
56 match v {
57 0 => Self::Proceed,
58 1 => Self::AwaitNextAction,
59 2 => Self::Discontinue,
60 other => Self::Unknown(other),
61 }
62 }
63 #[must_use]
65 pub fn to_raw(self) -> u8 {
66 match self {
67 Self::Proceed => 0,
68 Self::AwaitNextAction => 1,
69 Self::Discontinue => 2,
70 Self::Unknown(v) => v,
71 }
72 }
73}
74
75#[derive(Copy, Clone, Debug, PartialEq, Eq)]
77pub enum DownloadProtocolEnum {
78 BdxSynchronous,
80 BdxAsynchronous,
82 Https,
84 VendorSpecific,
86 Unknown(u8),
88}
89
90impl DownloadProtocolEnum {
91 #[must_use]
93 pub fn from_raw(v: u8) -> Self {
94 match v {
95 0 => Self::BdxSynchronous,
96 1 => Self::BdxAsynchronous,
97 2 => Self::Https,
98 3 => Self::VendorSpecific,
99 other => Self::Unknown(other),
100 }
101 }
102 #[must_use]
104 pub fn to_raw(self) -> u8 {
105 match self {
106 Self::BdxSynchronous => 0,
107 Self::BdxAsynchronous => 1,
108 Self::Https => 2,
109 Self::VendorSpecific => 3,
110 Self::Unknown(v) => v,
111 }
112 }
113}
114
115#[derive(Copy, Clone, Debug, PartialEq, Eq)]
117pub enum StatusEnum {
118 UpdateAvailable,
120 Busy,
122 NotAvailable,
124 DownloadProtocolNotSupported,
126 Unknown(u8),
128}
129
130impl StatusEnum {
131 #[must_use]
133 pub fn from_raw(v: u8) -> Self {
134 match v {
135 0 => Self::UpdateAvailable,
136 1 => Self::Busy,
137 2 => Self::NotAvailable,
138 3 => Self::DownloadProtocolNotSupported,
139 other => Self::Unknown(other),
140 }
141 }
142 #[must_use]
144 pub fn to_raw(self) -> u8 {
145 match self {
146 Self::UpdateAvailable => 0,
147 Self::Busy => 1,
148 Self::NotAvailable => 2,
149 Self::DownloadProtocolNotSupported => 3,
150 Self::Unknown(v) => v,
151 }
152 }
153}
154
155#[must_use]
157#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_query_image(
159 vendor_id: u16,
160 product_id: u16,
161 software_version: u32,
162 protocols_supported: &Vec<DownloadProtocolEnum>,
163 hardware_version: Option<u16>,
164 location: Option<String>,
165 requestor_can_consent: Option<bool>,
166 metadata_for_provider: Option<Vec<u8>>,
167) -> Vec<u8> {
168 let mut buf = Vec::new();
169 let mut w = TlvWriter::new(&mut buf);
170 w.start_structure(Tag::Anonymous)
171 .expect("infallible: vec writer");
172 w.put_uint(Tag::Context(0), u64::from(vendor_id))
173 .expect("infallible: vec writer");
174 w.put_uint(Tag::Context(1), u64::from(product_id))
175 .expect("infallible: vec writer");
176 w.put_uint(Tag::Context(2), u64::from(software_version))
177 .expect("infallible: vec writer");
178 w.start_array(Tag::Context(3))
179 .expect("infallible: vec writer");
180 for el in protocols_supported.iter().copied() {
181 w.put_uint(Tag::Anonymous, u64::from(el.to_raw()))
182 .expect("infallible: vec writer");
183 }
184 w.end_container().expect("infallible: vec writer");
185 if let Some(hardware_version) = hardware_version {
186 w.put_uint(Tag::Context(4), u64::from(hardware_version))
187 .expect("infallible: vec writer");
188 }
189 if let Some(location) = location {
190 w.put_utf8(Tag::Context(5), &location)
191 .expect("infallible: vec writer");
192 }
193 if let Some(requestor_can_consent) = requestor_can_consent {
194 w.put_bool(Tag::Context(6), requestor_can_consent)
195 .expect("infallible: vec writer");
196 }
197 if let Some(metadata_for_provider) = metadata_for_provider {
198 w.put_bytes(Tag::Context(7), &metadata_for_provider)
199 .expect("infallible: vec writer");
200 }
201 w.end_container().expect("infallible: vec writer");
202 buf
203}
204
205#[derive(Clone, Debug, PartialEq)]
207#[non_exhaustive]
208pub struct QueryImageResponse {
209 pub status: StatusEnum,
211 pub delayed_action_time: Option<u32>,
213 pub image_uri: Option<String>,
215 pub software_version: Option<u32>,
217 pub software_version_string: Option<String>,
219 pub update_token: Option<Vec<u8>>,
221 pub user_consent_needed: Option<bool>,
223 pub metadata_for_requestor: Option<Vec<u8>>,
225}
226
227impl QueryImageResponse {
228 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
234 let mut f_status: Option<StatusEnum> = None;
235 let mut f_delayed_action_time: Option<u32> = None;
236 let mut f_image_uri: Option<String> = None;
237 let mut f_software_version: Option<u32> = None;
238 let mut f_software_version_string: Option<String> = None;
239 let mut f_update_token: Option<Vec<u8>> = None;
240 let mut f_user_consent_needed: Option<bool> = None;
241 let mut f_metadata_for_requestor: Option<Vec<u8>> = None;
242 loop {
243 match r.next()? {
244 Some(Element::ContainerEnd) => break,
245 Some(Element::Scalar {
246 tag: Tag::Context(0),
247 value: Value::Uint(v),
248 }) => {
249 f_status = Some(StatusEnum::from_raw(
250 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Status"))?,
251 ))
252 }
253 Some(Element::Scalar {
254 tag: Tag::Context(1),
255 value: Value::Uint(v),
256 }) => {
257 f_delayed_action_time = Some(
258 u32::try_from(v)
259 .map_err(|_| ClusterError::InvalidLength("DelayedActionTime"))?,
260 )
261 }
262 Some(Element::Scalar {
263 tag: Tag::Context(2),
264 value: Value::Utf8(v),
265 }) => f_image_uri = Some(v),
266 Some(Element::Scalar {
267 tag: Tag::Context(3),
268 value: Value::Uint(v),
269 }) => {
270 f_software_version = Some(
271 u32::try_from(v)
272 .map_err(|_| ClusterError::InvalidLength("SoftwareVersion"))?,
273 )
274 }
275 Some(Element::Scalar {
276 tag: Tag::Context(4),
277 value: Value::Utf8(v),
278 }) => f_software_version_string = Some(v),
279 Some(Element::Scalar {
280 tag: Tag::Context(5),
281 value: Value::Bytes(v),
282 }) => f_update_token = Some(v),
283 Some(Element::Scalar {
284 tag: Tag::Context(6),
285 value: Value::Bool(v),
286 }) => f_user_consent_needed = Some(v),
287 Some(Element::Scalar {
288 tag: Tag::Context(7),
289 value: Value::Bytes(v),
290 }) => f_metadata_for_requestor = Some(v),
291 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
292 Some(Element::ContainerStart { .. }) => r.skip_container()?,
293 Some(_) => {} }
295 }
296 Ok(Self {
297 status: f_status.ok_or(ClusterError::MissingField("Status"))?,
298 delayed_action_time: f_delayed_action_time,
299 image_uri: f_image_uri,
300 software_version: f_software_version,
301 software_version_string: f_software_version_string,
302 update_token: f_update_token,
303 user_consent_needed: f_user_consent_needed,
304 metadata_for_requestor: f_metadata_for_requestor,
305 })
306 }
307 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
312 let mut r = TlvReader::new(tlv);
313 match r.next()? {
314 Some(Element::ContainerStart {
315 kind: ContainerKind::Structure,
316 ..
317 }) => {}
318 _ => {
319 return Err(ClusterError::UnexpectedType {
320 context: "QueryImageResponse",
321 })
322 }
323 }
324 Self::decode_from(&mut r)
325 }
326}
327
328#[must_use]
330#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_apply_update_request(update_token: &Vec<u8>, new_version: u32) -> Vec<u8> {
332 let mut buf = Vec::new();
333 let mut w = TlvWriter::new(&mut buf);
334 w.start_structure(Tag::Anonymous)
335 .expect("infallible: vec writer");
336 w.put_bytes(Tag::Context(0), &update_token)
337 .expect("infallible: vec writer");
338 w.put_uint(Tag::Context(1), u64::from(new_version))
339 .expect("infallible: vec writer");
340 w.end_container().expect("infallible: vec writer");
341 buf
342}
343
344#[derive(Clone, Debug, PartialEq)]
346#[non_exhaustive]
347pub struct ApplyUpdateResponse {
348 pub action: ApplyUpdateActionEnum,
350 pub delayed_action_time: u32,
352}
353
354impl ApplyUpdateResponse {
355 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
361 let mut f_action: Option<ApplyUpdateActionEnum> = None;
362 let mut f_delayed_action_time: Option<u32> = None;
363 loop {
364 match r.next()? {
365 Some(Element::ContainerEnd) => break,
366 Some(Element::Scalar {
367 tag: Tag::Context(0),
368 value: Value::Uint(v),
369 }) => {
370 f_action = Some(ApplyUpdateActionEnum::from_raw(
371 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Action"))?,
372 ))
373 }
374 Some(Element::Scalar {
375 tag: Tag::Context(1),
376 value: Value::Uint(v),
377 }) => {
378 f_delayed_action_time = Some(
379 u32::try_from(v)
380 .map_err(|_| ClusterError::InvalidLength("DelayedActionTime"))?,
381 )
382 }
383 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
384 Some(Element::ContainerStart { .. }) => r.skip_container()?,
385 Some(_) => {} }
387 }
388 Ok(Self {
389 action: f_action.ok_or(ClusterError::MissingField("Action"))?,
390 delayed_action_time: f_delayed_action_time
391 .ok_or(ClusterError::MissingField("DelayedActionTime"))?,
392 })
393 }
394 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
399 let mut r = TlvReader::new(tlv);
400 match r.next()? {
401 Some(Element::ContainerStart {
402 kind: ContainerKind::Structure,
403 ..
404 }) => {}
405 _ => {
406 return Err(ClusterError::UnexpectedType {
407 context: "ApplyUpdateResponse",
408 })
409 }
410 }
411 Self::decode_from(&mut r)
412 }
413}
414
415#[must_use]
417#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_notify_update_applied(update_token: &Vec<u8>, software_version: u32) -> Vec<u8> {
419 let mut buf = Vec::new();
420 let mut w = TlvWriter::new(&mut buf);
421 w.start_structure(Tag::Anonymous)
422 .expect("infallible: vec writer");
423 w.put_bytes(Tag::Context(0), &update_token)
424 .expect("infallible: vec writer");
425 w.put_uint(Tag::Context(1), u64::from(software_version))
426 .expect("infallible: vec writer");
427 w.end_container().expect("infallible: vec writer");
428 buf
429}