Skip to main content

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
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Import serialization helpers for octet strings
14use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
15
16// Enum definitions
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum GroupKeyMulticastPolicy {
21    /// Indicates filtering of multicast messages for a specific Group ID
22    Pergroupid = 0,
23    /// Indicates not filtering of multicast messages
24    Allnodes = 1,
25}
26
27impl GroupKeyMulticastPolicy {
28    /// Convert from u8 value
29    pub fn from_u8(value: u8) -> Option<Self> {
30        match value {
31            0 => Some(GroupKeyMulticastPolicy::Pergroupid),
32            1 => Some(GroupKeyMulticastPolicy::Allnodes),
33            _ => None,
34        }
35    }
36
37    /// Convert to u8 value
38    pub fn to_u8(self) -> u8 {
39        self as u8
40    }
41}
42
43impl From<GroupKeyMulticastPolicy> for u8 {
44    fn from(val: GroupKeyMulticastPolicy) -> Self {
45        val as u8
46    }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
50#[repr(u8)]
51pub enum GroupKeySecurityPolicy {
52    /// Message counter synchronization using trust-first
53    Trustfirst = 0,
54    /// Message counter synchronization using cache-and-sync
55    Cacheandsync = 1,
56}
57
58impl GroupKeySecurityPolicy {
59    /// Convert from u8 value
60    pub fn from_u8(value: u8) -> Option<Self> {
61        match value {
62            0 => Some(GroupKeySecurityPolicy::Trustfirst),
63            1 => Some(GroupKeySecurityPolicy::Cacheandsync),
64            _ => None,
65        }
66    }
67
68    /// Convert to u8 value
69    pub fn to_u8(self) -> u8 {
70        self as u8
71    }
72}
73
74impl From<GroupKeySecurityPolicy> for u8 {
75    fn from(val: GroupKeySecurityPolicy) -> Self {
76        val as u8
77    }
78}
79
80// Struct definitions
81
82#[derive(Debug, serde::Serialize)]
83pub struct GroupInfoMap {
84    pub group_id: Option<u16>,
85    pub endpoints: Option<Vec<u16>>,
86    pub group_name: Option<String>,
87}
88
89#[derive(Debug, serde::Serialize)]
90pub struct GroupKeyMap {
91    pub group_id: Option<u16>,
92    pub group_key_set_id: Option<u16>,
93}
94
95#[derive(Debug, serde::Serialize)]
96pub struct GroupKeySet {
97    pub group_key_set_id: Option<u16>,
98    pub group_key_security_policy: Option<GroupKeySecurityPolicy>,
99    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
100    pub epoch_key0: Option<Vec<u8>>,
101    pub epoch_start_time0: Option<u64>,
102    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
103    pub epoch_key1: Option<Vec<u8>>,
104    pub epoch_start_time1: Option<u64>,
105    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
106    pub epoch_key2: Option<Vec<u8>>,
107    pub epoch_start_time2: Option<u64>,
108    pub group_key_multicast_policy: Option<GroupKeyMulticastPolicy>,
109}
110
111#[derive(Debug, serde::Serialize)]
112pub struct GroupcastAdoption {
113    pub groupcast_adopted: Option<bool>,
114}
115
116// Command encoders
117
118/// Encode KeySetWrite command (0x00)
119pub fn encode_key_set_write(group_key_set: GroupKeySet) -> anyhow::Result<Vec<u8>> {
120            // Encode struct GroupKeySetStruct
121            let mut group_key_set_fields = Vec::new();
122            if let Some(x) = group_key_set.group_key_set_id { group_key_set_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
123            if let Some(x) = group_key_set.group_key_security_policy { group_key_set_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
124            if let Some(x) = group_key_set.epoch_key0 { group_key_set_fields.push((2, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
125            if let Some(x) = group_key_set.epoch_start_time0 { group_key_set_fields.push((3, tlv::TlvItemValueEnc::UInt64(x)).into()); }
126            if let Some(x) = group_key_set.epoch_key1 { group_key_set_fields.push((4, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
127            if let Some(x) = group_key_set.epoch_start_time1 { group_key_set_fields.push((5, tlv::TlvItemValueEnc::UInt64(x)).into()); }
128            if let Some(x) = group_key_set.epoch_key2 { group_key_set_fields.push((6, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
129            if let Some(x) = group_key_set.epoch_start_time2 { group_key_set_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
130            if let Some(x) = group_key_set.group_key_multicast_policy { group_key_set_fields.push((8, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
131    let tlv = tlv::TlvItemEnc {
132        tag: 0,
133        value: tlv::TlvItemValueEnc::StructInvisible(vec![
134        (0, tlv::TlvItemValueEnc::StructInvisible(group_key_set_fields)).into(),
135        ]),
136    };
137    Ok(tlv.encode()?)
138}
139
140/// Encode KeySetRead command (0x01)
141pub fn encode_key_set_read(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
142    let tlv = tlv::TlvItemEnc {
143        tag: 0,
144        value: tlv::TlvItemValueEnc::StructInvisible(vec![
145        (0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
146        ]),
147    };
148    Ok(tlv.encode()?)
149}
150
151/// Encode KeySetRemove command (0x03)
152pub fn encode_key_set_remove(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
153    let tlv = tlv::TlvItemEnc {
154        tag: 0,
155        value: tlv::TlvItemValueEnc::StructInvisible(vec![
156        (0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
157        ]),
158    };
159    Ok(tlv.encode()?)
160}
161
162/// Encode KeySetReadAllIndices command (0x04)
163pub fn encode_key_set_read_all_indices(do_not_use: Option<u8>) -> anyhow::Result<Vec<u8>> {
164    let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
165    if let Some(x) = do_not_use { tlv_fields.push((0, tlv::TlvItemValueEnc::UInt8(x)).into()); }
166    let tlv = tlv::TlvItemEnc {
167        tag: 0,
168        value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
169    };
170    Ok(tlv.encode()?)
171}
172
173// Attribute decoders
174
175/// Decode GroupKeyMap attribute (0x0000)
176pub fn decode_group_key_map(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<GroupKeyMap>> {
177    let mut res = Vec::new();
178    if let tlv::TlvItemValue::List(v) = inp {
179        for item in v {
180            res.push(GroupKeyMap {
181                group_id: item.get_int(&[1]).map(|v| v as u16),
182                group_key_set_id: item.get_int(&[2]).map(|v| v as u16),
183            });
184        }
185    }
186    Ok(res)
187}
188
189/// Decode GroupTable attribute (0x0001)
190pub fn decode_group_table(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<GroupInfoMap>> {
191    let mut res = Vec::new();
192    if let tlv::TlvItemValue::List(v) = inp {
193        for item in v {
194            res.push(GroupInfoMap {
195                group_id: item.get_int(&[1]).map(|v| v as u16),
196                endpoints: {
197                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
198                        let items: Vec<u16> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u16) } else { None } }).collect();
199                        Some(items)
200                    } else {
201                        None
202                    }
203                },
204                group_name: item.get_string_owned(&[3]),
205            });
206        }
207    }
208    Ok(res)
209}
210
211/// Decode MaxGroupsPerFabric attribute (0x0002)
212pub fn decode_max_groups_per_fabric(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
213    if let tlv::TlvItemValue::Int(v) = inp {
214        Ok(*v as u16)
215    } else {
216        Err(anyhow::anyhow!("Expected UInt16"))
217    }
218}
219
220/// Decode MaxGroupKeysPerFabric attribute (0x0003)
221pub fn decode_max_group_keys_per_fabric(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
222    if let tlv::TlvItemValue::Int(v) = inp {
223        Ok(*v as u16)
224    } else {
225        Err(anyhow::anyhow!("Expected UInt16"))
226    }
227}
228
229/// Decode GroupcastAdoption attribute (0x0004)
230pub fn decode_groupcast_adoption(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<GroupcastAdoption>> {
231    let mut res = Vec::new();
232    if let tlv::TlvItemValue::List(v) = inp {
233        for item in v {
234            res.push(GroupcastAdoption {
235                groupcast_adopted: item.get_bool(&[0]),
236            });
237        }
238    }
239    Ok(res)
240}
241
242
243// JSON dispatcher function
244
245/// Decode attribute value and return as JSON string
246///
247/// # Parameters
248/// * `cluster_id` - The cluster identifier
249/// * `attribute_id` - The attribute identifier
250/// * `tlv_value` - The TLV value to decode
251///
252/// # Returns
253/// JSON string representation of the decoded value or error
254pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
255    // Verify this is the correct cluster
256    if cluster_id != 0x003F {
257        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x003F, got {}\"}}", cluster_id);
258    }
259
260    match attribute_id {
261        0x0000 => {
262            match decode_group_key_map(tlv_value) {
263                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
264                Err(e) => format!("{{\"error\": \"{}\"}}", e),
265            }
266        }
267        0x0001 => {
268            match decode_group_table(tlv_value) {
269                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
270                Err(e) => format!("{{\"error\": \"{}\"}}", e),
271            }
272        }
273        0x0002 => {
274            match decode_max_groups_per_fabric(tlv_value) {
275                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
276                Err(e) => format!("{{\"error\": \"{}\"}}", e),
277            }
278        }
279        0x0003 => {
280            match decode_max_group_keys_per_fabric(tlv_value) {
281                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
282                Err(e) => format!("{{\"error\": \"{}\"}}", e),
283            }
284        }
285        0x0004 => {
286            match decode_groupcast_adoption(tlv_value) {
287                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
288                Err(e) => format!("{{\"error\": \"{}\"}}", e),
289            }
290        }
291        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
292    }
293}
294
295/// Get list of all attributes supported by this cluster
296///
297/// # Returns
298/// Vector of tuples containing (attribute_id, attribute_name)
299pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
300    vec![
301        (0x0000, "GroupKeyMap"),
302        (0x0001, "GroupTable"),
303        (0x0002, "MaxGroupsPerFabric"),
304        (0x0003, "MaxGroupKeysPerFabric"),
305        (0x0004, "GroupcastAdoption"),
306    ]
307}
308
309// Command listing
310
311pub fn get_command_list() -> Vec<(u32, &'static str)> {
312    vec![
313        (0x00, "KeySetWrite"),
314        (0x01, "KeySetRead"),
315        (0x03, "KeySetRemove"),
316        (0x04, "KeySetReadAllIndices"),
317    ]
318}
319
320pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
321    match cmd_id {
322        0x00 => Some("KeySetWrite"),
323        0x01 => Some("KeySetRead"),
324        0x03 => Some("KeySetRemove"),
325        0x04 => Some("KeySetReadAllIndices"),
326        _ => None,
327    }
328}
329
330pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
331    match cmd_id {
332        0x00 => Some(vec![
333            crate::clusters::codec::CommandField { tag: 0, name: "group_key_set", kind: crate::clusters::codec::FieldKind::Struct { name: "GroupKeySetStruct" }, optional: false, nullable: false },
334        ]),
335        0x01 => Some(vec![
336            crate::clusters::codec::CommandField { tag: 0, name: "group_key_set_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
337        ]),
338        0x03 => Some(vec![
339            crate::clusters::codec::CommandField { tag: 0, name: "group_key_set_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
340        ]),
341        0x04 => Some(vec![
342            crate::clusters::codec::CommandField { tag: 0, name: "do_not_use", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
343        ]),
344        _ => None,
345    }
346}
347
348pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
349    match cmd_id {
350        0x00 => Err(anyhow::anyhow!("command \"KeySetWrite\" has complex args: use raw mode")),
351        0x01 => {
352        let group_key_set_id = crate::clusters::codec::json_util::get_u16(args, "group_key_set_id")?;
353        encode_key_set_read(group_key_set_id)
354        }
355        0x03 => {
356        let group_key_set_id = crate::clusters::codec::json_util::get_u16(args, "group_key_set_id")?;
357        encode_key_set_remove(group_key_set_id)
358        }
359        0x04 => {
360        let do_not_use = crate::clusters::codec::json_util::get_opt_u8(args, "do_not_use")?;
361        encode_key_set_read_all_indices(do_not_use)
362        }
363        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
364    }
365}
366
367#[derive(Debug, serde::Serialize)]
368pub struct KeySetReadResponse {
369    pub group_key_set: Option<GroupKeySet>,
370}
371
372#[derive(Debug, serde::Serialize)]
373pub struct KeySetReadAllIndicesResponse {
374    pub group_key_set_i_ds: Option<Vec<u16>>,
375}
376
377// Command response decoders
378
379/// Decode KeySetReadResponse command response (02)
380pub fn decode_key_set_read_response(inp: &tlv::TlvItemValue) -> anyhow::Result<KeySetReadResponse> {
381    if let tlv::TlvItemValue::List(_fields) = inp {
382        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
383        Ok(KeySetReadResponse {
384                group_key_set: {
385                    if let Some(nested_tlv) = item.get(&[0]) {
386                        if let tlv::TlvItemValue::List(_) = nested_tlv {
387                            let nested_item = tlv::TlvItem { tag: 0, value: nested_tlv.clone() };
388                            Some(GroupKeySet {
389                group_key_set_id: nested_item.get_int(&[0]).map(|v| v as u16),
390                group_key_security_policy: nested_item.get_int(&[1]).and_then(|v| GroupKeySecurityPolicy::from_u8(v as u8)),
391                epoch_key0: nested_item.get_octet_string_owned(&[2]),
392                epoch_start_time0: nested_item.get_int(&[3]),
393                epoch_key1: nested_item.get_octet_string_owned(&[4]),
394                epoch_start_time1: nested_item.get_int(&[5]),
395                epoch_key2: nested_item.get_octet_string_owned(&[6]),
396                epoch_start_time2: nested_item.get_int(&[7]),
397                group_key_multicast_policy: nested_item.get_int(&[8]).and_then(|v| GroupKeyMulticastPolicy::from_u8(v as u8)),
398                            })
399                        } else {
400                            None
401                        }
402                    } else {
403                        None
404                    }
405                },
406        })
407    } else {
408        Err(anyhow::anyhow!("Expected struct fields"))
409    }
410}
411
412/// Decode KeySetReadAllIndicesResponse command response (05)
413pub fn decode_key_set_read_all_indices_response(inp: &tlv::TlvItemValue) -> anyhow::Result<KeySetReadAllIndicesResponse> {
414    if let tlv::TlvItemValue::List(_fields) = inp {
415        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
416        Ok(KeySetReadAllIndicesResponse {
417                group_key_set_i_ds: {
418                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
419                        let items: Vec<u16> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u16) } else { None } }).collect();
420                        Some(items)
421                    } else {
422                        None
423                    }
424                },
425        })
426    } else {
427        Err(anyhow::anyhow!("Expected struct fields"))
428    }
429}
430
431// Typed facade (invokes + reads)
432
433/// Invoke `KeySetWrite` command on cluster `Group Key Management`.
434pub async fn key_set_write(conn: &crate::controller::Connection, endpoint: u16, group_key_set: GroupKeySet) -> anyhow::Result<()> {
435    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_CMD_ID_KEYSETWRITE, &encode_key_set_write(group_key_set)?).await?;
436    Ok(())
437}
438
439/// Invoke `KeySetRead` command on cluster `Group Key Management`.
440pub async fn key_set_read(conn: &crate::controller::Connection, endpoint: u16, group_key_set_id: u16) -> anyhow::Result<KeySetReadResponse> {
441    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_CMD_ID_KEYSETREAD, &encode_key_set_read(group_key_set_id)?).await?;
442    decode_key_set_read_response(&tlv)
443}
444
445/// Invoke `KeySetRemove` command on cluster `Group Key Management`.
446pub async fn key_set_remove(conn: &crate::controller::Connection, endpoint: u16, group_key_set_id: u16) -> anyhow::Result<()> {
447    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_CMD_ID_KEYSETREMOVE, &encode_key_set_remove(group_key_set_id)?).await?;
448    Ok(())
449}
450
451/// Invoke `KeySetReadAllIndices` command on cluster `Group Key Management`.
452pub async fn key_set_read_all_indices(conn: &crate::controller::Connection, endpoint: u16, do_not_use: Option<u8>) -> anyhow::Result<KeySetReadAllIndicesResponse> {
453    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_CMD_ID_KEYSETREADALLINDICES, &encode_key_set_read_all_indices(do_not_use)?).await?;
454    decode_key_set_read_all_indices_response(&tlv)
455}
456
457/// Read `GroupKeyMap` attribute from cluster `Group Key Management`.
458pub async fn read_group_key_map(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<GroupKeyMap>> {
459    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_ATTR_ID_GROUPKEYMAP).await?;
460    decode_group_key_map(&tlv)
461}
462
463/// Read `GroupTable` attribute from cluster `Group Key Management`.
464pub async fn read_group_table(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<GroupInfoMap>> {
465    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_ATTR_ID_GROUPTABLE).await?;
466    decode_group_table(&tlv)
467}
468
469/// Read `MaxGroupsPerFabric` attribute from cluster `Group Key Management`.
470pub async fn read_max_groups_per_fabric(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
471    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_ATTR_ID_MAXGROUPSPERFABRIC).await?;
472    decode_max_groups_per_fabric(&tlv)
473}
474
475/// Read `MaxGroupKeysPerFabric` attribute from cluster `Group Key Management`.
476pub async fn read_max_group_keys_per_fabric(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
477    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_ATTR_ID_MAXGROUPKEYSPERFABRIC).await?;
478    decode_max_group_keys_per_fabric(&tlv)
479}
480
481/// Read `GroupcastAdoption` attribute from cluster `Group Key Management`.
482pub async fn read_groupcast_adoption(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<GroupcastAdoption>> {
483    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_ATTR_ID_GROUPCASTADOPTION).await?;
484    decode_groupcast_adoption(&tlv)
485}
486