matc/clusters/codec/
group_key_management_cluster.rs

1//! Matter TLV encoders and decoders for Group Key Management Cluster
2//! Cluster ID: 0x003F
3//!
4//! This file is automatically generated from Group-Key-Management-Cluster.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Import serialization helpers for octet strings
12use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
13
14// Enum definitions
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
17#[repr(u8)]
18pub enum GroupKeyMulticastPolicy {
19    /// Indicates filtering of multicast messages for a specific Group ID
20    Pergroupid = 0,
21    /// Indicates not filtering of multicast messages
22    Allnodes = 1,
23}
24
25impl GroupKeyMulticastPolicy {
26    /// Convert from u8 value
27    pub fn from_u8(value: u8) -> Option<Self> {
28        match value {
29            0 => Some(GroupKeyMulticastPolicy::Pergroupid),
30            1 => Some(GroupKeyMulticastPolicy::Allnodes),
31            _ => None,
32        }
33    }
34
35    /// Convert to u8 value
36    pub fn to_u8(self) -> u8 {
37        self as u8
38    }
39}
40
41impl From<GroupKeyMulticastPolicy> for u8 {
42    fn from(val: GroupKeyMulticastPolicy) -> Self {
43        val as u8
44    }
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
48#[repr(u8)]
49pub enum GroupKeySecurityPolicy {
50    /// Message counter synchronization using trust-first
51    Trustfirst = 0,
52    /// Message counter synchronization using cache-and-sync
53    Cacheandsync = 1,
54}
55
56impl GroupKeySecurityPolicy {
57    /// Convert from u8 value
58    pub fn from_u8(value: u8) -> Option<Self> {
59        match value {
60            0 => Some(GroupKeySecurityPolicy::Trustfirst),
61            1 => Some(GroupKeySecurityPolicy::Cacheandsync),
62            _ => None,
63        }
64    }
65
66    /// Convert to u8 value
67    pub fn to_u8(self) -> u8 {
68        self as u8
69    }
70}
71
72impl From<GroupKeySecurityPolicy> for u8 {
73    fn from(val: GroupKeySecurityPolicy) -> Self {
74        val as u8
75    }
76}
77
78// Struct definitions
79
80#[derive(Debug, serde::Serialize)]
81pub struct GroupInfoMap {
82    pub group_id: Option<u8>,
83    pub endpoints: Option<Vec<u16>>,
84    pub group_name: Option<String>,
85}
86
87#[derive(Debug, serde::Serialize)]
88pub struct GroupKeyMap {
89    pub group_id: Option<u8>,
90    pub group_key_set_id: Option<u16>,
91}
92
93#[derive(Debug, serde::Serialize)]
94pub struct GroupKeySet {
95    pub group_key_set_id: Option<u16>,
96    pub group_key_security_policy: Option<GroupKeySecurityPolicy>,
97    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
98    pub epoch_key0: Option<Vec<u8>>,
99    pub epoch_start_time0: Option<u64>,
100    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
101    pub epoch_key1: Option<Vec<u8>>,
102    pub epoch_start_time1: Option<u64>,
103    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
104    pub epoch_key2: Option<Vec<u8>>,
105    pub epoch_start_time2: Option<u64>,
106    pub group_key_multicast_policy: Option<GroupKeyMulticastPolicy>,
107}
108
109// Command encoders
110
111/// Encode KeySetWrite command (0x00)
112pub fn encode_key_set_write(group_key_set: GroupKeySet) -> anyhow::Result<Vec<u8>> {
113            // Encode struct GroupKeySetStruct
114            let mut group_key_set_fields = Vec::new();
115            if let Some(x) = group_key_set.group_key_set_id { group_key_set_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
116            if let Some(x) = group_key_set.group_key_security_policy { group_key_set_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
117            if let Some(x) = group_key_set.epoch_key0 { group_key_set_fields.push((2, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
118            if let Some(x) = group_key_set.epoch_start_time0 { group_key_set_fields.push((3, tlv::TlvItemValueEnc::UInt64(x)).into()); }
119            if let Some(x) = group_key_set.epoch_key1 { group_key_set_fields.push((4, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
120            if let Some(x) = group_key_set.epoch_start_time1 { group_key_set_fields.push((5, tlv::TlvItemValueEnc::UInt64(x)).into()); }
121            if let Some(x) = group_key_set.epoch_key2 { group_key_set_fields.push((6, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
122            if let Some(x) = group_key_set.epoch_start_time2 { group_key_set_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
123            if let Some(x) = group_key_set.group_key_multicast_policy { group_key_set_fields.push((8, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
124    let tlv = tlv::TlvItemEnc {
125        tag: 0,
126        value: tlv::TlvItemValueEnc::StructInvisible(vec![
127        (0, tlv::TlvItemValueEnc::StructInvisible(group_key_set_fields)).into(),
128        ]),
129    };
130    Ok(tlv.encode()?)
131}
132
133/// Encode KeySetRead command (0x01)
134pub fn encode_key_set_read(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
135    let tlv = tlv::TlvItemEnc {
136        tag: 0,
137        value: tlv::TlvItemValueEnc::StructInvisible(vec![
138        (0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
139        ]),
140    };
141    Ok(tlv.encode()?)
142}
143
144/// Encode KeySetRemove command (0x03)
145pub fn encode_key_set_remove(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
146    let tlv = tlv::TlvItemEnc {
147        tag: 0,
148        value: tlv::TlvItemValueEnc::StructInvisible(vec![
149        (0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
150        ]),
151    };
152    Ok(tlv.encode()?)
153}
154
155/// Encode KeySetReadAllIndices command (0x04)
156pub fn encode_key_set_read_all_indices(do_not_use: u8) -> anyhow::Result<Vec<u8>> {
157    let tlv = tlv::TlvItemEnc {
158        tag: 0,
159        value: tlv::TlvItemValueEnc::StructInvisible(vec![
160        (0, tlv::TlvItemValueEnc::UInt8(do_not_use)).into(),
161        ]),
162    };
163    Ok(tlv.encode()?)
164}
165
166// Attribute decoders
167
168/// Decode GroupKeyMap attribute (0x0000)
169pub fn decode_group_key_map(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<GroupKeyMap>> {
170    let mut res = Vec::new();
171    if let tlv::TlvItemValue::List(v) = inp {
172        for item in v {
173            res.push(GroupKeyMap {
174                group_id: item.get_int(&[1]).map(|v| v as u8),
175                group_key_set_id: item.get_int(&[2]).map(|v| v as u16),
176            });
177        }
178    }
179    Ok(res)
180}
181
182/// Decode GroupTable attribute (0x0001)
183pub fn decode_group_table(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<GroupInfoMap>> {
184    let mut res = Vec::new();
185    if let tlv::TlvItemValue::List(v) = inp {
186        for item in v {
187            res.push(GroupInfoMap {
188                group_id: item.get_int(&[1]).map(|v| v as u8),
189                endpoints: {
190                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
191                        let items: Vec<u16> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u16) } else { None } }).collect();
192                        Some(items)
193                    } else {
194                        None
195                    }
196                },
197                group_name: item.get_string_owned(&[3]),
198            });
199        }
200    }
201    Ok(res)
202}
203
204/// Decode MaxGroupsPerFabric attribute (0x0002)
205pub fn decode_max_groups_per_fabric(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
206    if let tlv::TlvItemValue::Int(v) = inp {
207        Ok(*v as u16)
208    } else {
209        Err(anyhow::anyhow!("Expected UInt16"))
210    }
211}
212
213/// Decode MaxGroupKeysPerFabric attribute (0x0003)
214pub fn decode_max_group_keys_per_fabric(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
215    if let tlv::TlvItemValue::Int(v) = inp {
216        Ok(*v as u16)
217    } else {
218        Err(anyhow::anyhow!("Expected UInt16"))
219    }
220}
221
222
223// JSON dispatcher function
224
225/// Decode attribute value and return as JSON string
226///
227/// # Parameters
228/// * `cluster_id` - The cluster identifier
229/// * `attribute_id` - The attribute identifier
230/// * `tlv_value` - The TLV value to decode
231///
232/// # Returns
233/// JSON string representation of the decoded value or error
234pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
235    // Verify this is the correct cluster
236    if cluster_id != 0x003F {
237        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x003F, got {}\"}}", cluster_id);
238    }
239
240    match attribute_id {
241        0x0000 => {
242            match decode_group_key_map(tlv_value) {
243                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
244                Err(e) => format!("{{\"error\": \"{}\"}}", e),
245            }
246        }
247        0x0001 => {
248            match decode_group_table(tlv_value) {
249                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
250                Err(e) => format!("{{\"error\": \"{}\"}}", e),
251            }
252        }
253        0x0002 => {
254            match decode_max_groups_per_fabric(tlv_value) {
255                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
256                Err(e) => format!("{{\"error\": \"{}\"}}", e),
257            }
258        }
259        0x0003 => {
260            match decode_max_group_keys_per_fabric(tlv_value) {
261                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
262                Err(e) => format!("{{\"error\": \"{}\"}}", e),
263            }
264        }
265        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
266    }
267}
268
269/// Get list of all attributes supported by this cluster
270///
271/// # Returns
272/// Vector of tuples containing (attribute_id, attribute_name)
273pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
274    vec![
275        (0x0000, "GroupKeyMap"),
276        (0x0001, "GroupTable"),
277        (0x0002, "MaxGroupsPerFabric"),
278        (0x0003, "MaxGroupKeysPerFabric"),
279    ]
280}
281
282#[derive(Debug, serde::Serialize)]
283pub struct KeySetReadResponse {
284    pub group_key_set: Option<GroupKeySet>,
285}
286
287#[derive(Debug, serde::Serialize)]
288pub struct KeySetReadAllIndicesResponse {
289    pub group_key_set_i_ds: Option<Vec<u16>>,
290}
291
292// Command response decoders
293
294/// Decode KeySetReadResponse command response (02)
295pub fn decode_key_set_read_response(inp: &tlv::TlvItemValue) -> anyhow::Result<KeySetReadResponse> {
296    if let tlv::TlvItemValue::List(_fields) = inp {
297        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
298        Ok(KeySetReadResponse {
299                group_key_set: {
300                    if let Some(nested_tlv) = item.get(&[0]) {
301                        if let tlv::TlvItemValue::List(_) = nested_tlv {
302                            let nested_item = tlv::TlvItem { tag: 0, value: nested_tlv.clone() };
303                            Some(GroupKeySet {
304                group_key_set_id: nested_item.get_int(&[0]).map(|v| v as u16),
305                group_key_security_policy: nested_item.get_int(&[1]).and_then(|v| GroupKeySecurityPolicy::from_u8(v as u8)),
306                epoch_key0: nested_item.get_octet_string_owned(&[2]),
307                epoch_start_time0: nested_item.get_int(&[3]),
308                epoch_key1: nested_item.get_octet_string_owned(&[4]),
309                epoch_start_time1: nested_item.get_int(&[5]),
310                epoch_key2: nested_item.get_octet_string_owned(&[6]),
311                epoch_start_time2: nested_item.get_int(&[7]),
312                group_key_multicast_policy: nested_item.get_int(&[8]).and_then(|v| GroupKeyMulticastPolicy::from_u8(v as u8)),
313                            })
314                        } else {
315                            None
316                        }
317                    } else {
318                        None
319                    }
320                },
321        })
322    } else {
323        Err(anyhow::anyhow!("Expected struct fields"))
324    }
325}
326
327/// Decode KeySetReadAllIndicesResponse command response (05)
328pub fn decode_key_set_read_all_indices_response(inp: &tlv::TlvItemValue) -> anyhow::Result<KeySetReadAllIndicesResponse> {
329    if let tlv::TlvItemValue::List(_fields) = inp {
330        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
331        Ok(KeySetReadAllIndicesResponse {
332                group_key_set_i_ds: {
333                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
334                        let items: Vec<u16> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u16) } else { None } }).collect();
335                        Some(items)
336                    } else {
337                        None
338                    }
339                },
340        })
341    } else {
342        Err(anyhow::anyhow!("Expected struct fields"))
343    }
344}
345