matc/clusters/codec/
joint_fabric_administrator_cluster.rs

1//! Matter TLV encoders and decoders for Joint Fabric Administrator Cluster
2//! Cluster ID: 0x0753
3//!
4//! This file is automatically generated from JointFabricAdministratorCluster.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 ICACResponseStatus {
19    /// No error
20    Ok = 0,
21    /// Public Key in the ICAC is invalid
22    Invalidpublickey = 1,
23    /// ICAC chain validation failed / ICAC DN Encoding rules verification failed
24    Invalidicac = 2,
25}
26
27impl ICACResponseStatus {
28    /// Convert from u8 value
29    pub fn from_u8(value: u8) -> Option<Self> {
30        match value {
31            0 => Some(ICACResponseStatus::Ok),
32            1 => Some(ICACResponseStatus::Invalidpublickey),
33            2 => Some(ICACResponseStatus::Invalidicac),
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<ICACResponseStatus> for u8 {
45    fn from(val: ICACResponseStatus) -> Self {
46        val as u8
47    }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
51#[repr(u8)]
52pub enum StatusCode {
53    /// Could not be completed because another commissioning is in progress
54    Busy = 2,
55    /// Provided PAKE parameters were incorrectly formatted or otherwise invalid
56    Pakeparametererror = 3,
57    /// No commissioning window was currently open
58    Windownotopen = 4,
59    /// ICACCSRRequest command has been invoked by a peer against which Fabric Table VID Verification hasn't been executed
60    Vidnotverified = 5,
61    /// OpenJointCommissioningWindow command has been invoked but the AdministratorFabricIndex field has the value of null
62    Invalidadministratorfabricindex = 6,
63}
64
65impl StatusCode {
66    /// Convert from u8 value
67    pub fn from_u8(value: u8) -> Option<Self> {
68        match value {
69            2 => Some(StatusCode::Busy),
70            3 => Some(StatusCode::Pakeparametererror),
71            4 => Some(StatusCode::Windownotopen),
72            5 => Some(StatusCode::Vidnotverified),
73            6 => Some(StatusCode::Invalidadministratorfabricindex),
74            _ => None,
75        }
76    }
77
78    /// Convert to u8 value
79    pub fn to_u8(self) -> u8 {
80        self as u8
81    }
82}
83
84impl From<StatusCode> for u8 {
85    fn from(val: StatusCode) -> Self {
86        val as u8
87    }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
91#[repr(u8)]
92pub enum TransferAnchorResponseStatus {
93    /// No error
94    Ok = 0,
95    /// Anchor Transfer was not started due to on-going Datastore operations
96    Transferanchorstatusdatastorebusy = 1,
97    /// User has not consented for Anchor Transfer
98    Transferanchorstatusnouserconsent = 2,
99}
100
101impl TransferAnchorResponseStatus {
102    /// Convert from u8 value
103    pub fn from_u8(value: u8) -> Option<Self> {
104        match value {
105            0 => Some(TransferAnchorResponseStatus::Ok),
106            1 => Some(TransferAnchorResponseStatus::Transferanchorstatusdatastorebusy),
107            2 => Some(TransferAnchorResponseStatus::Transferanchorstatusnouserconsent),
108            _ => None,
109        }
110    }
111
112    /// Convert to u8 value
113    pub fn to_u8(self) -> u8 {
114        self as u8
115    }
116}
117
118impl From<TransferAnchorResponseStatus> for u8 {
119    fn from(val: TransferAnchorResponseStatus) -> Self {
120        val as u8
121    }
122}
123
124// Command encoders
125
126/// Encode AddICAC command (0x02)
127pub fn encode_add_icac(icac_value: Vec<u8>) -> anyhow::Result<Vec<u8>> {
128    let tlv = tlv::TlvItemEnc {
129        tag: 0,
130        value: tlv::TlvItemValueEnc::StructInvisible(vec![
131        (1, tlv::TlvItemValueEnc::OctetString(icac_value)).into(),
132        ]),
133    };
134    Ok(tlv.encode()?)
135}
136
137/// Encode OpenJointCommissioningWindow command (0x04)
138pub fn encode_open_joint_commissioning_window(commissioning_timeout: u16, pake_passcode_verifier: Vec<u8>, discriminator: u16, iterations: u32, salt: Vec<u8>) -> anyhow::Result<Vec<u8>> {
139    let tlv = tlv::TlvItemEnc {
140        tag: 0,
141        value: tlv::TlvItemValueEnc::StructInvisible(vec![
142        (0, tlv::TlvItemValueEnc::UInt16(commissioning_timeout)).into(),
143        (1, tlv::TlvItemValueEnc::OctetString(pake_passcode_verifier)).into(),
144        (2, tlv::TlvItemValueEnc::UInt16(discriminator)).into(),
145        (3, tlv::TlvItemValueEnc::UInt32(iterations)).into(),
146        (4, tlv::TlvItemValueEnc::OctetString(salt)).into(),
147        ]),
148    };
149    Ok(tlv.encode()?)
150}
151
152/// Encode AnnounceJointFabricAdministrator command (0x08)
153pub fn encode_announce_joint_fabric_administrator(endpoint_id: u16) -> anyhow::Result<Vec<u8>> {
154    let tlv = tlv::TlvItemEnc {
155        tag: 0,
156        value: tlv::TlvItemValueEnc::StructInvisible(vec![
157        (0, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
158        ]),
159    };
160    Ok(tlv.encode()?)
161}
162
163// Attribute decoders
164
165/// Decode AdministratorFabricIndex attribute (0x0000)
166pub fn decode_administrator_fabric_index(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
167    if let tlv::TlvItemValue::Int(v) = inp {
168        Ok(Some(*v as u8))
169    } else {
170        Ok(None)
171    }
172}
173
174
175// JSON dispatcher function
176
177/// Decode attribute value and return as JSON string
178///
179/// # Parameters
180/// * `cluster_id` - The cluster identifier
181/// * `attribute_id` - The attribute identifier
182/// * `tlv_value` - The TLV value to decode
183///
184/// # Returns
185/// JSON string representation of the decoded value or error
186pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
187    // Verify this is the correct cluster
188    if cluster_id != 0x0753 {
189        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0753, got {}\"}}", cluster_id);
190    }
191
192    match attribute_id {
193        0x0000 => {
194            match decode_administrator_fabric_index(tlv_value) {
195                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
196                Err(e) => format!("{{\"error\": \"{}\"}}", e),
197            }
198        }
199        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
200    }
201}
202
203/// Get list of all attributes supported by this cluster
204///
205/// # Returns
206/// Vector of tuples containing (attribute_id, attribute_name)
207pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
208    vec![
209        (0x0000, "AdministratorFabricIndex"),
210    ]
211}
212
213#[derive(Debug, serde::Serialize)]
214pub struct ICACCSRResponse {
215    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
216    pub icaccsr: Option<Vec<u8>>,
217}
218
219#[derive(Debug, serde::Serialize)]
220pub struct ICACResponse {
221    pub status_code: Option<ICACResponseStatus>,
222}
223
224#[derive(Debug, serde::Serialize)]
225pub struct TransferAnchorResponse {
226    pub status_code: Option<TransferAnchorResponseStatus>,
227}
228
229// Command response decoders
230
231/// Decode ICACCSRResponse command response (01)
232pub fn decode_icaccsr_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ICACCSRResponse> {
233    if let tlv::TlvItemValue::List(_fields) = inp {
234        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
235        Ok(ICACCSRResponse {
236                icaccsr: item.get_octet_string_owned(&[0]),
237        })
238    } else {
239        Err(anyhow::anyhow!("Expected struct fields"))
240    }
241}
242
243/// Decode ICACResponse command response (03)
244pub fn decode_icac_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ICACResponse> {
245    if let tlv::TlvItemValue::List(_fields) = inp {
246        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
247        Ok(ICACResponse {
248                status_code: item.get_int(&[0]).and_then(|v| ICACResponseStatus::from_u8(v as u8)),
249        })
250    } else {
251        Err(anyhow::anyhow!("Expected struct fields"))
252    }
253}
254
255/// Decode TransferAnchorResponse command response (06)
256pub fn decode_transfer_anchor_response(inp: &tlv::TlvItemValue) -> anyhow::Result<TransferAnchorResponse> {
257    if let tlv::TlvItemValue::List(_fields) = inp {
258        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
259        Ok(TransferAnchorResponse {
260                status_code: item.get_int(&[0]).and_then(|v| TransferAnchorResponseStatus::from_u8(v as u8)),
261        })
262    } else {
263        Err(anyhow::anyhow!("Expected struct fields"))
264    }
265}
266