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 = 0x0008;
19pub const CLUSTER_REVISION: u16 = 7;
21
22pub mod command_id {
24 pub const MOVE_TO_LEVEL: u32 = 0x00;
26 pub const MOVE: u32 = 0x01;
28 pub const STEP: u32 = 0x02;
30 pub const STOP: u32 = 0x03;
32 pub const MOVE_TO_LEVEL_WITH_ON_OFF: u32 = 0x04;
34 pub const MOVE_WITH_ON_OFF: u32 = 0x05;
36 pub const STEP_WITH_ON_OFF: u32 = 0x06;
38 pub const STOP_WITH_ON_OFF: u32 = 0x07;
40 pub const MOVE_TO_CLOSEST_FREQUENCY: u32 = 0x08;
42}
43
44pub mod attribute_id {
46 pub const CURRENT_LEVEL: u32 = 0x0000;
48 pub const REMAINING_TIME: u32 = 0x0001;
50 pub const MIN_LEVEL: u32 = 0x0002;
52 pub const MAX_LEVEL: u32 = 0x0003;
54 pub const CURRENT_FREQUENCY: u32 = 0x0004;
56 pub const MIN_FREQUENCY: u32 = 0x0005;
58 pub const MAX_FREQUENCY: u32 = 0x0006;
60 pub const OPTIONS: u32 = 0x000F;
62 pub const ON_OFF_TRANSITION_TIME: u32 = 0x0010;
64 pub const ON_LEVEL: u32 = 0x0011;
66 pub const ON_TRANSITION_TIME: u32 = 0x0012;
68 pub const OFF_TRANSITION_TIME: u32 = 0x0013;
70 pub const DEFAULT_MOVE_RATE: u32 = 0x0014;
72 pub const START_UP_CURRENT_LEVEL: u32 = 0x4000;
74}
75
76bitflags::bitflags! {
77 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
79 pub struct Feature: u32 {
80 const OO = 1 << 0;
82 const LT = 1 << 1;
84 const FQ = 1 << 2;
86 }
87}
88
89#[derive(Copy, Clone, Debug, PartialEq, Eq)]
91pub enum MoveModeEnum {
92 Up,
94 Down,
96 Unknown(u8),
98}
99
100impl MoveModeEnum {
101 #[must_use]
103 pub fn from_raw(v: u8) -> Self {
104 match v {
105 0 => Self::Up,
106 1 => Self::Down,
107 other => Self::Unknown(other),
108 }
109 }
110 #[must_use]
112 pub fn to_raw(self) -> u8 {
113 match self {
114 Self::Up => 0,
115 Self::Down => 1,
116 Self::Unknown(v) => v,
117 }
118 }
119}
120
121bitflags::bitflags! {
122 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
124 pub struct OptionsBitmap: u8 {
125 const EXECUTE_IF_OFF = 1 << 0;
127 const COUPLE_COLOR_TEMP_TO_LEVEL = 1 << 1;
129 }
130}
131
132#[derive(Copy, Clone, Debug, PartialEq, Eq)]
134pub enum StepModeEnum {
135 Up,
137 Down,
139 Unknown(u8),
141}
142
143impl StepModeEnum {
144 #[must_use]
146 pub fn from_raw(v: u8) -> Self {
147 match v {
148 0 => Self::Up,
149 1 => Self::Down,
150 other => Self::Unknown(other),
151 }
152 }
153 #[must_use]
155 pub fn to_raw(self) -> u8 {
156 match self {
157 Self::Up => 0,
158 Self::Down => 1,
159 Self::Unknown(v) => v,
160 }
161 }
162}
163
164pub fn decode_current_level(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
169 let mut r = TlvReader::new(tlv);
170 match r.next()? {
171 Some(Element::Scalar {
172 value: Value::Null, ..
173 }) => Ok(Nullable::Null),
174 Some(Element::Scalar {
175 value: Value::Uint(v),
176 ..
177 }) => {
178 Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
179 ClusterError::InvalidLength("CurrentLevel")
180 })?))
181 }
182 _ => Err(ClusterError::UnexpectedType {
183 context: "CurrentLevel",
184 }),
185 }
186}
187
188pub fn decode_remaining_time(tlv: &[u8]) -> Result<u16, ClusterError> {
193 let mut r = TlvReader::new(tlv);
194 match r.next()? {
195 Some(Element::Scalar {
196 value: Value::Uint(v),
197 ..
198 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("RemainingTime"))?),
199 _ => Err(ClusterError::UnexpectedType {
200 context: "RemainingTime",
201 }),
202 }
203}
204
205pub fn decode_min_level(tlv: &[u8]) -> Result<u8, ClusterError> {
210 let mut r = TlvReader::new(tlv);
211 match r.next()? {
212 Some(Element::Scalar {
213 value: Value::Uint(v),
214 ..
215 }) => Ok(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("MinLevel"))?),
216 _ => Err(ClusterError::UnexpectedType {
217 context: "MinLevel",
218 }),
219 }
220}
221
222pub fn decode_max_level(tlv: &[u8]) -> Result<u8, ClusterError> {
227 let mut r = TlvReader::new(tlv);
228 match r.next()? {
229 Some(Element::Scalar {
230 value: Value::Uint(v),
231 ..
232 }) => Ok(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("MaxLevel"))?),
233 _ => Err(ClusterError::UnexpectedType {
234 context: "MaxLevel",
235 }),
236 }
237}
238
239pub fn decode_current_frequency(tlv: &[u8]) -> Result<u16, ClusterError> {
244 let mut r = TlvReader::new(tlv);
245 match r.next()? {
246 Some(Element::Scalar {
247 value: Value::Uint(v),
248 ..
249 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("CurrentFrequency"))?),
250 _ => Err(ClusterError::UnexpectedType {
251 context: "CurrentFrequency",
252 }),
253 }
254}
255
256pub fn decode_min_frequency(tlv: &[u8]) -> Result<u16, ClusterError> {
261 let mut r = TlvReader::new(tlv);
262 match r.next()? {
263 Some(Element::Scalar {
264 value: Value::Uint(v),
265 ..
266 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("MinFrequency"))?),
267 _ => Err(ClusterError::UnexpectedType {
268 context: "MinFrequency",
269 }),
270 }
271}
272
273pub fn decode_max_frequency(tlv: &[u8]) -> Result<u16, ClusterError> {
278 let mut r = TlvReader::new(tlv);
279 match r.next()? {
280 Some(Element::Scalar {
281 value: Value::Uint(v),
282 ..
283 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("MaxFrequency"))?),
284 _ => Err(ClusterError::UnexpectedType {
285 context: "MaxFrequency",
286 }),
287 }
288}
289
290pub fn decode_options(tlv: &[u8]) -> Result<OptionsBitmap, ClusterError> {
295 let mut r = TlvReader::new(tlv);
296 match r.next()? {
297 Some(Element::Scalar {
298 value: Value::Uint(v),
299 ..
300 }) => Ok(OptionsBitmap::from_bits_retain(
301 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Options"))?,
302 )),
303 _ => Err(ClusterError::UnexpectedType { context: "Options" }),
304 }
305}
306
307#[must_use]
309#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_options(value: OptionsBitmap) -> Vec<u8> {
311 let mut buf = Vec::new();
312 let mut w = TlvWriter::new(&mut buf);
313 w.put_uint(Tag::Anonymous, u64::from(value.bits()))
314 .expect("infallible: vec writer");
315 buf
316}
317
318pub fn decode_on_off_transition_time(tlv: &[u8]) -> Result<u16, ClusterError> {
323 let mut r = TlvReader::new(tlv);
324 match r.next()? {
325 Some(Element::Scalar {
326 value: Value::Uint(v),
327 ..
328 }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("OnOffTransitionTime"))?),
329 _ => Err(ClusterError::UnexpectedType {
330 context: "OnOffTransitionTime",
331 }),
332 }
333}
334
335#[must_use]
337#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_on_off_transition_time(value: u16) -> Vec<u8> {
339 let mut buf = Vec::new();
340 let mut w = TlvWriter::new(&mut buf);
341 w.put_uint(Tag::Anonymous, u64::from(value))
342 .expect("infallible: vec writer");
343 buf
344}
345
346pub fn decode_on_level(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
351 let mut r = TlvReader::new(tlv);
352 match r.next()? {
353 Some(Element::Scalar {
354 value: Value::Null, ..
355 }) => Ok(Nullable::Null),
356 Some(Element::Scalar {
357 value: Value::Uint(v),
358 ..
359 }) => Ok(Nullable::Value(
360 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("OnLevel"))?,
361 )),
362 _ => Err(ClusterError::UnexpectedType { context: "OnLevel" }),
363 }
364}
365
366#[must_use]
368#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_on_level(value: Nullable<u8>) -> Vec<u8> {
370 let mut buf = Vec::new();
371 let mut w = TlvWriter::new(&mut buf);
372 match value {
373 Nullable::Null => w.put_null(Tag::Anonymous).expect("infallible: vec writer"),
374 Nullable::Value(value) => {
375 w.put_uint(Tag::Anonymous, u64::from(value))
376 .expect("infallible: vec writer");
377 }
378 }
379 buf
380}
381
382pub fn decode_on_transition_time(tlv: &[u8]) -> Result<Nullable<u16>, ClusterError> {
387 let mut r = TlvReader::new(tlv);
388 match r.next()? {
389 Some(Element::Scalar {
390 value: Value::Null, ..
391 }) => Ok(Nullable::Null),
392 Some(Element::Scalar {
393 value: Value::Uint(v),
394 ..
395 }) => {
396 Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
397 ClusterError::InvalidLength("OnTransitionTime")
398 })?))
399 }
400 _ => Err(ClusterError::UnexpectedType {
401 context: "OnTransitionTime",
402 }),
403 }
404}
405
406#[must_use]
408#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_on_transition_time(value: Nullable<u16>) -> Vec<u8> {
410 let mut buf = Vec::new();
411 let mut w = TlvWriter::new(&mut buf);
412 match value {
413 Nullable::Null => w.put_null(Tag::Anonymous).expect("infallible: vec writer"),
414 Nullable::Value(value) => {
415 w.put_uint(Tag::Anonymous, u64::from(value))
416 .expect("infallible: vec writer");
417 }
418 }
419 buf
420}
421
422pub fn decode_off_transition_time(tlv: &[u8]) -> Result<Nullable<u16>, ClusterError> {
427 let mut r = TlvReader::new(tlv);
428 match r.next()? {
429 Some(Element::Scalar {
430 value: Value::Null, ..
431 }) => Ok(Nullable::Null),
432 Some(Element::Scalar {
433 value: Value::Uint(v),
434 ..
435 }) => {
436 Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
437 ClusterError::InvalidLength("OffTransitionTime")
438 })?))
439 }
440 _ => Err(ClusterError::UnexpectedType {
441 context: "OffTransitionTime",
442 }),
443 }
444}
445
446#[must_use]
448#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_off_transition_time(value: Nullable<u16>) -> Vec<u8> {
450 let mut buf = Vec::new();
451 let mut w = TlvWriter::new(&mut buf);
452 match value {
453 Nullable::Null => w.put_null(Tag::Anonymous).expect("infallible: vec writer"),
454 Nullable::Value(value) => {
455 w.put_uint(Tag::Anonymous, u64::from(value))
456 .expect("infallible: vec writer");
457 }
458 }
459 buf
460}
461
462pub fn decode_default_move_rate(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
467 let mut r = TlvReader::new(tlv);
468 match r.next()? {
469 Some(Element::Scalar {
470 value: Value::Null, ..
471 }) => Ok(Nullable::Null),
472 Some(Element::Scalar {
473 value: Value::Uint(v),
474 ..
475 }) => {
476 Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
477 ClusterError::InvalidLength("DefaultMoveRate")
478 })?))
479 }
480 _ => Err(ClusterError::UnexpectedType {
481 context: "DefaultMoveRate",
482 }),
483 }
484}
485
486#[must_use]
488#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_default_move_rate(value: Nullable<u8>) -> Vec<u8> {
490 let mut buf = Vec::new();
491 let mut w = TlvWriter::new(&mut buf);
492 match value {
493 Nullable::Null => w.put_null(Tag::Anonymous).expect("infallible: vec writer"),
494 Nullable::Value(value) => {
495 w.put_uint(Tag::Anonymous, u64::from(value))
496 .expect("infallible: vec writer");
497 }
498 }
499 buf
500}
501
502pub fn decode_start_up_current_level(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
507 let mut r = TlvReader::new(tlv);
508 match r.next()? {
509 Some(Element::Scalar {
510 value: Value::Null, ..
511 }) => Ok(Nullable::Null),
512 Some(Element::Scalar {
513 value: Value::Uint(v),
514 ..
515 }) => Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
516 ClusterError::InvalidLength("StartUpCurrentLevel")
517 })?)),
518 _ => Err(ClusterError::UnexpectedType {
519 context: "StartUpCurrentLevel",
520 }),
521 }
522}
523
524#[must_use]
526#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_start_up_current_level(value: Nullable<u8>) -> Vec<u8> {
528 let mut buf = Vec::new();
529 let mut w = TlvWriter::new(&mut buf);
530 match value {
531 Nullable::Null => w.put_null(Tag::Anonymous).expect("infallible: vec writer"),
532 Nullable::Value(value) => {
533 w.put_uint(Tag::Anonymous, u64::from(value))
534 .expect("infallible: vec writer");
535 }
536 }
537 buf
538}
539
540#[must_use]
542#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_move_to_level(
544 level: u8,
545 transition_time: Nullable<u16>,
546 options_mask: OptionsBitmap,
547 options_override: OptionsBitmap,
548) -> Vec<u8> {
549 let mut buf = Vec::new();
550 let mut w = TlvWriter::new(&mut buf);
551 w.start_structure(Tag::Anonymous)
552 .expect("infallible: vec writer");
553 w.put_uint(Tag::Context(0), u64::from(level))
554 .expect("infallible: vec writer");
555 match transition_time {
556 Nullable::Null => w.put_null(Tag::Context(1)).expect("infallible: vec writer"),
557 Nullable::Value(transition_time) => {
558 w.put_uint(Tag::Context(1), u64::from(transition_time))
559 .expect("infallible: vec writer");
560 }
561 }
562 w.put_uint(Tag::Context(2), u64::from(options_mask.bits()))
563 .expect("infallible: vec writer");
564 w.put_uint(Tag::Context(3), u64::from(options_override.bits()))
565 .expect("infallible: vec writer");
566 w.end_container().expect("infallible: vec writer");
567 buf
568}
569
570#[must_use]
572#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_move(
574 move_mode: MoveModeEnum,
575 rate: Nullable<u8>,
576 options_mask: OptionsBitmap,
577 options_override: OptionsBitmap,
578) -> Vec<u8> {
579 let mut buf = Vec::new();
580 let mut w = TlvWriter::new(&mut buf);
581 w.start_structure(Tag::Anonymous)
582 .expect("infallible: vec writer");
583 w.put_uint(Tag::Context(0), u64::from(move_mode.to_raw()))
584 .expect("infallible: vec writer");
585 match rate {
586 Nullable::Null => w.put_null(Tag::Context(1)).expect("infallible: vec writer"),
587 Nullable::Value(rate) => {
588 w.put_uint(Tag::Context(1), u64::from(rate))
589 .expect("infallible: vec writer");
590 }
591 }
592 w.put_uint(Tag::Context(2), u64::from(options_mask.bits()))
593 .expect("infallible: vec writer");
594 w.put_uint(Tag::Context(3), u64::from(options_override.bits()))
595 .expect("infallible: vec writer");
596 w.end_container().expect("infallible: vec writer");
597 buf
598}
599
600#[must_use]
602#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_step(
604 step_mode: StepModeEnum,
605 step_size: u8,
606 transition_time: Nullable<u16>,
607 options_mask: OptionsBitmap,
608 options_override: OptionsBitmap,
609) -> Vec<u8> {
610 let mut buf = Vec::new();
611 let mut w = TlvWriter::new(&mut buf);
612 w.start_structure(Tag::Anonymous)
613 .expect("infallible: vec writer");
614 w.put_uint(Tag::Context(0), u64::from(step_mode.to_raw()))
615 .expect("infallible: vec writer");
616 w.put_uint(Tag::Context(1), u64::from(step_size))
617 .expect("infallible: vec writer");
618 match transition_time {
619 Nullable::Null => w.put_null(Tag::Context(2)).expect("infallible: vec writer"),
620 Nullable::Value(transition_time) => {
621 w.put_uint(Tag::Context(2), u64::from(transition_time))
622 .expect("infallible: vec writer");
623 }
624 }
625 w.put_uint(Tag::Context(3), u64::from(options_mask.bits()))
626 .expect("infallible: vec writer");
627 w.put_uint(Tag::Context(4), u64::from(options_override.bits()))
628 .expect("infallible: vec writer");
629 w.end_container().expect("infallible: vec writer");
630 buf
631}
632
633#[must_use]
635#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_stop(options_mask: OptionsBitmap, options_override: OptionsBitmap) -> Vec<u8> {
637 let mut buf = Vec::new();
638 let mut w = TlvWriter::new(&mut buf);
639 w.start_structure(Tag::Anonymous)
640 .expect("infallible: vec writer");
641 w.put_uint(Tag::Context(0), u64::from(options_mask.bits()))
642 .expect("infallible: vec writer");
643 w.put_uint(Tag::Context(1), u64::from(options_override.bits()))
644 .expect("infallible: vec writer");
645 w.end_container().expect("infallible: vec writer");
646 buf
647}
648
649#[must_use]
651#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_move_to_level_with_on_off() -> Vec<u8> {
653 let mut buf = Vec::new();
654 let mut w = TlvWriter::new(&mut buf);
655 w.start_structure(Tag::Anonymous)
656 .expect("infallible: vec writer");
657 w.end_container().expect("infallible: vec writer");
658 buf
659}
660
661#[must_use]
663#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_move_with_on_off() -> Vec<u8> {
665 let mut buf = Vec::new();
666 let mut w = TlvWriter::new(&mut buf);
667 w.start_structure(Tag::Anonymous)
668 .expect("infallible: vec writer");
669 w.end_container().expect("infallible: vec writer");
670 buf
671}
672
673#[must_use]
675#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_step_with_on_off() -> Vec<u8> {
677 let mut buf = Vec::new();
678 let mut w = TlvWriter::new(&mut buf);
679 w.start_structure(Tag::Anonymous)
680 .expect("infallible: vec writer");
681 w.end_container().expect("infallible: vec writer");
682 buf
683}
684
685#[must_use]
687#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_stop_with_on_off() -> Vec<u8> {
689 let mut buf = Vec::new();
690 let mut w = TlvWriter::new(&mut buf);
691 w.start_structure(Tag::Anonymous)
692 .expect("infallible: vec writer");
693 w.end_container().expect("infallible: vec writer");
694 buf
695}
696
697#[must_use]
699#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_move_to_closest_frequency(frequency: u16) -> Vec<u8> {
701 let mut buf = Vec::new();
702 let mut w = TlvWriter::new(&mut buf);
703 w.start_structure(Tag::Anonymous)
704 .expect("infallible: vec writer");
705 w.put_uint(Tag::Context(0), u64::from(frequency))
706 .expect("infallible: vec writer");
707 w.end_container().expect("infallible: vec writer");
708 buf
709}