matter_controller/
binding.rs1use matter_codec::{Tag, Value};
6use matter_interaction::AttributePath;
7
8pub(crate) const BINDING_CLUSTER: u32 = 0x001E;
10pub(crate) const ATTR_BINDING: u32 = 0x0000;
12
13#[derive(Clone, Debug, PartialEq, Eq)]
17#[non_exhaustive]
18pub struct BindingTarget {
19 pub node: Option<u64>,
21 pub group: Option<u16>,
23 pub endpoint: Option<u16>,
25 pub cluster: Option<u32>,
27}
28
29impl BindingTarget {
30 #[must_use]
33 pub fn new(
34 node: Option<u64>,
35 group: Option<u16>,
36 endpoint: Option<u16>,
37 cluster: Option<u32>,
38 ) -> Self {
39 Self {
40 node,
41 group,
42 endpoint,
43 cluster,
44 }
45 }
46}
47
48pub(crate) fn binding_target_value(t: &BindingTarget) -> Value {
51 let mut m = Vec::new();
52 if let Some(n) = t.node {
53 m.push((Tag::Context(1), Value::Uint(n)));
54 }
55 if let Some(g) = t.group {
56 m.push((Tag::Context(2), Value::Uint(u64::from(g))));
57 }
58 if let Some(e) = t.endpoint {
59 m.push((Tag::Context(3), Value::Uint(u64::from(e))));
60 }
61 if let Some(c) = t.cluster {
62 m.push((Tag::Context(4), Value::Uint(u64::from(c))));
63 }
64 Value::Structure(m)
65}
66
67pub(crate) fn parse_bindings(reports: &[(AttributePath, Value)]) -> Vec<BindingTarget> {
70 let mut out = Vec::new();
71 for (p, v) in reports {
72 if p.cluster != BINDING_CLUSTER || p.attribute != ATTR_BINDING {
73 continue;
74 }
75 if let Value::Array(entries) = v {
76 for entry in entries {
77 if let Value::Structure(members) = entry {
78 let mut t = BindingTarget::new(None, None, None, None);
79 for (tag, val) in members {
80 match (*tag, val) {
81 (Tag::Context(1), Value::Uint(n)) => t.node = Some(*n),
82 (Tag::Context(2), Value::Uint(g)) => t.group = u16::try_from(*g).ok(),
83 (Tag::Context(3), Value::Uint(e)) => {
84 t.endpoint = u16::try_from(*e).ok();
85 }
86 (Tag::Context(4), Value::Uint(c)) => {
87 t.cluster = u32::try_from(*c).ok();
88 }
89 _ => {}
90 }
91 }
92 out.push(t);
93 }
94 }
95 }
96 }
97 out
98}
99
100#[cfg(test)]
101mod tests {
102 #![allow(clippy::unwrap_used, clippy::expect_used)] use super::*;
104
105 #[test]
106 fn target_value_and_parse_roundtrip() {
107 let targets = vec![
108 BindingTarget::new(Some(0x1122), None, Some(1), Some(0x0006)), BindingTarget::new(None, Some(0x0007), None, Some(0x0006)), ];
111 let list = Value::Array(targets.iter().map(binding_target_value).collect());
113 let reports = vec![(
114 AttributePath {
115 endpoint: 1,
116 cluster: BINDING_CLUSTER,
117 attribute: ATTR_BINDING,
118 },
119 list,
120 )];
121 assert_eq!(parse_bindings(&reports), targets);
122 }
123}