matc/clusters/codec/
tls_client_management.rs

1//! Matter TLV encoders and decoders for TLS Client Management Cluster
2//! Cluster ID: 0x0802
3//!
4//! This file is automatically generated from TLSClientManagement.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 StatusCode {
19    /// The endpoint is already installed.
20    Endpointalreadyinstalled = 2,
21    /// No root certificate exists for this CAID.
22    Rootcertificatenotfound = 3,
23    /// No client certificate exists for this CCDID.
24    Clientcertificatenotfound = 4,
25    /// The endpoint is in use and cannot be removed.
26    Endpointinuse = 5,
27    /// Time sync has not yet occurred.
28    Invalidtime = 6,
29}
30
31impl StatusCode {
32    /// Convert from u8 value
33    pub fn from_u8(value: u8) -> Option<Self> {
34        match value {
35            2 => Some(StatusCode::Endpointalreadyinstalled),
36            3 => Some(StatusCode::Rootcertificatenotfound),
37            4 => Some(StatusCode::Clientcertificatenotfound),
38            5 => Some(StatusCode::Endpointinuse),
39            6 => Some(StatusCode::Invalidtime),
40            _ => None,
41        }
42    }
43
44    /// Convert to u8 value
45    pub fn to_u8(self) -> u8 {
46        self as u8
47    }
48}
49
50impl From<StatusCode> for u8 {
51    fn from(val: StatusCode) -> Self {
52        val as u8
53    }
54}
55
56// Struct definitions
57
58#[derive(Debug, serde::Serialize)]
59pub struct TLSEndpoint {
60    pub endpoint_id: Option<u8>,
61    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
62    pub hostname: Option<Vec<u8>>,
63    pub port: Option<u16>,
64    pub caid: Option<u8>,
65    pub ccdid: Option<u8>,
66    pub reference_count: Option<u8>,
67}
68
69// Command encoders
70
71/// Encode ProvisionEndpoint command (0x00)
72pub fn encode_provision_endpoint(hostname: Vec<u8>, port: u16, caid: u8, ccdid: Option<u8>, endpoint_id: Option<u8>) -> anyhow::Result<Vec<u8>> {
73    let tlv = tlv::TlvItemEnc {
74        tag: 0,
75        value: tlv::TlvItemValueEnc::StructInvisible(vec![
76        (0, tlv::TlvItemValueEnc::OctetString(hostname)).into(),
77        (1, tlv::TlvItemValueEnc::UInt16(port)).into(),
78        (2, tlv::TlvItemValueEnc::UInt8(caid)).into(),
79        (3, tlv::TlvItemValueEnc::UInt8(ccdid.unwrap_or(0))).into(),
80        (4, tlv::TlvItemValueEnc::UInt8(endpoint_id.unwrap_or(0))).into(),
81        ]),
82    };
83    Ok(tlv.encode()?)
84}
85
86/// Encode FindEndpoint command (0x02)
87pub fn encode_find_endpoint(endpoint_id: u8) -> anyhow::Result<Vec<u8>> {
88    let tlv = tlv::TlvItemEnc {
89        tag: 0,
90        value: tlv::TlvItemValueEnc::StructInvisible(vec![
91        (0, tlv::TlvItemValueEnc::UInt8(endpoint_id)).into(),
92        ]),
93    };
94    Ok(tlv.encode()?)
95}
96
97/// Encode RemoveEndpoint command (0x04)
98pub fn encode_remove_endpoint(endpoint_id: u8) -> anyhow::Result<Vec<u8>> {
99    let tlv = tlv::TlvItemEnc {
100        tag: 0,
101        value: tlv::TlvItemValueEnc::StructInvisible(vec![
102        (0, tlv::TlvItemValueEnc::UInt8(endpoint_id)).into(),
103        ]),
104    };
105    Ok(tlv.encode()?)
106}
107
108// Attribute decoders
109
110/// Decode MaxProvisioned attribute (0x0000)
111pub fn decode_max_provisioned(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
112    if let tlv::TlvItemValue::Int(v) = inp {
113        Ok(*v as u8)
114    } else {
115        Err(anyhow::anyhow!("Expected UInt8"))
116    }
117}
118
119/// Decode ProvisionedEndpoints attribute (0x0001)
120pub fn decode_provisioned_endpoints(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<TLSEndpoint>> {
121    let mut res = Vec::new();
122    if let tlv::TlvItemValue::List(v) = inp {
123        for item in v {
124            res.push(TLSEndpoint {
125                endpoint_id: item.get_int(&[0]).map(|v| v as u8),
126                hostname: item.get_octet_string_owned(&[1]),
127                port: item.get_int(&[2]).map(|v| v as u16),
128                caid: item.get_int(&[3]).map(|v| v as u8),
129                ccdid: item.get_int(&[4]).map(|v| v as u8),
130                reference_count: item.get_int(&[5]).map(|v| v as u8),
131            });
132        }
133    }
134    Ok(res)
135}
136
137
138// JSON dispatcher function
139
140/// Decode attribute value and return as JSON string
141///
142/// # Parameters
143/// * `cluster_id` - The cluster identifier
144/// * `attribute_id` - The attribute identifier
145/// * `tlv_value` - The TLV value to decode
146///
147/// # Returns
148/// JSON string representation of the decoded value or error
149pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
150    // Verify this is the correct cluster
151    if cluster_id != 0x0802 {
152        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0802, got {}\"}}", cluster_id);
153    }
154
155    match attribute_id {
156        0x0000 => {
157            match decode_max_provisioned(tlv_value) {
158                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
159                Err(e) => format!("{{\"error\": \"{}\"}}", e),
160            }
161        }
162        0x0001 => {
163            match decode_provisioned_endpoints(tlv_value) {
164                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
165                Err(e) => format!("{{\"error\": \"{}\"}}", e),
166            }
167        }
168        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
169    }
170}
171
172/// Get list of all attributes supported by this cluster
173///
174/// # Returns
175/// Vector of tuples containing (attribute_id, attribute_name)
176pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
177    vec![
178        (0x0000, "MaxProvisioned"),
179        (0x0001, "ProvisionedEndpoints"),
180    ]
181}
182
183#[derive(Debug, serde::Serialize)]
184pub struct ProvisionEndpointResponse {
185    pub endpoint_id: Option<u8>,
186}
187
188#[derive(Debug, serde::Serialize)]
189pub struct FindEndpointResponse {
190    pub endpoint: Option<TLSEndpoint>,
191}
192
193// Command response decoders
194
195/// Decode ProvisionEndpointResponse command response (01)
196pub fn decode_provision_endpoint_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ProvisionEndpointResponse> {
197    if let tlv::TlvItemValue::List(_fields) = inp {
198        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
199        Ok(ProvisionEndpointResponse {
200                endpoint_id: item.get_int(&[0]).map(|v| v as u8),
201        })
202    } else {
203        Err(anyhow::anyhow!("Expected struct fields"))
204    }
205}
206
207/// Decode FindEndpointResponse command response (03)
208pub fn decode_find_endpoint_response(inp: &tlv::TlvItemValue) -> anyhow::Result<FindEndpointResponse> {
209    if let tlv::TlvItemValue::List(_fields) = inp {
210        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
211        Ok(FindEndpointResponse {
212                endpoint: {
213                    if let Some(nested_tlv) = item.get(&[0]) {
214                        if let tlv::TlvItemValue::List(_) = nested_tlv {
215                            let nested_item = tlv::TlvItem { tag: 0, value: nested_tlv.clone() };
216                            Some(TLSEndpoint {
217                endpoint_id: nested_item.get_int(&[0]).map(|v| v as u8),
218                hostname: nested_item.get_octet_string_owned(&[1]),
219                port: nested_item.get_int(&[2]).map(|v| v as u16),
220                caid: nested_item.get_int(&[3]).map(|v| v as u8),
221                ccdid: nested_item.get_int(&[4]).map(|v| v as u8),
222                reference_count: nested_item.get_int(&[5]).map(|v| v as u8),
223                            })
224                        } else {
225                            None
226                        }
227                    } else {
228                        None
229                    }
230                },
231        })
232    } else {
233        Err(anyhow::anyhow!("Expected struct fields"))
234    }
235}
236