matc/clusters/codec/
joint_fabric_datastore_cluster.rs

1//! Matter TLV encoders and decoders for Joint Fabric Datastore Cluster
2//! Cluster ID: 0x0752
3//!
4//! This file is automatically generated from JointFabricDatastoreCluster.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 DatastoreAccessControlEntryAuthMode {
19    /// Passcode authenticated session
20    Pase = 1,
21    /// Certificate authenticated session
22    Case = 2,
23    /// Group authenticated session
24    Group = 3,
25}
26
27impl DatastoreAccessControlEntryAuthMode {
28    /// Convert from u8 value
29    pub fn from_u8(value: u8) -> Option<Self> {
30        match value {
31            1 => Some(DatastoreAccessControlEntryAuthMode::Pase),
32            2 => Some(DatastoreAccessControlEntryAuthMode::Case),
33            3 => Some(DatastoreAccessControlEntryAuthMode::Group),
34            _ => None,
35        }
36    }
37
38    /// Convert to u8 value
39    pub fn to_u8(self) -> u8 {
40        self as u8
41    }
42}
43
44impl From<DatastoreAccessControlEntryAuthMode> for u8 {
45    fn from(val: DatastoreAccessControlEntryAuthMode) -> Self {
46        val as u8
47    }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
51#[repr(u8)]
52pub enum DatastoreAccessControlEntryPrivilege {
53    /// Can read and observe all (except Access Control Cluster)
54    View = 1,
55    Proxyview = 2,
56    /// View privileges, and can perform the primary function of this Node (except Access Control Cluster)
57    Operate = 3,
58    /// Operate privileges, and can modify persistent configuration of this Node (except Access Control Cluster)
59    Manage = 4,
60    /// Manage privileges, and can observe and modify the Access Control Cluster
61    Administer = 5,
62}
63
64impl DatastoreAccessControlEntryPrivilege {
65    /// Convert from u8 value
66    pub fn from_u8(value: u8) -> Option<Self> {
67        match value {
68            1 => Some(DatastoreAccessControlEntryPrivilege::View),
69            2 => Some(DatastoreAccessControlEntryPrivilege::Proxyview),
70            3 => Some(DatastoreAccessControlEntryPrivilege::Operate),
71            4 => Some(DatastoreAccessControlEntryPrivilege::Manage),
72            5 => Some(DatastoreAccessControlEntryPrivilege::Administer),
73            _ => None,
74        }
75    }
76
77    /// Convert to u8 value
78    pub fn to_u8(self) -> u8 {
79        self as u8
80    }
81}
82
83impl From<DatastoreAccessControlEntryPrivilege> for u8 {
84    fn from(val: DatastoreAccessControlEntryPrivilege) -> Self {
85        val as u8
86    }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
90#[repr(u8)]
91pub enum DatastoreGroupKeyMulticastPolicy {
92    /// Indicates filtering of multicast messages for a specific Group ID
93    Pergroupid = 0,
94    /// Indicates not filtering of multicast messages
95    Allnodes = 1,
96}
97
98impl DatastoreGroupKeyMulticastPolicy {
99    /// Convert from u8 value
100    pub fn from_u8(value: u8) -> Option<Self> {
101        match value {
102            0 => Some(DatastoreGroupKeyMulticastPolicy::Pergroupid),
103            1 => Some(DatastoreGroupKeyMulticastPolicy::Allnodes),
104            _ => None,
105        }
106    }
107
108    /// Convert to u8 value
109    pub fn to_u8(self) -> u8 {
110        self as u8
111    }
112}
113
114impl From<DatastoreGroupKeyMulticastPolicy> for u8 {
115    fn from(val: DatastoreGroupKeyMulticastPolicy) -> Self {
116        val as u8
117    }
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
121#[repr(u8)]
122pub enum DatastoreGroupKeySecurityPolicy {
123    /// Message counter synchronization using trust-first
124    Trustfirst = 0,
125}
126
127impl DatastoreGroupKeySecurityPolicy {
128    /// Convert from u8 value
129    pub fn from_u8(value: u8) -> Option<Self> {
130        match value {
131            0 => Some(DatastoreGroupKeySecurityPolicy::Trustfirst),
132            _ => None,
133        }
134    }
135
136    /// Convert to u8 value
137    pub fn to_u8(self) -> u8 {
138        self as u8
139    }
140}
141
142impl From<DatastoreGroupKeySecurityPolicy> for u8 {
143    fn from(val: DatastoreGroupKeySecurityPolicy) -> Self {
144        val as u8
145    }
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
149#[repr(u8)]
150pub enum DatastoreState {
151    /// Target device operation is pending
152    Pending = 0,
153    /// Target device operation has been committed
154    Committed = 1,
155    /// Target device delete operation is pending
156    Deletepending = 2,
157    /// Target device operation has failed
158    Commitfailed = 3,
159}
160
161impl DatastoreState {
162    /// Convert from u8 value
163    pub fn from_u8(value: u8) -> Option<Self> {
164        match value {
165            0 => Some(DatastoreState::Pending),
166            1 => Some(DatastoreState::Committed),
167            2 => Some(DatastoreState::Deletepending),
168            3 => Some(DatastoreState::Commitfailed),
169            _ => None,
170        }
171    }
172
173    /// Convert to u8 value
174    pub fn to_u8(self) -> u8 {
175        self as u8
176    }
177}
178
179impl From<DatastoreState> for u8 {
180    fn from(val: DatastoreState) -> Self {
181        val as u8
182    }
183}
184
185// Struct definitions
186
187#[derive(Debug, serde::Serialize)]
188pub struct DatastoreACLEntry {
189    pub node_id: Option<u64>,
190    pub list_id: Option<u16>,
191    pub acl_entry: Option<DatastoreAccessControlEntry>,
192    pub status_entry: Option<DatastoreStatusEntry>,
193}
194
195#[derive(Debug, serde::Serialize)]
196pub struct DatastoreAccessControlEntry {
197    pub privilege: Option<DatastoreAccessControlEntryPrivilege>,
198    pub auth_mode: Option<DatastoreAccessControlEntryAuthMode>,
199    pub subjects: Option<Vec<u64>>,
200    pub targets: Option<Vec<DatastoreAccessControlTarget>>,
201}
202
203#[derive(Debug, serde::Serialize)]
204pub struct DatastoreAccessControlTarget {
205    pub cluster: Option<u32>,
206    pub endpoint: Option<u16>,
207    pub device_type: Option<u32>,
208}
209
210#[derive(Debug, serde::Serialize)]
211pub struct DatastoreAdministratorInformationEntry {
212    pub node_id: Option<u64>,
213    pub friendly_name: Option<String>,
214    pub vendor_id: Option<u16>,
215    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
216    pub icac: Option<Vec<u8>>,
217}
218
219#[derive(Debug, serde::Serialize)]
220pub struct DatastoreBindingTarget {
221    pub node: Option<u64>,
222    pub group: Option<u8>,
223    pub endpoint: Option<u16>,
224    pub cluster: Option<u32>,
225}
226
227#[derive(Debug, serde::Serialize)]
228pub struct DatastoreEndpointBindingEntry {
229    pub node_id: Option<u64>,
230    pub endpoint_id: Option<u16>,
231    pub list_id: Option<u16>,
232    pub binding: Option<DatastoreBindingTarget>,
233    pub status_entry: Option<DatastoreStatusEntry>,
234}
235
236#[derive(Debug, serde::Serialize)]
237pub struct DatastoreEndpointEntry {
238    pub endpoint_id: Option<u16>,
239    pub node_id: Option<u64>,
240    pub friendly_name: Option<String>,
241    pub status_entry: Option<DatastoreStatusEntry>,
242}
243
244#[derive(Debug, serde::Serialize)]
245pub struct DatastoreEndpointGroupIDEntry {
246    pub node_id: Option<u64>,
247    pub endpoint_id: Option<u16>,
248    pub group_id: Option<u8>,
249    pub status_entry: Option<DatastoreStatusEntry>,
250}
251
252#[derive(Debug, serde::Serialize)]
253pub struct DatastoreGroupInformationEntry {
254    pub group_id: Option<u64>,
255    pub friendly_name: Option<String>,
256    pub group_key_set_id: Option<u16>,
257    pub group_cat: Option<u16>,
258    pub group_cat_version: Option<u16>,
259    pub group_permission: Option<DatastoreAccessControlEntryPrivilege>,
260}
261
262#[derive(Debug, serde::Serialize)]
263pub struct DatastoreGroupKeySet {
264    pub group_key_set_id: Option<u16>,
265    pub group_key_security_policy: Option<DatastoreGroupKeySecurityPolicy>,
266    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
267    pub epoch_key0: Option<Vec<u8>>,
268    pub epoch_start_time0: Option<u64>,
269    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
270    pub epoch_key1: Option<Vec<u8>>,
271    pub epoch_start_time1: Option<u64>,
272    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
273    pub epoch_key2: Option<Vec<u8>>,
274    pub epoch_start_time2: Option<u64>,
275    pub group_key_multicast_policy: Option<DatastoreGroupKeyMulticastPolicy>,
276}
277
278#[derive(Debug, serde::Serialize)]
279pub struct DatastoreNodeInformationEntry {
280    pub node_id: Option<u64>,
281    pub friendly_name: Option<String>,
282    pub commissioning_status_entry: Option<DatastoreStatusEntry>,
283}
284
285#[derive(Debug, serde::Serialize)]
286pub struct DatastoreNodeKeySetEntry {
287    pub node_id: Option<u64>,
288    pub group_key_set_id: Option<u16>,
289    pub status_entry: Option<DatastoreStatusEntry>,
290}
291
292#[derive(Debug, serde::Serialize)]
293pub struct DatastoreStatusEntry {
294    pub state: Option<DatastoreState>,
295    pub update_timestamp: Option<u64>,
296    pub failure_code: Option<u8>,
297}
298
299// Command encoders
300
301/// Encode AddKeySet command (0x00)
302pub fn encode_add_key_set(group_key_set: DatastoreGroupKeySet) -> anyhow::Result<Vec<u8>> {
303            // Encode struct DatastoreGroupKeySetStruct
304            let mut group_key_set_fields = Vec::new();
305            if let Some(x) = group_key_set.group_key_set_id { group_key_set_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
306            if let Some(x) = group_key_set.group_key_security_policy { group_key_set_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
307            if let Some(x) = group_key_set.epoch_key0 { group_key_set_fields.push((2, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
308            if let Some(x) = group_key_set.epoch_start_time0 { group_key_set_fields.push((3, tlv::TlvItemValueEnc::UInt64(x)).into()); }
309            if let Some(x) = group_key_set.epoch_key1 { group_key_set_fields.push((4, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
310            if let Some(x) = group_key_set.epoch_start_time1 { group_key_set_fields.push((5, tlv::TlvItemValueEnc::UInt64(x)).into()); }
311            if let Some(x) = group_key_set.epoch_key2 { group_key_set_fields.push((6, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
312            if let Some(x) = group_key_set.epoch_start_time2 { group_key_set_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
313            if let Some(x) = group_key_set.group_key_multicast_policy { group_key_set_fields.push((8, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
314    let tlv = tlv::TlvItemEnc {
315        tag: 0,
316        value: tlv::TlvItemValueEnc::StructInvisible(vec![
317        (0, tlv::TlvItemValueEnc::StructInvisible(group_key_set_fields)).into(),
318        ]),
319    };
320    Ok(tlv.encode()?)
321}
322
323/// Encode UpdateKeySet command (0x01)
324pub fn encode_update_key_set(group_key_set: DatastoreGroupKeySet) -> anyhow::Result<Vec<u8>> {
325            // Encode struct DatastoreGroupKeySetStruct
326            let mut group_key_set_fields = Vec::new();
327            if let Some(x) = group_key_set.group_key_set_id { group_key_set_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
328            if let Some(x) = group_key_set.group_key_security_policy { group_key_set_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
329            if let Some(x) = group_key_set.epoch_key0 { group_key_set_fields.push((2, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
330            if let Some(x) = group_key_set.epoch_start_time0 { group_key_set_fields.push((3, tlv::TlvItemValueEnc::UInt64(x)).into()); }
331            if let Some(x) = group_key_set.epoch_key1 { group_key_set_fields.push((4, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
332            if let Some(x) = group_key_set.epoch_start_time1 { group_key_set_fields.push((5, tlv::TlvItemValueEnc::UInt64(x)).into()); }
333            if let Some(x) = group_key_set.epoch_key2 { group_key_set_fields.push((6, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
334            if let Some(x) = group_key_set.epoch_start_time2 { group_key_set_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
335            if let Some(x) = group_key_set.group_key_multicast_policy { group_key_set_fields.push((8, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
336    let tlv = tlv::TlvItemEnc {
337        tag: 0,
338        value: tlv::TlvItemValueEnc::StructInvisible(vec![
339        (0, tlv::TlvItemValueEnc::StructInvisible(group_key_set_fields)).into(),
340        ]),
341    };
342    Ok(tlv.encode()?)
343}
344
345/// Encode RemoveKeySet command (0x02)
346pub fn encode_remove_key_set(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
347    let tlv = tlv::TlvItemEnc {
348        tag: 0,
349        value: tlv::TlvItemValueEnc::StructInvisible(vec![
350        (0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
351        ]),
352    };
353    Ok(tlv.encode()?)
354}
355
356/// Encode AddGroup command (0x03)
357pub fn encode_add_group(group_id: u8, friendly_name: String, group_key_set_id: Option<u16>, group_cat: Option<u16>, group_cat_version: Option<u16>, group_permission: DatastoreAccessControlEntryPrivilege) -> anyhow::Result<Vec<u8>> {
358    let tlv = tlv::TlvItemEnc {
359        tag: 0,
360        value: tlv::TlvItemValueEnc::StructInvisible(vec![
361        (0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
362        (1, tlv::TlvItemValueEnc::String(friendly_name)).into(),
363        (2, tlv::TlvItemValueEnc::UInt16(group_key_set_id.unwrap_or(0))).into(),
364        (3, tlv::TlvItemValueEnc::UInt16(group_cat.unwrap_or(0))).into(),
365        (4, tlv::TlvItemValueEnc::UInt16(group_cat_version.unwrap_or(0))).into(),
366        (5, tlv::TlvItemValueEnc::UInt8(group_permission.to_u8())).into(),
367        ]),
368    };
369    Ok(tlv.encode()?)
370}
371
372/// Encode UpdateGroup command (0x04)
373pub fn encode_update_group(group_id: u8, friendly_name: Option<String>, group_key_set_id: Option<u16>, group_cat: Option<u16>, group_cat_version: Option<u16>, group_permission: Option<DatastoreAccessControlEntryPrivilege>) -> anyhow::Result<Vec<u8>> {
374    let tlv = tlv::TlvItemEnc {
375        tag: 0,
376        value: tlv::TlvItemValueEnc::StructInvisible(vec![
377        (0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
378        (1, tlv::TlvItemValueEnc::String(friendly_name.unwrap_or("".to_string()))).into(),
379        (2, tlv::TlvItemValueEnc::UInt16(group_key_set_id.unwrap_or(0))).into(),
380        (3, tlv::TlvItemValueEnc::UInt16(group_cat.unwrap_or(0))).into(),
381        (4, tlv::TlvItemValueEnc::UInt16(group_cat_version.unwrap_or(0))).into(),
382        (5, tlv::TlvItemValueEnc::UInt8(group_permission.map(|e| e.to_u8()).unwrap_or(0))).into(),
383        ]),
384    };
385    Ok(tlv.encode()?)
386}
387
388/// Encode RemoveGroup command (0x05)
389pub fn encode_remove_group(group_id: u8) -> anyhow::Result<Vec<u8>> {
390    let tlv = tlv::TlvItemEnc {
391        tag: 0,
392        value: tlv::TlvItemValueEnc::StructInvisible(vec![
393        (0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
394        ]),
395    };
396    Ok(tlv.encode()?)
397}
398
399/// Encode AddAdmin command (0x06)
400pub fn encode_add_admin(node_id: u64, friendly_name: String, vendor_id: u16, icac: Vec<u8>) -> anyhow::Result<Vec<u8>> {
401    let tlv = tlv::TlvItemEnc {
402        tag: 0,
403        value: tlv::TlvItemValueEnc::StructInvisible(vec![
404        (1, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
405        (2, tlv::TlvItemValueEnc::String(friendly_name)).into(),
406        (3, tlv::TlvItemValueEnc::UInt16(vendor_id)).into(),
407        (4, tlv::TlvItemValueEnc::OctetString(icac)).into(),
408        ]),
409    };
410    Ok(tlv.encode()?)
411}
412
413/// Encode UpdateAdmin command (0x07)
414pub fn encode_update_admin(node_id: Option<u64>, friendly_name: Option<String>, icac: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
415    let tlv = tlv::TlvItemEnc {
416        tag: 0,
417        value: tlv::TlvItemValueEnc::StructInvisible(vec![
418        (0, tlv::TlvItemValueEnc::UInt64(node_id.unwrap_or(0))).into(),
419        (1, tlv::TlvItemValueEnc::String(friendly_name.unwrap_or("".to_string()))).into(),
420        (2, tlv::TlvItemValueEnc::OctetString(icac.unwrap_or(vec![]))).into(),
421        ]),
422    };
423    Ok(tlv.encode()?)
424}
425
426/// Encode RemoveAdmin command (0x08)
427pub fn encode_remove_admin(node_id: u64) -> anyhow::Result<Vec<u8>> {
428    let tlv = tlv::TlvItemEnc {
429        tag: 0,
430        value: tlv::TlvItemValueEnc::StructInvisible(vec![
431        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
432        ]),
433    };
434    Ok(tlv.encode()?)
435}
436
437/// Encode AddPendingNode command (0x09)
438pub fn encode_add_pending_node(node_id: u64, friendly_name: String) -> anyhow::Result<Vec<u8>> {
439    let tlv = tlv::TlvItemEnc {
440        tag: 0,
441        value: tlv::TlvItemValueEnc::StructInvisible(vec![
442        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
443        (1, tlv::TlvItemValueEnc::String(friendly_name)).into(),
444        ]),
445    };
446    Ok(tlv.encode()?)
447}
448
449/// Encode RefreshNode command (0x0A)
450pub fn encode_refresh_node(node_id: u64) -> anyhow::Result<Vec<u8>> {
451    let tlv = tlv::TlvItemEnc {
452        tag: 0,
453        value: tlv::TlvItemValueEnc::StructInvisible(vec![
454        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
455        ]),
456    };
457    Ok(tlv.encode()?)
458}
459
460/// Encode UpdateNode command (0x0B)
461pub fn encode_update_node(node_id: u64, friendly_name: String) -> anyhow::Result<Vec<u8>> {
462    let tlv = tlv::TlvItemEnc {
463        tag: 0,
464        value: tlv::TlvItemValueEnc::StructInvisible(vec![
465        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
466        (1, tlv::TlvItemValueEnc::String(friendly_name)).into(),
467        ]),
468    };
469    Ok(tlv.encode()?)
470}
471
472/// Encode RemoveNode command (0x0C)
473pub fn encode_remove_node(node_id: u64) -> anyhow::Result<Vec<u8>> {
474    let tlv = tlv::TlvItemEnc {
475        tag: 0,
476        value: tlv::TlvItemValueEnc::StructInvisible(vec![
477        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
478        ]),
479    };
480    Ok(tlv.encode()?)
481}
482
483/// Encode UpdateEndpointForNode command (0x0D)
484pub fn encode_update_endpoint_for_node(endpoint_id: u16, node_id: u64, friendly_name: String) -> anyhow::Result<Vec<u8>> {
485    let tlv = tlv::TlvItemEnc {
486        tag: 0,
487        value: tlv::TlvItemValueEnc::StructInvisible(vec![
488        (0, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
489        (1, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
490        (2, tlv::TlvItemValueEnc::String(friendly_name)).into(),
491        ]),
492    };
493    Ok(tlv.encode()?)
494}
495
496/// Encode AddGroupIDToEndpointForNode command (0x0E)
497pub fn encode_add_group_id_to_endpoint_for_node(node_id: u64, endpoint_id: u16, group_id: u8) -> anyhow::Result<Vec<u8>> {
498    let tlv = tlv::TlvItemEnc {
499        tag: 0,
500        value: tlv::TlvItemValueEnc::StructInvisible(vec![
501        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
502        (1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
503        (2, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
504        ]),
505    };
506    Ok(tlv.encode()?)
507}
508
509/// Encode RemoveGroupIDFromEndpointForNode command (0x0F)
510pub fn encode_remove_group_id_from_endpoint_for_node(node_id: u64, endpoint_id: u16, group_id: u8) -> anyhow::Result<Vec<u8>> {
511    let tlv = tlv::TlvItemEnc {
512        tag: 0,
513        value: tlv::TlvItemValueEnc::StructInvisible(vec![
514        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
515        (1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
516        (2, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
517        ]),
518    };
519    Ok(tlv.encode()?)
520}
521
522/// Encode AddBindingToEndpointForNode command (0x10)
523pub fn encode_add_binding_to_endpoint_for_node(node_id: u64, endpoint_id: u16, binding: DatastoreBindingTarget) -> anyhow::Result<Vec<u8>> {
524            // Encode struct DatastoreBindingTargetStruct
525            let mut binding_fields = Vec::new();
526            if let Some(x) = binding.node { binding_fields.push((1, tlv::TlvItemValueEnc::UInt64(x)).into()); }
527            // TODO: encoding for field group (group-id) not implemented
528            if let Some(x) = binding.endpoint { binding_fields.push((3, tlv::TlvItemValueEnc::UInt16(x)).into()); }
529            if let Some(x) = binding.cluster { binding_fields.push((4, tlv::TlvItemValueEnc::UInt32(x)).into()); }
530    let tlv = tlv::TlvItemEnc {
531        tag: 0,
532        value: tlv::TlvItemValueEnc::StructInvisible(vec![
533        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
534        (1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
535        (2, tlv::TlvItemValueEnc::StructInvisible(binding_fields)).into(),
536        ]),
537    };
538    Ok(tlv.encode()?)
539}
540
541/// Encode RemoveBindingFromEndpointForNode command (0x11)
542pub fn encode_remove_binding_from_endpoint_for_node(list_id: u16, endpoint_id: u16, node_id: u64) -> anyhow::Result<Vec<u8>> {
543    let tlv = tlv::TlvItemEnc {
544        tag: 0,
545        value: tlv::TlvItemValueEnc::StructInvisible(vec![
546        (0, tlv::TlvItemValueEnc::UInt16(list_id)).into(),
547        (1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
548        (2, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
549        ]),
550    };
551    Ok(tlv.encode()?)
552}
553
554/// Encode AddACLToNode command (0x12)
555pub fn encode_add_acl_to_node(node_id: u64, acl_entry: DatastoreAccessControlEntry) -> anyhow::Result<Vec<u8>> {
556            // Encode struct DatastoreAccessControlEntryStruct
557            let mut acl_entry_fields = Vec::new();
558            if let Some(x) = acl_entry.privilege { acl_entry_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
559            if let Some(x) = acl_entry.auth_mode { acl_entry_fields.push((2, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
560            if let Some(listv) = acl_entry.subjects { acl_entry_fields.push((3, tlv::TlvItemValueEnc::StructAnon(listv.into_iter().map(|x| (0, tlv::TlvItemValueEnc::UInt64(x)).into()).collect())).into()); }
561            if let Some(listv) = acl_entry.targets {
562                let inner_vec: Vec<_> = listv.into_iter().map(|inner| {
563                    let mut nested_fields = Vec::new();
564                        if let Some(x) = inner.cluster { nested_fields.push((0, tlv::TlvItemValueEnc::UInt32(x)).into()); }
565                        if let Some(x) = inner.endpoint { nested_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
566                        if let Some(x) = inner.device_type { nested_fields.push((2, tlv::TlvItemValueEnc::UInt32(x)).into()); }
567                    (0, tlv::TlvItemValueEnc::StructAnon(nested_fields)).into()
568                }).collect();
569                acl_entry_fields.push((4, tlv::TlvItemValueEnc::Array(inner_vec)).into());
570            }
571    let tlv = tlv::TlvItemEnc {
572        tag: 0,
573        value: tlv::TlvItemValueEnc::StructInvisible(vec![
574        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
575        (1, tlv::TlvItemValueEnc::StructInvisible(acl_entry_fields)).into(),
576        ]),
577    };
578    Ok(tlv.encode()?)
579}
580
581/// Encode RemoveACLFromNode command (0x13)
582pub fn encode_remove_acl_from_node(list_id: u16, node_id: u64) -> anyhow::Result<Vec<u8>> {
583    let tlv = tlv::TlvItemEnc {
584        tag: 0,
585        value: tlv::TlvItemValueEnc::StructInvisible(vec![
586        (0, tlv::TlvItemValueEnc::UInt16(list_id)).into(),
587        (1, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
588        ]),
589    };
590    Ok(tlv.encode()?)
591}
592
593// Attribute decoders
594
595/// Decode AnchorRootCA attribute (0x0000)
596pub fn decode_anchor_root_ca(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
597    if let tlv::TlvItemValue::OctetString(v) = inp {
598        Ok(v.clone())
599    } else {
600        Err(anyhow::anyhow!("Expected OctetString"))
601    }
602}
603
604/// Decode AnchorNodeID attribute (0x0001)
605pub fn decode_anchor_node_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
606    if let tlv::TlvItemValue::Int(v) = inp {
607        Ok(*v)
608    } else {
609        Err(anyhow::anyhow!("Expected UInt64"))
610    }
611}
612
613/// Decode AnchorVendorID attribute (0x0002)
614pub fn decode_anchor_vendor_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
615    if let tlv::TlvItemValue::Int(v) = inp {
616        Ok(*v as u16)
617    } else {
618        Err(anyhow::anyhow!("Expected UInt16"))
619    }
620}
621
622/// Decode FriendlyName attribute (0x0003)
623pub fn decode_friendly_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
624    if let tlv::TlvItemValue::String(v) = inp {
625        Ok(v.clone())
626    } else {
627        Err(anyhow::anyhow!("Expected String"))
628    }
629}
630
631/// Decode GroupKeySetList attribute (0x0004)
632pub fn decode_group_key_set_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreGroupKeySet>> {
633    let mut res = Vec::new();
634    if let tlv::TlvItemValue::List(v) = inp {
635        for item in v {
636            res.push(DatastoreGroupKeySet {
637                group_key_set_id: item.get_int(&[0]).map(|v| v as u16),
638                group_key_security_policy: item.get_int(&[1]).and_then(|v| DatastoreGroupKeySecurityPolicy::from_u8(v as u8)),
639                epoch_key0: item.get_octet_string_owned(&[2]),
640                epoch_start_time0: item.get_int(&[3]),
641                epoch_key1: item.get_octet_string_owned(&[4]),
642                epoch_start_time1: item.get_int(&[5]),
643                epoch_key2: item.get_octet_string_owned(&[6]),
644                epoch_start_time2: item.get_int(&[7]),
645                group_key_multicast_policy: item.get_int(&[8]).and_then(|v| DatastoreGroupKeyMulticastPolicy::from_u8(v as u8)),
646            });
647        }
648    }
649    Ok(res)
650}
651
652/// Decode GroupList attribute (0x0005)
653pub fn decode_group_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreGroupInformationEntry>> {
654    let mut res = Vec::new();
655    if let tlv::TlvItemValue::List(v) = inp {
656        for item in v {
657            res.push(DatastoreGroupInformationEntry {
658                group_id: item.get_int(&[0]),
659                friendly_name: item.get_string_owned(&[1]),
660                group_key_set_id: item.get_int(&[2]).map(|v| v as u16),
661                group_cat: item.get_int(&[3]).map(|v| v as u16),
662                group_cat_version: item.get_int(&[4]).map(|v| v as u16),
663                group_permission: item.get_int(&[5]).and_then(|v| DatastoreAccessControlEntryPrivilege::from_u8(v as u8)),
664            });
665        }
666    }
667    Ok(res)
668}
669
670/// Decode NodeList attribute (0x0006)
671pub fn decode_node_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreNodeInformationEntry>> {
672    let mut res = Vec::new();
673    if let tlv::TlvItemValue::List(v) = inp {
674        for item in v {
675            res.push(DatastoreNodeInformationEntry {
676                node_id: item.get_int(&[1]),
677                friendly_name: item.get_string_owned(&[2]),
678                commissioning_status_entry: {
679                    if let Some(nested_tlv) = item.get(&[3]) {
680                        if let tlv::TlvItemValue::List(_) = nested_tlv {
681                            let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
682                            Some(DatastoreStatusEntry {
683                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
684                update_timestamp: nested_item.get_int(&[1]),
685                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
686                            })
687                        } else {
688                            None
689                        }
690                    } else {
691                        None
692                    }
693                },
694            });
695        }
696    }
697    Ok(res)
698}
699
700/// Decode AdminList attribute (0x0007)
701pub fn decode_admin_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreAdministratorInformationEntry>> {
702    let mut res = Vec::new();
703    if let tlv::TlvItemValue::List(v) = inp {
704        for item in v {
705            res.push(DatastoreAdministratorInformationEntry {
706                node_id: item.get_int(&[1]),
707                friendly_name: item.get_string_owned(&[2]),
708                vendor_id: item.get_int(&[3]).map(|v| v as u16),
709                icac: item.get_octet_string_owned(&[4]),
710            });
711        }
712    }
713    Ok(res)
714}
715
716/// Decode Status attribute (0x0008)
717pub fn decode_status(inp: &tlv::TlvItemValue) -> anyhow::Result<DatastoreStatusEntry> {
718    if let tlv::TlvItemValue::List(_fields) = inp {
719        // Struct with fields
720        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
721        Ok(DatastoreStatusEntry {
722                state: item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
723                update_timestamp: item.get_int(&[1]),
724                failure_code: item.get_int(&[2]).map(|v| v as u8),
725        })
726    } else {
727        Err(anyhow::anyhow!("Expected struct fields"))
728    }
729}
730
731/// Decode EndpointGroupIDList attribute (0x0009)
732pub fn decode_endpoint_group_id_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreEndpointGroupIDEntry>> {
733    let mut res = Vec::new();
734    if let tlv::TlvItemValue::List(v) = inp {
735        for item in v {
736            res.push(DatastoreEndpointGroupIDEntry {
737                node_id: item.get_int(&[0]),
738                endpoint_id: item.get_int(&[1]).map(|v| v as u16),
739                group_id: item.get_int(&[2]).map(|v| v as u8),
740                status_entry: {
741                    if let Some(nested_tlv) = item.get(&[3]) {
742                        if let tlv::TlvItemValue::List(_) = nested_tlv {
743                            let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
744                            Some(DatastoreStatusEntry {
745                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
746                update_timestamp: nested_item.get_int(&[1]),
747                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
748                            })
749                        } else {
750                            None
751                        }
752                    } else {
753                        None
754                    }
755                },
756            });
757        }
758    }
759    Ok(res)
760}
761
762/// Decode EndpointBindingList attribute (0x000A)
763pub fn decode_endpoint_binding_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreEndpointBindingEntry>> {
764    let mut res = Vec::new();
765    if let tlv::TlvItemValue::List(v) = inp {
766        for item in v {
767            res.push(DatastoreEndpointBindingEntry {
768                node_id: item.get_int(&[0]),
769                endpoint_id: item.get_int(&[1]).map(|v| v as u16),
770                list_id: item.get_int(&[2]).map(|v| v as u16),
771                binding: {
772                    if let Some(nested_tlv) = item.get(&[3]) {
773                        if let tlv::TlvItemValue::List(_) = nested_tlv {
774                            let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
775                            Some(DatastoreBindingTarget {
776                node: nested_item.get_int(&[1]),
777                group: nested_item.get_int(&[2]).map(|v| v as u8),
778                endpoint: nested_item.get_int(&[3]).map(|v| v as u16),
779                cluster: nested_item.get_int(&[4]).map(|v| v as u32),
780                            })
781                        } else {
782                            None
783                        }
784                    } else {
785                        None
786                    }
787                },
788                status_entry: {
789                    if let Some(nested_tlv) = item.get(&[4]) {
790                        if let tlv::TlvItemValue::List(_) = nested_tlv {
791                            let nested_item = tlv::TlvItem { tag: 4, value: nested_tlv.clone() };
792                            Some(DatastoreStatusEntry {
793                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
794                update_timestamp: nested_item.get_int(&[1]),
795                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
796                            })
797                        } else {
798                            None
799                        }
800                    } else {
801                        None
802                    }
803                },
804            });
805        }
806    }
807    Ok(res)
808}
809
810/// Decode NodeKeySetList attribute (0x000B)
811pub fn decode_node_key_set_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreNodeKeySetEntry>> {
812    let mut res = Vec::new();
813    if let tlv::TlvItemValue::List(v) = inp {
814        for item in v {
815            res.push(DatastoreNodeKeySetEntry {
816                node_id: item.get_int(&[0]),
817                group_key_set_id: item.get_int(&[1]).map(|v| v as u16),
818                status_entry: {
819                    if let Some(nested_tlv) = item.get(&[2]) {
820                        if let tlv::TlvItemValue::List(_) = nested_tlv {
821                            let nested_item = tlv::TlvItem { tag: 2, value: nested_tlv.clone() };
822                            Some(DatastoreStatusEntry {
823                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
824                update_timestamp: nested_item.get_int(&[1]),
825                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
826                            })
827                        } else {
828                            None
829                        }
830                    } else {
831                        None
832                    }
833                },
834            });
835        }
836    }
837    Ok(res)
838}
839
840/// Decode NodeACLList attribute (0x000C)
841pub fn decode_node_acl_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreACLEntry>> {
842    let mut res = Vec::new();
843    if let tlv::TlvItemValue::List(v) = inp {
844        for item in v {
845            res.push(DatastoreACLEntry {
846                node_id: item.get_int(&[0]),
847                list_id: item.get_int(&[1]).map(|v| v as u16),
848                acl_entry: {
849                    if let Some(nested_tlv) = item.get(&[2]) {
850                        if let tlv::TlvItemValue::List(_) = nested_tlv {
851                            let nested_item = tlv::TlvItem { tag: 2, value: nested_tlv.clone() };
852                            Some(DatastoreAccessControlEntry {
853                privilege: nested_item.get_int(&[1]).and_then(|v| DatastoreAccessControlEntryPrivilege::from_u8(v as u8)),
854                auth_mode: nested_item.get_int(&[2]).and_then(|v| DatastoreAccessControlEntryAuthMode::from_u8(v as u8)),
855                subjects: {
856                    if let Some(tlv::TlvItemValue::List(l)) = nested_item.get(&[3]) {
857                        let items: Vec<u64> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v) } else { None } }).collect();
858                        Some(items)
859                    } else {
860                        None
861                    }
862                },
863                targets: {
864                    if let Some(tlv::TlvItemValue::List(l)) = nested_item.get(&[4]) {
865                        let mut items = Vec::new();
866                        for list_item in l {
867                            items.push(DatastoreAccessControlTarget {
868                cluster: list_item.get_int(&[0]).map(|v| v as u32),
869                endpoint: list_item.get_int(&[1]).map(|v| v as u16),
870                device_type: list_item.get_int(&[2]).map(|v| v as u32),
871                            });
872                        }
873                        Some(items)
874                    } else {
875                        None
876                    }
877                },
878                            })
879                        } else {
880                            None
881                        }
882                    } else {
883                        None
884                    }
885                },
886                status_entry: {
887                    if let Some(nested_tlv) = item.get(&[3]) {
888                        if let tlv::TlvItemValue::List(_) = nested_tlv {
889                            let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
890                            Some(DatastoreStatusEntry {
891                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
892                update_timestamp: nested_item.get_int(&[1]),
893                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
894                            })
895                        } else {
896                            None
897                        }
898                    } else {
899                        None
900                    }
901                },
902            });
903        }
904    }
905    Ok(res)
906}
907
908/// Decode NodeEndpointList attribute (0x000D)
909pub fn decode_node_endpoint_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreEndpointEntry>> {
910    let mut res = Vec::new();
911    if let tlv::TlvItemValue::List(v) = inp {
912        for item in v {
913            res.push(DatastoreEndpointEntry {
914                endpoint_id: item.get_int(&[0]).map(|v| v as u16),
915                node_id: item.get_int(&[1]),
916                friendly_name: item.get_string_owned(&[2]),
917                status_entry: {
918                    if let Some(nested_tlv) = item.get(&[3]) {
919                        if let tlv::TlvItemValue::List(_) = nested_tlv {
920                            let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
921                            Some(DatastoreStatusEntry {
922                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
923                update_timestamp: nested_item.get_int(&[1]),
924                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
925                            })
926                        } else {
927                            None
928                        }
929                    } else {
930                        None
931                    }
932                },
933            });
934        }
935    }
936    Ok(res)
937}
938
939
940// JSON dispatcher function
941
942/// Decode attribute value and return as JSON string
943///
944/// # Parameters
945/// * `cluster_id` - The cluster identifier
946/// * `attribute_id` - The attribute identifier
947/// * `tlv_value` - The TLV value to decode
948///
949/// # Returns
950/// JSON string representation of the decoded value or error
951pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
952    // Verify this is the correct cluster
953    if cluster_id != 0x0752 {
954        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0752, got {}\"}}", cluster_id);
955    }
956
957    match attribute_id {
958        0x0000 => {
959            match decode_anchor_root_ca(tlv_value) {
960                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
961                Err(e) => format!("{{\"error\": \"{}\"}}", e),
962            }
963        }
964        0x0001 => {
965            match decode_anchor_node_id(tlv_value) {
966                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
967                Err(e) => format!("{{\"error\": \"{}\"}}", e),
968            }
969        }
970        0x0002 => {
971            match decode_anchor_vendor_id(tlv_value) {
972                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
973                Err(e) => format!("{{\"error\": \"{}\"}}", e),
974            }
975        }
976        0x0003 => {
977            match decode_friendly_name(tlv_value) {
978                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
979                Err(e) => format!("{{\"error\": \"{}\"}}", e),
980            }
981        }
982        0x0004 => {
983            match decode_group_key_set_list(tlv_value) {
984                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
985                Err(e) => format!("{{\"error\": \"{}\"}}", e),
986            }
987        }
988        0x0005 => {
989            match decode_group_list(tlv_value) {
990                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
991                Err(e) => format!("{{\"error\": \"{}\"}}", e),
992            }
993        }
994        0x0006 => {
995            match decode_node_list(tlv_value) {
996                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
997                Err(e) => format!("{{\"error\": \"{}\"}}", e),
998            }
999        }
1000        0x0007 => {
1001            match decode_admin_list(tlv_value) {
1002                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1003                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1004            }
1005        }
1006        0x0008 => {
1007            match decode_status(tlv_value) {
1008                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1009                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1010            }
1011        }
1012        0x0009 => {
1013            match decode_endpoint_group_id_list(tlv_value) {
1014                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1015                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1016            }
1017        }
1018        0x000A => {
1019            match decode_endpoint_binding_list(tlv_value) {
1020                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1021                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1022            }
1023        }
1024        0x000B => {
1025            match decode_node_key_set_list(tlv_value) {
1026                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1027                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1028            }
1029        }
1030        0x000C => {
1031            match decode_node_acl_list(tlv_value) {
1032                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1033                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1034            }
1035        }
1036        0x000D => {
1037            match decode_node_endpoint_list(tlv_value) {
1038                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1039                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1040            }
1041        }
1042        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
1043    }
1044}
1045
1046/// Get list of all attributes supported by this cluster
1047///
1048/// # Returns
1049/// Vector of tuples containing (attribute_id, attribute_name)
1050pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
1051    vec![
1052        (0x0000, "AnchorRootCA"),
1053        (0x0001, "AnchorNodeID"),
1054        (0x0002, "AnchorVendorID"),
1055        (0x0003, "FriendlyName"),
1056        (0x0004, "GroupKeySetList"),
1057        (0x0005, "GroupList"),
1058        (0x0006, "NodeList"),
1059        (0x0007, "AdminList"),
1060        (0x0008, "Status"),
1061        (0x0009, "EndpointGroupIDList"),
1062        (0x000A, "EndpointBindingList"),
1063        (0x000B, "NodeKeySetList"),
1064        (0x000C, "NodeACLList"),
1065        (0x000D, "NodeEndpointList"),
1066    ]
1067}
1068