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 = 0x0046;
19pub const CLUSTER_REVISION: u16 = 3;
21
22pub mod command_id {
24 pub const REGISTER_CLIENT: u32 = 0x00;
26 pub const REGISTER_CLIENT_RESPONSE: u32 = 0x01;
28 pub const UNREGISTER_CLIENT: u32 = 0x02;
30 pub const STAY_ACTIVE_REQUEST: u32 = 0x03;
32 pub const STAY_ACTIVE_RESPONSE: u32 = 0x04;
34}
35
36pub mod attribute_id {
38 pub const IDLE_MODE_DURATION: u32 = 0x0000;
40 pub const ACTIVE_MODE_DURATION: u32 = 0x0001;
42 pub const ACTIVE_MODE_THRESHOLD: u32 = 0x0002;
44 pub const REGISTERED_CLIENTS: u32 = 0x0003;
46 pub const ICD_COUNTER: u32 = 0x0004;
48 pub const CLIENTS_SUPPORTED_PER_FABRIC: u32 = 0x0005;
50 pub const USER_ACTIVE_MODE_TRIGGER_HINT: u32 = 0x0006;
52 pub const USER_ACTIVE_MODE_TRIGGER_INSTRUCTION: u32 = 0x0007;
54 pub const OPERATING_MODE: u32 = 0x0008;
56 pub const MAXIMUM_CHECK_IN_BACKOFF: u32 = 0x0009;
58}
59
60bitflags::bitflags! {
61 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
63 pub struct Feature: u32 {
64 const CIP = 1 << 0;
66 const UAT = 1 << 1;
68 const LITS = 1 << 2;
70 const DSLS = 1 << 3;
72 }
73}
74
75#[derive(Copy, Clone, Debug, PartialEq, Eq)]
77pub enum ClientTypeEnum {
78 Permanent,
80 Ephemeral,
82 Unknown(u8),
84}
85
86impl ClientTypeEnum {
87 #[must_use]
89 pub fn from_raw(v: u8) -> Self {
90 match v {
91 0 => Self::Permanent,
92 1 => Self::Ephemeral,
93 other => Self::Unknown(other),
94 }
95 }
96 #[must_use]
98 pub fn to_raw(self) -> u8 {
99 match self {
100 Self::Permanent => 0,
101 Self::Ephemeral => 1,
102 Self::Unknown(v) => v,
103 }
104 }
105}
106
107#[derive(Clone, Debug, PartialEq)]
109#[non_exhaustive]
110pub struct MonitoringRegistrationStruct {
111 pub check_in_node_id: u64,
113 pub monitored_subject: u64,
115 pub client_type: ClientTypeEnum,
117 pub fabric_index: u8,
119}
120
121#[derive(Copy, Clone, Debug, PartialEq, Eq)]
123pub enum OperatingModeEnum {
124 Sit,
126 Lit,
128 Unknown(u8),
130}
131
132impl OperatingModeEnum {
133 #[must_use]
135 pub fn from_raw(v: u8) -> Self {
136 match v {
137 0 => Self::Sit,
138 1 => Self::Lit,
139 other => Self::Unknown(other),
140 }
141 }
142 #[must_use]
144 pub fn to_raw(self) -> u8 {
145 match self {
146 Self::Sit => 0,
147 Self::Lit => 1,
148 Self::Unknown(v) => v,
149 }
150 }
151}
152
153bitflags::bitflags! {
154 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
156 pub struct UserActiveModeTriggerBitmap: u32 {
157 const POWER_CYCLE = 1 << 0;
159 const SETTINGS_MENU = 1 << 1;
161 const CUSTOM_INSTRUCTION = 1 << 2;
163 const DEVICE_MANUAL = 1 << 3;
165 const ACTUATE_SENSOR = 1 << 4;
167 const ACTUATE_SENSOR_SECONDS = 1 << 5;
169 const ACTUATE_SENSOR_TIMES = 1 << 6;
171 const ACTUATE_SENSOR_LIGHTS_BLINK = 1 << 7;
173 const RESET_BUTTON = 1 << 8;
175 const RESET_BUTTON_LIGHTS_BLINK = 1 << 9;
177 const RESET_BUTTON_SECONDS = 1 << 10;
179 const RESET_BUTTON_TIMES = 1 << 11;
181 const SETUP_BUTTON = 1 << 12;
183 const SETUP_BUTTON_SECONDS = 1 << 13;
185 const SETUP_BUTTON_LIGHTS_BLINK = 1 << 14;
187 const SETUP_BUTTON_TIMES = 1 << 15;
189 const APP_DEFINED_BUTTON = 1 << 16;
191 }
192}
193
194impl MonitoringRegistrationStruct {
195 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
201 let mut f_check_in_node_id: Option<u64> = None;
202 let mut f_monitored_subject: Option<u64> = None;
203 let mut f_client_type: Option<ClientTypeEnum> = None;
204 let mut f_fabric_index: Option<u8> = None;
205 loop {
206 match r.next()? {
207 Some(Element::ContainerEnd) => break,
208 Some(Element::Scalar {
209 tag: Tag::Context(1),
210 value: Value::Uint(v),
211 }) => {
212 f_check_in_node_id = Some(
213 u64::try_from(v)
214 .map_err(|_| ClusterError::InvalidLength("CheckInNodeId"))?,
215 )
216 }
217 Some(Element::Scalar {
218 tag: Tag::Context(2),
219 value: Value::Uint(v),
220 }) => {
221 f_monitored_subject = Some(
222 u64::try_from(v)
223 .map_err(|_| ClusterError::InvalidLength("MonitoredSubject"))?,
224 )
225 }
226 Some(Element::Scalar {
227 tag: Tag::Context(4),
228 value: Value::Uint(v),
229 }) => {
230 f_client_type = Some(ClientTypeEnum::from_raw(
231 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ClientType"))?,
232 ))
233 }
234 Some(Element::Scalar {
235 tag: Tag::Context(254),
236 value: Value::Uint(v),
237 }) => {
238 f_fabric_index = Some(
239 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
240 )
241 }
242 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
243 Some(Element::ContainerStart { .. }) => r.skip_container()?,
244 Some(_) => {} }
246 }
247 Ok(Self {
248 check_in_node_id: f_check_in_node_id
249 .ok_or(ClusterError::MissingField("CheckInNodeId"))?,
250 monitored_subject: f_monitored_subject
251 .ok_or(ClusterError::MissingField("MonitoredSubject"))?,
252 client_type: f_client_type.ok_or(ClusterError::MissingField("ClientType"))?,
253 fabric_index: f_fabric_index.ok_or(ClusterError::MissingField("FabricIndex"))?,
254 })
255 }
256 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
261 let mut r = TlvReader::new(tlv);
262 match r.next()? {
263 Some(Element::ContainerStart {
264 kind: ContainerKind::Structure,
265 ..
266 }) => {}
267 _ => {
268 return Err(ClusterError::UnexpectedType {
269 context: "MonitoringRegistrationStruct",
270 })
271 }
272 }
273 Self::decode_from(&mut r)
274 }
275 #[allow(clippy::expect_used)] pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
278 w.put_uint(Tag::Context(1), u64::from(self.check_in_node_id))
279 .expect("infallible: vec writer");
280 w.put_uint(Tag::Context(2), u64::from(self.monitored_subject))
281 .expect("infallible: vec writer");
282 w.put_uint(Tag::Context(4), u64::from(self.client_type.to_raw()))
283 .expect("infallible: vec writer");
284 w.put_uint(Tag::Context(254), u64::from(self.fabric_index))
285 .expect("infallible: vec writer");
286 }
287 #[must_use]
289 #[allow(clippy::expect_used)] pub fn encode(&self) -> Vec<u8> {
291 let mut buf = Vec::new();
292 let mut w = TlvWriter::new(&mut buf);
293 w.start_structure(Tag::Anonymous)
294 .expect("infallible: vec writer");
295 self.write_fields(&mut w);
296 w.end_container().expect("infallible: vec writer");
297 buf
298 }
299}
300
301pub fn decode_idle_mode_duration(tlv: &[u8]) -> Result<u32, ClusterError> {
306 let mut r = TlvReader::new(tlv);
307 match r.next()? {
308 Some(Element::Scalar {
309 value: Value::Uint(v),
310 ..
311 }) => Ok(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("IdleModeDuration"))?),
312 _ => Err(ClusterError::UnexpectedType {
313 context: "IdleModeDuration",
314 }),
315 }
316}
317
318pub fn decode_active_mode_duration(tlv: &[u8]) -> Result<u32, ClusterError> {
323 let mut r = TlvReader::new(tlv);
324 match r.next()? {
325 Some(Element::Scalar {
326 value: Value::Uint(v),
327 ..
328 }) => Ok(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("ActiveModeDuration"))?),
329 _ => Err(ClusterError::UnexpectedType {
330 context: "ActiveModeDuration",
331 }),
332 }
333}
334
335pub fn decode_active_mode_threshold(tlv: &[u8]) -> Result<u16, ClusterError> {
340 let mut r = TlvReader::new(tlv);
341 match r.next()? {
342 Some(Element::Scalar {
343 value: Value::Uint(v),
344 ..
345 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("ActiveModeThreshold"))?),
346 _ => Err(ClusterError::UnexpectedType {
347 context: "ActiveModeThreshold",
348 }),
349 }
350}
351
352pub fn decode_registered_clients(
357 tlv: &[u8],
358) -> Result<Vec<MonitoringRegistrationStruct>, ClusterError> {
359 let mut r = TlvReader::new(tlv);
360 match r.next()? {
361 Some(Element::ContainerStart {
362 kind: ContainerKind::Array,
363 ..
364 }) => {}
365 _ => {
366 return Err(ClusterError::UnexpectedType {
367 context: "RegisteredClients",
368 })
369 }
370 }
371 let r = &mut r;
372 let mut out = Vec::new();
373 loop {
374 match r.next()? {
375 Some(Element::ContainerEnd) => break,
376 Some(Element::ContainerStart {
377 kind: ContainerKind::Structure,
378 ..
379 }) => {
380 out.push(MonitoringRegistrationStruct::decode_from(r)?);
381 }
382 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
383 Some(Element::ContainerStart { .. }) => r.skip_container()?,
384 Some(_) => {} }
386 }
387 Ok(out)
388}
389
390pub fn decode_icd_counter(tlv: &[u8]) -> Result<u32, ClusterError> {
395 let mut r = TlvReader::new(tlv);
396 match r.next()? {
397 Some(Element::Scalar {
398 value: Value::Uint(v),
399 ..
400 }) => Ok(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("IcdCounter"))?),
401 _ => Err(ClusterError::UnexpectedType {
402 context: "IcdCounter",
403 }),
404 }
405}
406
407pub fn decode_clients_supported_per_fabric(tlv: &[u8]) -> Result<u16, ClusterError> {
412 let mut r = TlvReader::new(tlv);
413 match r.next()? {
414 Some(Element::Scalar {
415 value: Value::Uint(v),
416 ..
417 }) => Ok(u16::try_from(v)
418 .map_err(|_| ClusterError::InvalidLength("ClientsSupportedPerFabric"))?),
419 _ => Err(ClusterError::UnexpectedType {
420 context: "ClientsSupportedPerFabric",
421 }),
422 }
423}
424
425pub fn decode_user_active_mode_trigger_hint(
430 tlv: &[u8],
431) -> Result<UserActiveModeTriggerBitmap, ClusterError> {
432 let mut r = TlvReader::new(tlv);
433 match r.next()? {
434 Some(Element::Scalar {
435 value: Value::Uint(v),
436 ..
437 }) => Ok(UserActiveModeTriggerBitmap::from_bits_retain(
438 u32::try_from(v)
439 .map_err(|_| ClusterError::InvalidLength("UserActiveModeTriggerHint"))?,
440 )),
441 _ => Err(ClusterError::UnexpectedType {
442 context: "UserActiveModeTriggerHint",
443 }),
444 }
445}
446
447pub fn decode_user_active_mode_trigger_instruction(tlv: &[u8]) -> Result<String, ClusterError> {
452 let mut r = TlvReader::new(tlv);
453 match r.next()? {
454 Some(Element::Scalar {
455 value: Value::Utf8(v),
456 ..
457 }) => Ok(v),
458 _ => Err(ClusterError::UnexpectedType {
459 context: "UserActiveModeTriggerInstruction",
460 }),
461 }
462}
463
464pub fn decode_operating_mode(tlv: &[u8]) -> Result<OperatingModeEnum, ClusterError> {
469 let mut r = TlvReader::new(tlv);
470 match r.next()? {
471 Some(Element::Scalar {
472 value: Value::Uint(v),
473 ..
474 }) => Ok(OperatingModeEnum::from_raw(
475 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("OperatingMode"))?,
476 )),
477 _ => Err(ClusterError::UnexpectedType {
478 context: "OperatingMode",
479 }),
480 }
481}
482
483pub fn decode_maximum_check_in_backoff(tlv: &[u8]) -> Result<u32, ClusterError> {
488 let mut r = TlvReader::new(tlv);
489 match r.next()? {
490 Some(Element::Scalar {
491 value: Value::Uint(v),
492 ..
493 }) => {
494 Ok(u32::try_from(v)
495 .map_err(|_| ClusterError::InvalidLength("MaximumCheckInBackoff"))?)
496 }
497 _ => Err(ClusterError::UnexpectedType {
498 context: "MaximumCheckInBackoff",
499 }),
500 }
501}
502
503#[must_use]
505#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_register_client(
507 check_in_node_id: u64,
508 monitored_subject: u64,
509 key: &Vec<u8>,
510 verification_key: Option<Vec<u8>>,
511 client_type: ClientTypeEnum,
512) -> Vec<u8> {
513 let mut buf = Vec::new();
514 let mut w = TlvWriter::new(&mut buf);
515 w.start_structure(Tag::Anonymous)
516 .expect("infallible: vec writer");
517 w.put_uint(Tag::Context(0), u64::from(check_in_node_id))
518 .expect("infallible: vec writer");
519 w.put_uint(Tag::Context(1), u64::from(monitored_subject))
520 .expect("infallible: vec writer");
521 w.put_bytes(Tag::Context(2), &key)
522 .expect("infallible: vec writer");
523 if let Some(verification_key) = verification_key {
524 w.put_bytes(Tag::Context(3), &verification_key)
525 .expect("infallible: vec writer");
526 }
527 w.put_uint(Tag::Context(4), u64::from(client_type.to_raw()))
528 .expect("infallible: vec writer");
529 w.end_container().expect("infallible: vec writer");
530 buf
531}
532
533#[derive(Clone, Debug, PartialEq)]
535#[non_exhaustive]
536pub struct RegisterClientResponse {
537 pub icd_counter: u32,
539}
540
541impl RegisterClientResponse {
542 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
548 let mut f_icd_counter: Option<u32> = None;
549 loop {
550 match r.next()? {
551 Some(Element::ContainerEnd) => break,
552 Some(Element::Scalar {
553 tag: Tag::Context(0),
554 value: Value::Uint(v),
555 }) => {
556 f_icd_counter = Some(
557 u32::try_from(v).map_err(|_| ClusterError::InvalidLength("IcdCounter"))?,
558 )
559 }
560 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
561 Some(Element::ContainerStart { .. }) => r.skip_container()?,
562 Some(_) => {} }
564 }
565 Ok(Self {
566 icd_counter: f_icd_counter.ok_or(ClusterError::MissingField("IcdCounter"))?,
567 })
568 }
569 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
574 let mut r = TlvReader::new(tlv);
575 match r.next()? {
576 Some(Element::ContainerStart {
577 kind: ContainerKind::Structure,
578 ..
579 }) => {}
580 _ => {
581 return Err(ClusterError::UnexpectedType {
582 context: "RegisterClientResponse",
583 })
584 }
585 }
586 Self::decode_from(&mut r)
587 }
588}
589
590#[must_use]
592#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_unregister_client(
594 check_in_node_id: u64,
595 verification_key: Option<Vec<u8>>,
596) -> Vec<u8> {
597 let mut buf = Vec::new();
598 let mut w = TlvWriter::new(&mut buf);
599 w.start_structure(Tag::Anonymous)
600 .expect("infallible: vec writer");
601 w.put_uint(Tag::Context(0), u64::from(check_in_node_id))
602 .expect("infallible: vec writer");
603 if let Some(verification_key) = verification_key {
604 w.put_bytes(Tag::Context(1), &verification_key)
605 .expect("infallible: vec writer");
606 }
607 w.end_container().expect("infallible: vec writer");
608 buf
609}
610
611#[must_use]
613#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_stay_active_request(stay_active_duration: u32) -> Vec<u8> {
615 let mut buf = Vec::new();
616 let mut w = TlvWriter::new(&mut buf);
617 w.start_structure(Tag::Anonymous)
618 .expect("infallible: vec writer");
619 w.put_uint(Tag::Context(0), u64::from(stay_active_duration))
620 .expect("infallible: vec writer");
621 w.end_container().expect("infallible: vec writer");
622 buf
623}
624
625#[derive(Clone, Debug, PartialEq)]
627#[non_exhaustive]
628pub struct StayActiveResponse {
629 pub promised_active_duration: u32,
631}
632
633impl StayActiveResponse {
634 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
640 let mut f_promised_active_duration: Option<u32> = None;
641 loop {
642 match r.next()? {
643 Some(Element::ContainerEnd) => break,
644 Some(Element::Scalar {
645 tag: Tag::Context(0),
646 value: Value::Uint(v),
647 }) => {
648 f_promised_active_duration = Some(
649 u32::try_from(v)
650 .map_err(|_| ClusterError::InvalidLength("PromisedActiveDuration"))?,
651 )
652 }
653 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
654 Some(Element::ContainerStart { .. }) => r.skip_container()?,
655 Some(_) => {} }
657 }
658 Ok(Self {
659 promised_active_duration: f_promised_active_duration
660 .ok_or(ClusterError::MissingField("PromisedActiveDuration"))?,
661 })
662 }
663 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
668 let mut r = TlvReader::new(tlv);
669 match r.next()? {
670 Some(Element::ContainerStart {
671 kind: ContainerKind::Structure,
672 ..
673 }) => {}
674 _ => {
675 return Err(ClusterError::UnexpectedType {
676 context: "StayActiveResponse",
677 })
678 }
679 }
680 Self::decode_from(&mut r)
681 }
682}