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 = 0x0028;
19pub const CLUSTER_REVISION: u16 = 5;
21
22pub mod command_id {}
24
25pub mod attribute_id {
27 pub const DATA_MODEL_REVISION: u32 = 0x0000;
29 pub const VENDOR_NAME: u32 = 0x0001;
31 pub const VENDOR_ID: u32 = 0x0002;
33 pub const PRODUCT_NAME: u32 = 0x0003;
35 pub const PRODUCT_ID: u32 = 0x0004;
37 pub const NODE_LABEL: u32 = 0x0005;
39 pub const LOCATION: u32 = 0x0006;
41 pub const HARDWARE_VERSION: u32 = 0x0007;
43 pub const HARDWARE_VERSION_STRING: u32 = 0x0008;
45 pub const SOFTWARE_VERSION: u32 = 0x0009;
47 pub const SOFTWARE_VERSION_STRING: u32 = 0x000A;
49 pub const MANUFACTURING_DATE: u32 = 0x000B;
51 pub const PART_NUMBER: u32 = 0x000C;
53 pub const PRODUCT_URL: u32 = 0x000D;
55 pub const PRODUCT_LABEL: u32 = 0x000E;
57 pub const SERIAL_NUMBER: u32 = 0x000F;
59 pub const LOCAL_CONFIG_DISABLED: u32 = 0x0010;
61 pub const REACHABLE: u32 = 0x0011;
63 pub const UNIQUE_ID: u32 = 0x0012;
65 pub const CAPABILITY_MINIMA: u32 = 0x0013;
67 pub const PRODUCT_APPEARANCE: u32 = 0x0014;
69 pub const SPECIFICATION_VERSION: u32 = 0x0015;
71 pub const MAX_PATHS_PER_INVOKE: u32 = 0x0016;
73 pub const CONFIGURATION_VERSION: u32 = 0x0018;
75}
76
77#[derive(Clone, Debug, PartialEq)]
79#[non_exhaustive]
80pub struct CapabilityMinimaStruct {
81 pub case_sessions_per_fabric: u16,
83 pub subscriptions_per_fabric: u16,
85}
86
87#[derive(Copy, Clone, Debug, PartialEq, Eq)]
89pub enum ColorEnum {
90 Black,
92 Navy,
94 Green,
96 Teal,
98 Maroon,
100 Purple,
102 Olive,
104 Gray,
106 Blue,
108 Lime,
110 Aqua,
112 Red,
114 Fuchsia,
116 Yellow,
118 White,
120 Nickel,
122 Chrome,
124 Brass,
126 Copper,
128 Silver,
130 Gold,
132 Unknown(u8),
134}
135
136impl ColorEnum {
137 #[must_use]
139 pub fn from_raw(v: u8) -> Self {
140 match v {
141 0 => Self::Black,
142 1 => Self::Navy,
143 2 => Self::Green,
144 3 => Self::Teal,
145 4 => Self::Maroon,
146 5 => Self::Purple,
147 6 => Self::Olive,
148 7 => Self::Gray,
149 8 => Self::Blue,
150 9 => Self::Lime,
151 10 => Self::Aqua,
152 11 => Self::Red,
153 12 => Self::Fuchsia,
154 13 => Self::Yellow,
155 14 => Self::White,
156 15 => Self::Nickel,
157 16 => Self::Chrome,
158 17 => Self::Brass,
159 18 => Self::Copper,
160 19 => Self::Silver,
161 20 => Self::Gold,
162 other => Self::Unknown(other),
163 }
164 }
165 #[must_use]
167 pub fn to_raw(self) -> u8 {
168 match self {
169 Self::Black => 0,
170 Self::Navy => 1,
171 Self::Green => 2,
172 Self::Teal => 3,
173 Self::Maroon => 4,
174 Self::Purple => 5,
175 Self::Olive => 6,
176 Self::Gray => 7,
177 Self::Blue => 8,
178 Self::Lime => 9,
179 Self::Aqua => 10,
180 Self::Red => 11,
181 Self::Fuchsia => 12,
182 Self::Yellow => 13,
183 Self::White => 14,
184 Self::Nickel => 15,
185 Self::Chrome => 16,
186 Self::Brass => 17,
187 Self::Copper => 18,
188 Self::Silver => 19,
189 Self::Gold => 20,
190 Self::Unknown(v) => v,
191 }
192 }
193}
194
195#[derive(Clone, Debug, PartialEq)]
197#[non_exhaustive]
198pub struct ProductAppearanceStruct {
199 pub finish: ProductFinishEnum,
201 pub primary_color: Nullable<ColorEnum>,
203}
204
205#[derive(Copy, Clone, Debug, PartialEq, Eq)]
207pub enum ProductFinishEnum {
208 Other,
210 Matte,
212 Satin,
214 Polished,
216 Rugged,
218 Fabric,
220 Unknown(u8),
222}
223
224impl ProductFinishEnum {
225 #[must_use]
227 pub fn from_raw(v: u8) -> Self {
228 match v {
229 0 => Self::Other,
230 1 => Self::Matte,
231 2 => Self::Satin,
232 3 => Self::Polished,
233 4 => Self::Rugged,
234 5 => Self::Fabric,
235 other => Self::Unknown(other),
236 }
237 }
238 #[must_use]
240 pub fn to_raw(self) -> u8 {
241 match self {
242 Self::Other => 0,
243 Self::Matte => 1,
244 Self::Satin => 2,
245 Self::Polished => 3,
246 Self::Rugged => 4,
247 Self::Fabric => 5,
248 Self::Unknown(v) => v,
249 }
250 }
251}
252
253impl CapabilityMinimaStruct {
254 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
260 let mut f_case_sessions_per_fabric: Option<u16> = None;
261 let mut f_subscriptions_per_fabric: Option<u16> = None;
262 loop {
263 match r.next()? {
264 Some(Element::ContainerEnd) => break,
265 Some(Element::Scalar {
266 tag: Tag::Context(0),
267 value: Value::Uint(v),
268 }) => {
269 f_case_sessions_per_fabric = Some(
270 u16::try_from(v)
271 .map_err(|_| ClusterError::InvalidLength("CaseSessionsPerFabric"))?,
272 )
273 }
274 Some(Element::Scalar {
275 tag: Tag::Context(1),
276 value: Value::Uint(v),
277 }) => {
278 f_subscriptions_per_fabric = Some(
279 u16::try_from(v)
280 .map_err(|_| ClusterError::InvalidLength("SubscriptionsPerFabric"))?,
281 )
282 }
283 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
284 Some(Element::ContainerStart { .. }) => r.skip_container()?,
285 Some(_) => {} }
287 }
288 Ok(Self {
289 case_sessions_per_fabric: f_case_sessions_per_fabric
290 .ok_or(ClusterError::MissingField("CaseSessionsPerFabric"))?,
291 subscriptions_per_fabric: f_subscriptions_per_fabric
292 .ok_or(ClusterError::MissingField("SubscriptionsPerFabric"))?,
293 })
294 }
295 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
300 let mut r = TlvReader::new(tlv);
301 match r.next()? {
302 Some(Element::ContainerStart {
303 kind: ContainerKind::Structure,
304 ..
305 }) => {}
306 _ => {
307 return Err(ClusterError::UnexpectedType {
308 context: "CapabilityMinimaStruct",
309 })
310 }
311 }
312 Self::decode_from(&mut r)
313 }
314 #[allow(clippy::expect_used)] pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
317 w.put_uint(Tag::Context(0), u64::from(self.case_sessions_per_fabric))
318 .expect("infallible: vec writer");
319 w.put_uint(Tag::Context(1), u64::from(self.subscriptions_per_fabric))
320 .expect("infallible: vec writer");
321 }
322 #[must_use]
324 #[allow(clippy::expect_used)] pub fn encode(&self) -> Vec<u8> {
326 let mut buf = Vec::new();
327 let mut w = TlvWriter::new(&mut buf);
328 w.start_structure(Tag::Anonymous)
329 .expect("infallible: vec writer");
330 self.write_fields(&mut w);
331 w.end_container().expect("infallible: vec writer");
332 buf
333 }
334}
335
336impl ProductAppearanceStruct {
337 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
343 let mut f_finish: Option<ProductFinishEnum> = None;
344 let mut f_primary_color: Option<Nullable<ColorEnum>> = None;
345 loop {
346 match r.next()? {
347 Some(Element::ContainerEnd) => break,
348 Some(Element::Scalar {
349 tag: Tag::Context(0),
350 value: Value::Uint(v),
351 }) => {
352 f_finish = Some(ProductFinishEnum::from_raw(
353 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Finish"))?,
354 ))
355 }
356 Some(Element::Scalar {
357 tag: Tag::Context(1),
358 value: Value::Null,
359 }) => f_primary_color = Some(Nullable::Null),
360 Some(Element::Scalar {
361 tag: Tag::Context(1),
362 value: Value::Uint(v),
363 }) => {
364 f_primary_color = Some(Nullable::Value(ColorEnum::from_raw(
365 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("PrimaryColor"))?,
366 )))
367 }
368 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
369 Some(Element::ContainerStart { .. }) => r.skip_container()?,
370 Some(_) => {} }
372 }
373 Ok(Self {
374 finish: f_finish.ok_or(ClusterError::MissingField("Finish"))?,
375 primary_color: f_primary_color.ok_or(ClusterError::MissingField("PrimaryColor"))?,
376 })
377 }
378 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
383 let mut r = TlvReader::new(tlv);
384 match r.next()? {
385 Some(Element::ContainerStart {
386 kind: ContainerKind::Structure,
387 ..
388 }) => {}
389 _ => {
390 return Err(ClusterError::UnexpectedType {
391 context: "ProductAppearanceStruct",
392 })
393 }
394 }
395 Self::decode_from(&mut r)
396 }
397 #[allow(clippy::expect_used)] pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
400 w.put_uint(Tag::Context(0), u64::from(self.finish.to_raw()))
401 .expect("infallible: vec writer");
402 match &self.primary_color {
403 Nullable::Null => w.put_null(Tag::Context(1)).expect("infallible: vec writer"),
404 Nullable::Value(primary_color) => {
405 w.put_uint(Tag::Context(1), u64::from((*primary_color).to_raw()))
406 .expect("infallible: vec writer");
407 }
408 }
409 }
410 #[must_use]
412 #[allow(clippy::expect_used)] pub fn encode(&self) -> Vec<u8> {
414 let mut buf = Vec::new();
415 let mut w = TlvWriter::new(&mut buf);
416 w.start_structure(Tag::Anonymous)
417 .expect("infallible: vec writer");
418 self.write_fields(&mut w);
419 w.end_container().expect("infallible: vec writer");
420 buf
421 }
422}
423
424pub fn decode_data_model_revision(tlv: &[u8]) -> Result<u16, ClusterError> {
429 let mut r = TlvReader::new(tlv);
430 match r.next()? {
431 Some(Element::Scalar {
432 value: Value::Uint(v),
433 ..
434 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("DataModelRevision"))?),
435 _ => Err(ClusterError::UnexpectedType {
436 context: "DataModelRevision",
437 }),
438 }
439}
440
441pub fn decode_vendor_name(tlv: &[u8]) -> Result<String, ClusterError> {
446 let mut r = TlvReader::new(tlv);
447 match r.next()? {
448 Some(Element::Scalar {
449 value: Value::Utf8(v),
450 ..
451 }) => Ok(v),
452 _ => Err(ClusterError::UnexpectedType {
453 context: "VendorName",
454 }),
455 }
456}
457
458pub fn decode_vendor_id(tlv: &[u8]) -> Result<u16, ClusterError> {
463 let mut r = TlvReader::new(tlv);
464 match r.next()? {
465 Some(Element::Scalar {
466 value: Value::Uint(v),
467 ..
468 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("VendorId"))?),
469 _ => Err(ClusterError::UnexpectedType {
470 context: "VendorId",
471 }),
472 }
473}
474
475pub fn decode_product_name(tlv: &[u8]) -> Result<String, ClusterError> {
480 let mut r = TlvReader::new(tlv);
481 match r.next()? {
482 Some(Element::Scalar {
483 value: Value::Utf8(v),
484 ..
485 }) => Ok(v),
486 _ => Err(ClusterError::UnexpectedType {
487 context: "ProductName",
488 }),
489 }
490}
491
492pub fn decode_product_id(tlv: &[u8]) -> Result<u16, ClusterError> {
497 let mut r = TlvReader::new(tlv);
498 match r.next()? {
499 Some(Element::Scalar {
500 value: Value::Uint(v),
501 ..
502 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("ProductId"))?),
503 _ => Err(ClusterError::UnexpectedType {
504 context: "ProductId",
505 }),
506 }
507}
508
509pub fn decode_node_label(tlv: &[u8]) -> Result<String, ClusterError> {
514 let mut r = TlvReader::new(tlv);
515 match r.next()? {
516 Some(Element::Scalar {
517 value: Value::Utf8(v),
518 ..
519 }) => Ok(v),
520 _ => Err(ClusterError::UnexpectedType {
521 context: "NodeLabel",
522 }),
523 }
524}
525
526#[must_use]
528#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_node_label(value: &String) -> Vec<u8> {
530 let mut buf = Vec::new();
531 let mut w = TlvWriter::new(&mut buf);
532 w.put_utf8(Tag::Anonymous, &value)
533 .expect("infallible: vec writer");
534 buf
535}
536
537pub fn decode_location(tlv: &[u8]) -> Result<String, ClusterError> {
542 let mut r = TlvReader::new(tlv);
543 match r.next()? {
544 Some(Element::Scalar {
545 value: Value::Utf8(v),
546 ..
547 }) => Ok(v),
548 _ => Err(ClusterError::UnexpectedType {
549 context: "Location",
550 }),
551 }
552}
553
554#[must_use]
556#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_location(value: &String) -> Vec<u8> {
558 let mut buf = Vec::new();
559 let mut w = TlvWriter::new(&mut buf);
560 w.put_utf8(Tag::Anonymous, &value)
561 .expect("infallible: vec writer");
562 buf
563}
564
565pub fn decode_hardware_version(tlv: &[u8]) -> Result<u16, ClusterError> {
570 let mut r = TlvReader::new(tlv);
571 match r.next()? {
572 Some(Element::Scalar {
573 value: Value::Uint(v),
574 ..
575 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("HardwareVersion"))?),
576 _ => Err(ClusterError::UnexpectedType {
577 context: "HardwareVersion",
578 }),
579 }
580}
581
582pub fn decode_hardware_version_string(tlv: &[u8]) -> Result<String, ClusterError> {
587 let mut r = TlvReader::new(tlv);
588 match r.next()? {
589 Some(Element::Scalar {
590 value: Value::Utf8(v),
591 ..
592 }) => Ok(v),
593 _ => Err(ClusterError::UnexpectedType {
594 context: "HardwareVersionString",
595 }),
596 }
597}
598
599pub fn decode_software_version(tlv: &[u8]) -> Result<u32, ClusterError> {
604 let mut r = TlvReader::new(tlv);
605 match r.next()? {
606 Some(Element::Scalar {
607 value: Value::Uint(v),
608 ..
609 }) => Ok(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("SoftwareVersion"))?),
610 _ => Err(ClusterError::UnexpectedType {
611 context: "SoftwareVersion",
612 }),
613 }
614}
615
616pub fn decode_software_version_string(tlv: &[u8]) -> Result<String, ClusterError> {
621 let mut r = TlvReader::new(tlv);
622 match r.next()? {
623 Some(Element::Scalar {
624 value: Value::Utf8(v),
625 ..
626 }) => Ok(v),
627 _ => Err(ClusterError::UnexpectedType {
628 context: "SoftwareVersionString",
629 }),
630 }
631}
632
633pub fn decode_manufacturing_date(tlv: &[u8]) -> Result<String, ClusterError> {
638 let mut r = TlvReader::new(tlv);
639 match r.next()? {
640 Some(Element::Scalar {
641 value: Value::Utf8(v),
642 ..
643 }) => Ok(v),
644 _ => Err(ClusterError::UnexpectedType {
645 context: "ManufacturingDate",
646 }),
647 }
648}
649
650pub fn decode_part_number(tlv: &[u8]) -> Result<String, ClusterError> {
655 let mut r = TlvReader::new(tlv);
656 match r.next()? {
657 Some(Element::Scalar {
658 value: Value::Utf8(v),
659 ..
660 }) => Ok(v),
661 _ => Err(ClusterError::UnexpectedType {
662 context: "PartNumber",
663 }),
664 }
665}
666
667pub fn decode_product_url(tlv: &[u8]) -> Result<String, ClusterError> {
672 let mut r = TlvReader::new(tlv);
673 match r.next()? {
674 Some(Element::Scalar {
675 value: Value::Utf8(v),
676 ..
677 }) => Ok(v),
678 _ => Err(ClusterError::UnexpectedType {
679 context: "ProductUrl",
680 }),
681 }
682}
683
684pub fn decode_product_label(tlv: &[u8]) -> Result<String, ClusterError> {
689 let mut r = TlvReader::new(tlv);
690 match r.next()? {
691 Some(Element::Scalar {
692 value: Value::Utf8(v),
693 ..
694 }) => Ok(v),
695 _ => Err(ClusterError::UnexpectedType {
696 context: "ProductLabel",
697 }),
698 }
699}
700
701pub fn decode_serial_number(tlv: &[u8]) -> Result<String, ClusterError> {
706 let mut r = TlvReader::new(tlv);
707 match r.next()? {
708 Some(Element::Scalar {
709 value: Value::Utf8(v),
710 ..
711 }) => Ok(v),
712 _ => Err(ClusterError::UnexpectedType {
713 context: "SerialNumber",
714 }),
715 }
716}
717
718pub fn decode_local_config_disabled(tlv: &[u8]) -> Result<bool, ClusterError> {
723 let mut r = TlvReader::new(tlv);
724 match r.next()? {
725 Some(Element::Scalar {
726 value: Value::Bool(v),
727 ..
728 }) => Ok(v),
729 _ => Err(ClusterError::UnexpectedType {
730 context: "LocalConfigDisabled",
731 }),
732 }
733}
734
735#[must_use]
737#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_local_config_disabled(value: bool) -> Vec<u8> {
739 let mut buf = Vec::new();
740 let mut w = TlvWriter::new(&mut buf);
741 w.put_bool(Tag::Anonymous, value)
742 .expect("infallible: vec writer");
743 buf
744}
745
746pub fn decode_reachable(tlv: &[u8]) -> Result<bool, ClusterError> {
751 let mut r = TlvReader::new(tlv);
752 match r.next()? {
753 Some(Element::Scalar {
754 value: Value::Bool(v),
755 ..
756 }) => Ok(v),
757 _ => Err(ClusterError::UnexpectedType {
758 context: "Reachable",
759 }),
760 }
761}
762
763pub fn decode_unique_id(tlv: &[u8]) -> Result<String, ClusterError> {
768 let mut r = TlvReader::new(tlv);
769 match r.next()? {
770 Some(Element::Scalar {
771 value: Value::Utf8(v),
772 ..
773 }) => Ok(v),
774 _ => Err(ClusterError::UnexpectedType {
775 context: "UniqueId",
776 }),
777 }
778}
779
780pub fn decode_capability_minima(tlv: &[u8]) -> Result<CapabilityMinimaStruct, ClusterError> {
785 CapabilityMinimaStruct::decode(tlv)
786}
787
788pub fn decode_product_appearance(tlv: &[u8]) -> Result<ProductAppearanceStruct, ClusterError> {
793 ProductAppearanceStruct::decode(tlv)
794}
795
796pub fn decode_specification_version(tlv: &[u8]) -> Result<u32, ClusterError> {
801 let mut r = TlvReader::new(tlv);
802 match r.next()? {
803 Some(Element::Scalar {
804 value: Value::Uint(v),
805 ..
806 }) => Ok(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("SpecificationVersion"))?),
807 _ => Err(ClusterError::UnexpectedType {
808 context: "SpecificationVersion",
809 }),
810 }
811}
812
813pub fn decode_max_paths_per_invoke(tlv: &[u8]) -> Result<u16, ClusterError> {
818 let mut r = TlvReader::new(tlv);
819 match r.next()? {
820 Some(Element::Scalar {
821 value: Value::Uint(v),
822 ..
823 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("MaxPathsPerInvoke"))?),
824 _ => Err(ClusterError::UnexpectedType {
825 context: "MaxPathsPerInvoke",
826 }),
827 }
828}
829
830pub fn decode_configuration_version(tlv: &[u8]) -> Result<u32, ClusterError> {
835 let mut r = TlvReader::new(tlv);
836 match r.next()? {
837 Some(Element::Scalar {
838 value: Value::Uint(v),
839 ..
840 }) => Ok(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("ConfigurationVersion"))?),
841 _ => Err(ClusterError::UnexpectedType {
842 context: "ConfigurationVersion",
843 }),
844 }
845}