Skip to main content

matter_clusters/gen/
ota_software_update_provider.rs

1//! OtaSoftwareUpdateProvider cluster (0x0029).
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 = 0x0029;
19/// Cluster revision.
20pub const CLUSTER_REVISION: u16 = 1;
21
22/// Command IDs (requests and responses).
23pub mod command_id {
24    /// `QueryImage` (request).
25    pub const QUERY_IMAGE: u32 = 0x00;
26    /// `QueryImageResponse` (response).
27    pub const QUERY_IMAGE_RESPONSE: u32 = 0x01;
28    /// `ApplyUpdateRequest` (request).
29    pub const APPLY_UPDATE_REQUEST: u32 = 0x02;
30    /// `ApplyUpdateResponse` (response).
31    pub const APPLY_UPDATE_RESPONSE: u32 = 0x03;
32    /// `NotifyUpdateApplied` (request).
33    pub const NOTIFY_UPDATE_APPLIED: u32 = 0x04;
34}
35
36/// Attribute IDs (cluster-specific).
37pub mod attribute_id {}
38
39/// `ApplyUpdateActionEnum` (enum8).
40#[derive(Copy, Clone, Debug, PartialEq, Eq)]
41pub enum ApplyUpdateActionEnum {
42    /// Proceed = 0.
43    Proceed,
44    /// AwaitNextAction = 1.
45    AwaitNextAction,
46    /// Discontinue = 2.
47    Discontinue,
48    /// A value not known to this codegen revision.
49    Unknown(u8),
50}
51
52impl ApplyUpdateActionEnum {
53    /// Decode from its raw discriminant (unknown → `Unknown`).
54    #[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    /// The raw discriminant.
64    #[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/// `DownloadProtocolEnum` (enum8).
76#[derive(Copy, Clone, Debug, PartialEq, Eq)]
77pub enum DownloadProtocolEnum {
78    /// BdxSynchronous = 0.
79    BdxSynchronous,
80    /// BdxAsynchronous = 1.
81    BdxAsynchronous,
82    /// Https = 2.
83    Https,
84    /// VendorSpecific = 3.
85    VendorSpecific,
86    /// A value not known to this codegen revision.
87    Unknown(u8),
88}
89
90impl DownloadProtocolEnum {
91    /// Decode from its raw discriminant (unknown → `Unknown`).
92    #[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    /// The raw discriminant.
103    #[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/// `StatusEnum` (enum8).
116#[derive(Copy, Clone, Debug, PartialEq, Eq)]
117pub enum StatusEnum {
118    /// UpdateAvailable = 0.
119    UpdateAvailable,
120    /// Busy = 1.
121    Busy,
122    /// NotAvailable = 2.
123    NotAvailable,
124    /// DownloadProtocolNotSupported = 3.
125    DownloadProtocolNotSupported,
126    /// A value not known to this codegen revision.
127    Unknown(u8),
128}
129
130impl StatusEnum {
131    /// Decode from its raw discriminant (unknown → `Unknown`).
132    #[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    /// The raw discriminant.
143    #[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/// Encode the `QueryImage` command request payload.
156#[must_use]
157#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
158pub 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/// Decoded `QueryImageResponse` payload.
206#[derive(Clone, Debug, PartialEq)]
207#[non_exhaustive]
208pub struct QueryImageResponse {
209    /// Field Status (tag 0).
210    pub status: StatusEnum,
211    /// Field DelayedActionTime (tag 1).
212    pub delayed_action_time: Option<u32>,
213    /// Field ImageUri (tag 2).
214    pub image_uri: Option<String>,
215    /// Field SoftwareVersion (tag 3).
216    pub software_version: Option<u32>,
217    /// Field SoftwareVersionString (tag 4).
218    pub software_version_string: Option<String>,
219    /// Field UpdateToken (tag 5).
220    pub update_token: Option<Vec<u8>>,
221    /// Field UserConsentNeeded (tag 6).
222    pub user_consent_needed: Option<bool>,
223    /// Field MetadataForRequestor (tag 7).
224    pub metadata_for_requestor: Option<Vec<u8>>,
225}
226
227impl QueryImageResponse {
228    /// Decode the fields of an already-opened anonymous structure
229    /// (reader positioned after the struct start; consumes to its end).
230    ///
231    /// # Errors
232    /// Returns [`ClusterError`] on a malformed structure or missing required field.
233    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(_) => {} // unknown/future scalar — skip
294            }
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    /// Decode from a standalone anonymous TLV structure.
308    ///
309    /// # Errors
310    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
311    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/// Encode the `ApplyUpdateRequest` command request payload.
329#[must_use]
330#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
331pub 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/// Decoded `ApplyUpdateResponse` payload.
345#[derive(Clone, Debug, PartialEq)]
346#[non_exhaustive]
347pub struct ApplyUpdateResponse {
348    /// Field Action (tag 0).
349    pub action: ApplyUpdateActionEnum,
350    /// Field DelayedActionTime (tag 1).
351    pub delayed_action_time: u32,
352}
353
354impl ApplyUpdateResponse {
355    /// Decode the fields of an already-opened anonymous structure
356    /// (reader positioned after the struct start; consumes to its end).
357    ///
358    /// # Errors
359    /// Returns [`ClusterError`] on a malformed structure or missing required field.
360    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(_) => {} // unknown/future scalar — skip
386            }
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    /// Decode from a standalone anonymous TLV structure.
395    ///
396    /// # Errors
397    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
398    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/// Encode the `NotifyUpdateApplied` command request payload.
416#[must_use]
417#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
418pub 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}