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 = 0x0038;
19pub const CLUSTER_REVISION: u16 = 2;
21
22pub mod command_id {
24 pub const SET_UTC_TIME: u32 = 0x00;
26 pub const SET_TRUSTED_TIME_SOURCE: u32 = 0x01;
28 pub const SET_TIME_ZONE: u32 = 0x02;
30 pub const SET_TIME_ZONE_RESPONSE: u32 = 0x03;
32 pub const SET_DST_OFFSET: u32 = 0x04;
34 pub const SET_DEFAULT_NTP: u32 = 0x05;
36}
37
38pub mod attribute_id {
40 pub const UTC_TIME: u32 = 0x0000;
42 pub const GRANULARITY: u32 = 0x0001;
44 pub const TIME_SOURCE: u32 = 0x0002;
46 pub const TRUSTED_TIME_SOURCE: u32 = 0x0003;
48 pub const DEFAULT_NTP: u32 = 0x0004;
50 pub const TIME_ZONE: u32 = 0x0005;
52 pub const DST_OFFSET: u32 = 0x0006;
54 pub const LOCAL_TIME: u32 = 0x0007;
56 pub const TIME_ZONE_DATABASE: u32 = 0x0008;
58 pub const NTP_SERVER_AVAILABLE: u32 = 0x0009;
60 pub const TIME_ZONE_LIST_MAX_SIZE: u32 = 0x000A;
62 pub const DST_OFFSET_LIST_MAX_SIZE: u32 = 0x000B;
64 pub const SUPPORTS_DNS_RESOLVE: u32 = 0x000C;
66}
67
68bitflags::bitflags! {
69 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
71 pub struct Feature: u32 {
72 const TZ = 1 << 0;
74 const NTPC = 1 << 1;
76 const NTPS = 1 << 2;
78 const TSC = 1 << 3;
80 }
81}
82
83#[derive(Clone, Debug, PartialEq)]
85pub struct DSTOffsetStruct {
86 pub offset: i32,
88 pub valid_starting: u64,
90 pub valid_until: Nullable<u64>,
92}
93
94#[derive(Clone, Debug, PartialEq)]
96pub struct FabricScopedTrustedTimeSourceStruct {
97 pub node_id: u64,
99 pub endpoint: u16,
101}
102
103#[derive(Copy, Clone, Debug, PartialEq, Eq)]
105pub enum GranularityEnum {
106 NoTimeGranularity,
108 MinutesGranularity,
110 SecondsGranularity,
112 MillisecondsGranularity,
114 MicrosecondsGranularity,
116 Unknown(u8),
118}
119
120impl GranularityEnum {
121 #[must_use]
123 pub fn from_raw(v: u8) -> Self {
124 match v {
125 0 => Self::NoTimeGranularity,
126 1 => Self::MinutesGranularity,
127 2 => Self::SecondsGranularity,
128 3 => Self::MillisecondsGranularity,
129 4 => Self::MicrosecondsGranularity,
130 other => Self::Unknown(other),
131 }
132 }
133 #[must_use]
135 pub fn to_raw(self) -> u8 {
136 match self {
137 Self::NoTimeGranularity => 0,
138 Self::MinutesGranularity => 1,
139 Self::SecondsGranularity => 2,
140 Self::MillisecondsGranularity => 3,
141 Self::MicrosecondsGranularity => 4,
142 Self::Unknown(v) => v,
143 }
144 }
145}
146
147#[derive(Copy, Clone, Debug, PartialEq, Eq)]
149pub enum StatusCodeEnum {
150 TimeNotAccepted,
152 Unknown(u8),
154}
155
156impl StatusCodeEnum {
157 #[must_use]
159 pub fn from_raw(v: u8) -> Self {
160 match v {
161 2 => Self::TimeNotAccepted,
162 other => Self::Unknown(other),
163 }
164 }
165 #[must_use]
167 pub fn to_raw(self) -> u8 {
168 match self {
169 Self::TimeNotAccepted => 2,
170 Self::Unknown(v) => v,
171 }
172 }
173}
174
175#[derive(Copy, Clone, Debug, PartialEq, Eq)]
177pub enum TimeSourceEnum {
178 None,
180 Unknown,
182 Admin,
184 NodeTimeCluster,
186 NonMatterSntp,
188 NonMatterNtp,
190 MatterSntp,
192 MatterNtp,
194 MixedNtp,
196 NonMatterSntpnts,
198 NonMatterNtpnts,
200 MatterSntpnts,
202 MatterNtpnts,
204 MixedNtpnts,
206 CloudSource,
208 Ptp,
210 Gnss,
212 Unrecognized(u8),
214}
215
216impl TimeSourceEnum {
217 #[must_use]
219 pub fn from_raw(v: u8) -> Self {
220 match v {
221 0 => Self::None,
222 1 => Self::Unknown,
223 2 => Self::Admin,
224 3 => Self::NodeTimeCluster,
225 4 => Self::NonMatterSntp,
226 5 => Self::NonMatterNtp,
227 6 => Self::MatterSntp,
228 7 => Self::MatterNtp,
229 8 => Self::MixedNtp,
230 9 => Self::NonMatterSntpnts,
231 10 => Self::NonMatterNtpnts,
232 11 => Self::MatterSntpnts,
233 12 => Self::MatterNtpnts,
234 13 => Self::MixedNtpnts,
235 14 => Self::CloudSource,
236 15 => Self::Ptp,
237 16 => Self::Gnss,
238 other => Self::Unrecognized(other),
239 }
240 }
241 #[must_use]
243 pub fn to_raw(self) -> u8 {
244 match self {
245 Self::None => 0,
246 Self::Unknown => 1,
247 Self::Admin => 2,
248 Self::NodeTimeCluster => 3,
249 Self::NonMatterSntp => 4,
250 Self::NonMatterNtp => 5,
251 Self::MatterSntp => 6,
252 Self::MatterNtp => 7,
253 Self::MixedNtp => 8,
254 Self::NonMatterSntpnts => 9,
255 Self::NonMatterNtpnts => 10,
256 Self::MatterSntpnts => 11,
257 Self::MatterNtpnts => 12,
258 Self::MixedNtpnts => 13,
259 Self::CloudSource => 14,
260 Self::Ptp => 15,
261 Self::Gnss => 16,
262 Self::Unrecognized(v) => v,
263 }
264 }
265}
266
267#[derive(Copy, Clone, Debug, PartialEq, Eq)]
269pub enum TimeZoneDatabaseEnum {
270 Full,
272 Partial,
274 None,
276 Unknown(u8),
278}
279
280impl TimeZoneDatabaseEnum {
281 #[must_use]
283 pub fn from_raw(v: u8) -> Self {
284 match v {
285 0 => Self::Full,
286 1 => Self::Partial,
287 2 => Self::None,
288 other => Self::Unknown(other),
289 }
290 }
291 #[must_use]
293 pub fn to_raw(self) -> u8 {
294 match self {
295 Self::Full => 0,
296 Self::Partial => 1,
297 Self::None => 2,
298 Self::Unknown(v) => v,
299 }
300 }
301}
302
303#[derive(Clone, Debug, PartialEq)]
305pub struct TimeZoneStruct {
306 pub offset: i32,
308 pub valid_at: u64,
310 pub name: Option<String>,
312}
313
314#[derive(Clone, Debug, PartialEq)]
316#[non_exhaustive]
317pub struct TrustedTimeSourceStruct {
318 pub fabric_index: u8,
320 pub node_id: u64,
322 pub endpoint: u16,
324}
325
326impl DSTOffsetStruct {
327 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
333 let mut f_offset: Option<i32> = None;
334 let mut f_valid_starting: Option<u64> = None;
335 let mut f_valid_until: Option<Nullable<u64>> = None;
336 loop {
337 match r.next()? {
338 Some(Element::ContainerEnd) => break,
339 Some(Element::Scalar {
340 tag: Tag::Context(0),
341 value: Value::Int(v),
342 }) => {
343 f_offset =
344 Some(i32::try_from(v).map_err(|_| ClusterError::InvalidLength("Offset"))?)
345 }
346 Some(Element::Scalar {
347 tag: Tag::Context(1),
348 value: Value::Uint(v),
349 }) => {
350 f_valid_starting = Some(
351 u64::try_from(v)
352 .map_err(|_| ClusterError::InvalidLength("ValidStarting"))?,
353 )
354 }
355 Some(Element::Scalar {
356 tag: Tag::Context(2),
357 value: Value::Null,
358 }) => f_valid_until = Some(Nullable::Null),
359 Some(Element::Scalar {
360 tag: Tag::Context(2),
361 value: Value::Uint(v),
362 }) => {
363 f_valid_until = Some(Nullable::Value(
364 u64::try_from(v).map_err(|_| ClusterError::InvalidLength("ValidUntil"))?,
365 ))
366 }
367 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
368 Some(Element::ContainerStart { .. }) => r.skip_container()?,
369 Some(_) => {} }
371 }
372 Ok(Self {
373 offset: f_offset.ok_or(ClusterError::MissingField("Offset"))?,
374 valid_starting: f_valid_starting.ok_or(ClusterError::MissingField("ValidStarting"))?,
375 valid_until: f_valid_until.ok_or(ClusterError::MissingField("ValidUntil"))?,
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: "DSTOffsetStruct",
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_int(Tag::Context(0), i64::from(self.offset))
401 .expect("infallible: vec writer");
402 w.put_uint(Tag::Context(1), u64::from(self.valid_starting))
403 .expect("infallible: vec writer");
404 match &self.valid_until {
405 Nullable::Null => w.put_null(Tag::Context(2)).expect("infallible: vec writer"),
406 Nullable::Value(valid_until) => {
407 w.put_uint(Tag::Context(2), u64::from(*valid_until))
408 .expect("infallible: vec writer");
409 }
410 }
411 }
412 #[must_use]
414 #[allow(clippy::expect_used)] pub fn encode(&self) -> Vec<u8> {
416 let mut buf = Vec::new();
417 let mut w = TlvWriter::new(&mut buf);
418 w.start_structure(Tag::Anonymous)
419 .expect("infallible: vec writer");
420 self.write_fields(&mut w);
421 w.end_container().expect("infallible: vec writer");
422 buf
423 }
424}
425
426impl FabricScopedTrustedTimeSourceStruct {
427 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
433 let mut f_node_id: Option<u64> = None;
434 let mut f_endpoint: Option<u16> = None;
435 loop {
436 match r.next()? {
437 Some(Element::ContainerEnd) => break,
438 Some(Element::Scalar {
439 tag: Tag::Context(0),
440 value: Value::Uint(v),
441 }) => {
442 f_node_id =
443 Some(u64::try_from(v).map_err(|_| ClusterError::InvalidLength("NodeId"))?)
444 }
445 Some(Element::Scalar {
446 tag: Tag::Context(1),
447 value: Value::Uint(v),
448 }) => {
449 f_endpoint = Some(
450 u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Endpoint"))?,
451 )
452 }
453 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
454 Some(Element::ContainerStart { .. }) => r.skip_container()?,
455 Some(_) => {} }
457 }
458 Ok(Self {
459 node_id: f_node_id.ok_or(ClusterError::MissingField("NodeId"))?,
460 endpoint: f_endpoint.ok_or(ClusterError::MissingField("Endpoint"))?,
461 })
462 }
463 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
468 let mut r = TlvReader::new(tlv);
469 match r.next()? {
470 Some(Element::ContainerStart {
471 kind: ContainerKind::Structure,
472 ..
473 }) => {}
474 _ => {
475 return Err(ClusterError::UnexpectedType {
476 context: "FabricScopedTrustedTimeSourceStruct",
477 })
478 }
479 }
480 Self::decode_from(&mut r)
481 }
482 #[allow(clippy::expect_used)] pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
485 w.put_uint(Tag::Context(0), u64::from(self.node_id))
486 .expect("infallible: vec writer");
487 w.put_uint(Tag::Context(1), u64::from(self.endpoint))
488 .expect("infallible: vec writer");
489 }
490 #[must_use]
492 #[allow(clippy::expect_used)] pub fn encode(&self) -> Vec<u8> {
494 let mut buf = Vec::new();
495 let mut w = TlvWriter::new(&mut buf);
496 w.start_structure(Tag::Anonymous)
497 .expect("infallible: vec writer");
498 self.write_fields(&mut w);
499 w.end_container().expect("infallible: vec writer");
500 buf
501 }
502}
503
504impl TimeZoneStruct {
505 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
511 let mut f_offset: Option<i32> = None;
512 let mut f_valid_at: Option<u64> = None;
513 let mut f_name: Option<String> = None;
514 loop {
515 match r.next()? {
516 Some(Element::ContainerEnd) => break,
517 Some(Element::Scalar {
518 tag: Tag::Context(0),
519 value: Value::Int(v),
520 }) => {
521 f_offset =
522 Some(i32::try_from(v).map_err(|_| ClusterError::InvalidLength("Offset"))?)
523 }
524 Some(Element::Scalar {
525 tag: Tag::Context(1),
526 value: Value::Uint(v),
527 }) => {
528 f_valid_at =
529 Some(u64::try_from(v).map_err(|_| ClusterError::InvalidLength("ValidAt"))?)
530 }
531 Some(Element::Scalar {
532 tag: Tag::Context(2),
533 value: Value::Utf8(v),
534 }) => f_name = Some(v),
535 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
536 Some(Element::ContainerStart { .. }) => r.skip_container()?,
537 Some(_) => {} }
539 }
540 Ok(Self {
541 offset: f_offset.ok_or(ClusterError::MissingField("Offset"))?,
542 valid_at: f_valid_at.ok_or(ClusterError::MissingField("ValidAt"))?,
543 name: f_name,
544 })
545 }
546 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
551 let mut r = TlvReader::new(tlv);
552 match r.next()? {
553 Some(Element::ContainerStart {
554 kind: ContainerKind::Structure,
555 ..
556 }) => {}
557 _ => {
558 return Err(ClusterError::UnexpectedType {
559 context: "TimeZoneStruct",
560 })
561 }
562 }
563 Self::decode_from(&mut r)
564 }
565 #[allow(clippy::expect_used)] pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
568 w.put_int(Tag::Context(0), i64::from(self.offset))
569 .expect("infallible: vec writer");
570 w.put_uint(Tag::Context(1), u64::from(self.valid_at))
571 .expect("infallible: vec writer");
572 if let Some(name) = &self.name {
573 w.put_utf8(Tag::Context(2), &*name)
574 .expect("infallible: vec writer");
575 }
576 }
577 #[must_use]
579 #[allow(clippy::expect_used)] pub fn encode(&self) -> Vec<u8> {
581 let mut buf = Vec::new();
582 let mut w = TlvWriter::new(&mut buf);
583 w.start_structure(Tag::Anonymous)
584 .expect("infallible: vec writer");
585 self.write_fields(&mut w);
586 w.end_container().expect("infallible: vec writer");
587 buf
588 }
589}
590
591impl TrustedTimeSourceStruct {
592 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
598 let mut f_fabric_index: Option<u8> = None;
599 let mut f_node_id: Option<u64> = None;
600 let mut f_endpoint: Option<u16> = None;
601 loop {
602 match r.next()? {
603 Some(Element::ContainerEnd) => break,
604 Some(Element::Scalar {
605 tag: Tag::Context(0),
606 value: Value::Uint(v),
607 }) => {
608 f_fabric_index = Some(
609 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
610 )
611 }
612 Some(Element::Scalar {
613 tag: Tag::Context(1),
614 value: Value::Uint(v),
615 }) => {
616 f_node_id =
617 Some(u64::try_from(v).map_err(|_| ClusterError::InvalidLength("NodeId"))?)
618 }
619 Some(Element::Scalar {
620 tag: Tag::Context(2),
621 value: Value::Uint(v),
622 }) => {
623 f_endpoint = Some(
624 u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Endpoint"))?,
625 )
626 }
627 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
628 Some(Element::ContainerStart { .. }) => r.skip_container()?,
629 Some(_) => {} }
631 }
632 Ok(Self {
633 fabric_index: f_fabric_index.ok_or(ClusterError::MissingField("FabricIndex"))?,
634 node_id: f_node_id.ok_or(ClusterError::MissingField("NodeId"))?,
635 endpoint: f_endpoint.ok_or(ClusterError::MissingField("Endpoint"))?,
636 })
637 }
638 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
643 let mut r = TlvReader::new(tlv);
644 match r.next()? {
645 Some(Element::ContainerStart {
646 kind: ContainerKind::Structure,
647 ..
648 }) => {}
649 _ => {
650 return Err(ClusterError::UnexpectedType {
651 context: "TrustedTimeSourceStruct",
652 })
653 }
654 }
655 Self::decode_from(&mut r)
656 }
657 #[allow(clippy::expect_used)] pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
660 w.put_uint(Tag::Context(0), u64::from(self.fabric_index))
661 .expect("infallible: vec writer");
662 w.put_uint(Tag::Context(1), u64::from(self.node_id))
663 .expect("infallible: vec writer");
664 w.put_uint(Tag::Context(2), u64::from(self.endpoint))
665 .expect("infallible: vec writer");
666 }
667 #[must_use]
669 #[allow(clippy::expect_used)] pub fn encode(&self) -> Vec<u8> {
671 let mut buf = Vec::new();
672 let mut w = TlvWriter::new(&mut buf);
673 w.start_structure(Tag::Anonymous)
674 .expect("infallible: vec writer");
675 self.write_fields(&mut w);
676 w.end_container().expect("infallible: vec writer");
677 buf
678 }
679}
680
681pub fn decode_utc_time(tlv: &[u8]) -> Result<Nullable<u64>, ClusterError> {
686 let mut r = TlvReader::new(tlv);
687 match r.next()? {
688 Some(Element::Scalar {
689 value: Value::Null, ..
690 }) => Ok(Nullable::Null),
691 Some(Element::Scalar {
692 value: Value::Uint(v),
693 ..
694 }) => Ok(Nullable::Value(
695 u64::try_from(v).map_err(|_| ClusterError::InvalidLength("UtcTime"))?,
696 )),
697 _ => Err(ClusterError::UnexpectedType { context: "UtcTime" }),
698 }
699}
700
701pub fn decode_granularity(tlv: &[u8]) -> Result<GranularityEnum, ClusterError> {
706 let mut r = TlvReader::new(tlv);
707 match r.next()? {
708 Some(Element::Scalar {
709 value: Value::Uint(v),
710 ..
711 }) => Ok(GranularityEnum::from_raw(
712 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Granularity"))?,
713 )),
714 _ => Err(ClusterError::UnexpectedType {
715 context: "Granularity",
716 }),
717 }
718}
719
720pub fn decode_time_source(tlv: &[u8]) -> Result<TimeSourceEnum, ClusterError> {
725 let mut r = TlvReader::new(tlv);
726 match r.next()? {
727 Some(Element::Scalar {
728 value: Value::Uint(v),
729 ..
730 }) => Ok(TimeSourceEnum::from_raw(
731 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("TimeSource"))?,
732 )),
733 _ => Err(ClusterError::UnexpectedType {
734 context: "TimeSource",
735 }),
736 }
737}
738
739pub fn decode_trusted_time_source(
744 tlv: &[u8],
745) -> Result<Nullable<TrustedTimeSourceStruct>, ClusterError> {
746 let mut r = TlvReader::new(tlv);
747 match r.next()? {
748 Some(Element::Scalar {
749 value: Value::Null, ..
750 }) => Ok(Nullable::Null),
751 Some(Element::ContainerStart {
752 kind: ContainerKind::Structure,
753 ..
754 }) => Ok(Nullable::Value(TrustedTimeSourceStruct::decode_from(
755 &mut r,
756 )?)),
757 _ => Err(ClusterError::UnexpectedType {
758 context: "TrustedTimeSource",
759 }),
760 }
761}
762
763pub fn decode_default_ntp(tlv: &[u8]) -> Result<Nullable<String>, ClusterError> {
768 let mut r = TlvReader::new(tlv);
769 match r.next()? {
770 Some(Element::Scalar {
771 value: Value::Null, ..
772 }) => Ok(Nullable::Null),
773 Some(Element::Scalar {
774 value: Value::Utf8(v),
775 ..
776 }) => Ok(Nullable::Value(v)),
777 _ => Err(ClusterError::UnexpectedType {
778 context: "DefaultNtp",
779 }),
780 }
781}
782
783pub fn decode_time_zone(tlv: &[u8]) -> Result<Vec<TimeZoneStruct>, ClusterError> {
788 let mut r = TlvReader::new(tlv);
789 match r.next()? {
790 Some(Element::ContainerStart {
791 kind: ContainerKind::Array,
792 ..
793 }) => {}
794 _ => {
795 return Err(ClusterError::UnexpectedType {
796 context: "TimeZone",
797 })
798 }
799 }
800 let r = &mut r;
801 let mut out = Vec::new();
802 loop {
803 match r.next()? {
804 Some(Element::ContainerEnd) => break,
805 Some(Element::ContainerStart {
806 kind: ContainerKind::Structure,
807 ..
808 }) => {
809 out.push(TimeZoneStruct::decode_from(r)?);
810 }
811 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
812 Some(Element::ContainerStart { .. }) => r.skip_container()?,
813 Some(_) => {} }
815 }
816 Ok(out)
817}
818
819pub fn decode_dst_offset(tlv: &[u8]) -> Result<Vec<DSTOffsetStruct>, ClusterError> {
824 let mut r = TlvReader::new(tlv);
825 match r.next()? {
826 Some(Element::ContainerStart {
827 kind: ContainerKind::Array,
828 ..
829 }) => {}
830 _ => {
831 return Err(ClusterError::UnexpectedType {
832 context: "DstOffset",
833 })
834 }
835 }
836 let r = &mut r;
837 let mut out = Vec::new();
838 loop {
839 match r.next()? {
840 Some(Element::ContainerEnd) => break,
841 Some(Element::ContainerStart {
842 kind: ContainerKind::Structure,
843 ..
844 }) => {
845 out.push(DSTOffsetStruct::decode_from(r)?);
846 }
847 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
848 Some(Element::ContainerStart { .. }) => r.skip_container()?,
849 Some(_) => {} }
851 }
852 Ok(out)
853}
854
855pub fn decode_local_time(tlv: &[u8]) -> Result<Nullable<u64>, ClusterError> {
860 let mut r = TlvReader::new(tlv);
861 match r.next()? {
862 Some(Element::Scalar {
863 value: Value::Null, ..
864 }) => Ok(Nullable::Null),
865 Some(Element::Scalar {
866 value: Value::Uint(v),
867 ..
868 }) => Ok(Nullable::Value(
869 u64::try_from(v).map_err(|_| ClusterError::InvalidLength("LocalTime"))?,
870 )),
871 _ => Err(ClusterError::UnexpectedType {
872 context: "LocalTime",
873 }),
874 }
875}
876
877pub fn decode_time_zone_database(tlv: &[u8]) -> Result<TimeZoneDatabaseEnum, ClusterError> {
882 let mut r = TlvReader::new(tlv);
883 match r.next()? {
884 Some(Element::Scalar {
885 value: Value::Uint(v),
886 ..
887 }) => Ok(TimeZoneDatabaseEnum::from_raw(
888 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("TimeZoneDatabase"))?,
889 )),
890 _ => Err(ClusterError::UnexpectedType {
891 context: "TimeZoneDatabase",
892 }),
893 }
894}
895
896pub fn decode_ntp_server_available(tlv: &[u8]) -> Result<bool, ClusterError> {
901 let mut r = TlvReader::new(tlv);
902 match r.next()? {
903 Some(Element::Scalar {
904 value: Value::Bool(v),
905 ..
906 }) => Ok(v),
907 _ => Err(ClusterError::UnexpectedType {
908 context: "NtpServerAvailable",
909 }),
910 }
911}
912
913pub fn decode_time_zone_list_max_size(tlv: &[u8]) -> Result<u8, ClusterError> {
918 let mut r = TlvReader::new(tlv);
919 match r.next()? {
920 Some(Element::Scalar {
921 value: Value::Uint(v),
922 ..
923 }) => Ok(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("TimeZoneListMaxSize"))?),
924 _ => Err(ClusterError::UnexpectedType {
925 context: "TimeZoneListMaxSize",
926 }),
927 }
928}
929
930pub fn decode_dst_offset_list_max_size(tlv: &[u8]) -> Result<u8, ClusterError> {
935 let mut r = TlvReader::new(tlv);
936 match r.next()? {
937 Some(Element::Scalar {
938 value: Value::Uint(v),
939 ..
940 }) => Ok(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("DstOffsetListMaxSize"))?),
941 _ => Err(ClusterError::UnexpectedType {
942 context: "DstOffsetListMaxSize",
943 }),
944 }
945}
946
947pub fn decode_supports_dns_resolve(tlv: &[u8]) -> Result<bool, ClusterError> {
952 let mut r = TlvReader::new(tlv);
953 match r.next()? {
954 Some(Element::Scalar {
955 value: Value::Bool(v),
956 ..
957 }) => Ok(v),
958 _ => Err(ClusterError::UnexpectedType {
959 context: "SupportsDnsResolve",
960 }),
961 }
962}
963
964#[must_use]
966#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_set_utc_time(
968 utc_time: u64,
969 granularity: GranularityEnum,
970 time_source: Option<TimeSourceEnum>,
971) -> Vec<u8> {
972 let mut buf = Vec::new();
973 let mut w = TlvWriter::new(&mut buf);
974 w.start_structure(Tag::Anonymous)
975 .expect("infallible: vec writer");
976 w.put_uint(Tag::Context(0), u64::from(utc_time))
977 .expect("infallible: vec writer");
978 w.put_uint(Tag::Context(1), u64::from(granularity.to_raw()))
979 .expect("infallible: vec writer");
980 if let Some(time_source) = time_source {
981 w.put_uint(Tag::Context(2), u64::from(time_source.to_raw()))
982 .expect("infallible: vec writer");
983 }
984 w.end_container().expect("infallible: vec writer");
985 buf
986}
987
988#[must_use]
990#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_set_trusted_time_source(
992 trusted_time_source: Nullable<FabricScopedTrustedTimeSourceStruct>,
993) -> Vec<u8> {
994 let mut buf = Vec::new();
995 let mut w = TlvWriter::new(&mut buf);
996 w.start_structure(Tag::Anonymous)
997 .expect("infallible: vec writer");
998 match &trusted_time_source {
999 Nullable::Null => w.put_null(Tag::Context(0)).expect("infallible: vec writer"),
1000 Nullable::Value(trusted_time_source) => {
1001 w.start_structure(Tag::Context(0))
1002 .expect("infallible: vec writer");
1003 trusted_time_source.write_fields(&mut w);
1004 w.end_container().expect("infallible: vec writer");
1005 }
1006 }
1007 w.end_container().expect("infallible: vec writer");
1008 buf
1009}
1010
1011#[must_use]
1013#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_set_time_zone(time_zone: &Vec<TimeZoneStruct>) -> Vec<u8> {
1015 let mut buf = Vec::new();
1016 let mut w = TlvWriter::new(&mut buf);
1017 w.start_structure(Tag::Anonymous)
1018 .expect("infallible: vec writer");
1019 w.start_array(Tag::Context(0))
1020 .expect("infallible: vec writer");
1021 for el in time_zone.iter() {
1022 w.start_structure(Tag::Anonymous)
1023 .expect("infallible: vec writer");
1024 el.write_fields(&mut w);
1025 w.end_container().expect("infallible: vec writer");
1026 }
1027 w.end_container().expect("infallible: vec writer");
1028 w.end_container().expect("infallible: vec writer");
1029 buf
1030}
1031
1032#[derive(Clone, Debug, PartialEq)]
1034#[non_exhaustive]
1035pub struct SetTimeZoneResponse {
1036 pub dst_offset_required: bool,
1038}
1039
1040impl SetTimeZoneResponse {
1041 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
1047 let mut f_dst_offset_required: Option<bool> = None;
1048 loop {
1049 match r.next()? {
1050 Some(Element::ContainerEnd) => break,
1051 Some(Element::Scalar {
1052 tag: Tag::Context(0),
1053 value: Value::Bool(v),
1054 }) => f_dst_offset_required = Some(v),
1055 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
1056 Some(Element::ContainerStart { .. }) => r.skip_container()?,
1057 Some(_) => {} }
1059 }
1060 Ok(Self {
1061 dst_offset_required: f_dst_offset_required
1062 .ok_or(ClusterError::MissingField("DstOffsetRequired"))?,
1063 })
1064 }
1065 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
1070 let mut r = TlvReader::new(tlv);
1071 match r.next()? {
1072 Some(Element::ContainerStart {
1073 kind: ContainerKind::Structure,
1074 ..
1075 }) => {}
1076 _ => {
1077 return Err(ClusterError::UnexpectedType {
1078 context: "SetTimeZoneResponse",
1079 })
1080 }
1081 }
1082 Self::decode_from(&mut r)
1083 }
1084}
1085
1086#[must_use]
1088#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_set_dst_offset(dst_offset: &Vec<DSTOffsetStruct>) -> Vec<u8> {
1090 let mut buf = Vec::new();
1091 let mut w = TlvWriter::new(&mut buf);
1092 w.start_structure(Tag::Anonymous)
1093 .expect("infallible: vec writer");
1094 w.start_array(Tag::Context(0))
1095 .expect("infallible: vec writer");
1096 for el in dst_offset.iter() {
1097 w.start_structure(Tag::Anonymous)
1098 .expect("infallible: vec writer");
1099 el.write_fields(&mut w);
1100 w.end_container().expect("infallible: vec writer");
1101 }
1102 w.end_container().expect("infallible: vec writer");
1103 w.end_container().expect("infallible: vec writer");
1104 buf
1105}
1106
1107#[must_use]
1109#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_set_default_ntp(default_ntp: Nullable<String>) -> Vec<u8> {
1111 let mut buf = Vec::new();
1112 let mut w = TlvWriter::new(&mut buf);
1113 w.start_structure(Tag::Anonymous)
1114 .expect("infallible: vec writer");
1115 match default_ntp {
1116 Nullable::Null => w.put_null(Tag::Context(0)).expect("infallible: vec writer"),
1117 Nullable::Value(default_ntp) => {
1118 w.put_utf8(Tag::Context(0), &default_ntp)
1119 .expect("infallible: vec writer");
1120 }
1121 }
1122 w.end_container().expect("infallible: vec writer");
1123 buf
1124}