matc/clusters/codec/
thread_network_directory.rs1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
13
14#[derive(Debug, serde::Serialize)]
17pub struct ThreadNetwork {
18 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
19 pub extended_pan_id: Option<Vec<u8>>,
20 pub network_name: Option<String>,
21 pub channel: Option<u16>,
22 pub active_timestamp: Option<u64>,
23}
24
25pub fn encode_add_network(operational_dataset: Vec<u8>) -> anyhow::Result<Vec<u8>> {
29 let tlv = tlv::TlvItemEnc {
30 tag: 0,
31 value: tlv::TlvItemValueEnc::StructInvisible(vec![
32 (0, tlv::TlvItemValueEnc::OctetString(operational_dataset)).into(),
33 ]),
34 };
35 Ok(tlv.encode()?)
36}
37
38pub fn encode_remove_network(extended_pan_id: Vec<u8>) -> anyhow::Result<Vec<u8>> {
40 let tlv = tlv::TlvItemEnc {
41 tag: 0,
42 value: tlv::TlvItemValueEnc::StructInvisible(vec![
43 (0, tlv::TlvItemValueEnc::OctetString(extended_pan_id)).into(),
44 ]),
45 };
46 Ok(tlv.encode()?)
47}
48
49pub fn encode_get_operational_dataset(extended_pan_id: Vec<u8>) -> anyhow::Result<Vec<u8>> {
51 let tlv = tlv::TlvItemEnc {
52 tag: 0,
53 value: tlv::TlvItemValueEnc::StructInvisible(vec![
54 (0, tlv::TlvItemValueEnc::OctetString(extended_pan_id)).into(),
55 ]),
56 };
57 Ok(tlv.encode()?)
58}
59
60pub fn decode_preferred_extended_pan_id(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
64 if let tlv::TlvItemValue::OctetString(v) = inp {
65 Ok(Some(v.clone()))
66 } else {
67 Ok(None)
68 }
69}
70
71pub fn decode_thread_networks(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<ThreadNetwork>> {
73 let mut res = Vec::new();
74 if let tlv::TlvItemValue::List(v) = inp {
75 for item in v {
76 res.push(ThreadNetwork {
77 extended_pan_id: item.get_octet_string_owned(&[0]),
78 network_name: item.get_string_owned(&[1]),
79 channel: item.get_int(&[2]).map(|v| v as u16),
80 active_timestamp: item.get_int(&[3]),
81 });
82 }
83 }
84 Ok(res)
85}
86
87pub fn decode_thread_network_table_size(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
89 if let tlv::TlvItemValue::Int(v) = inp {
90 Ok(*v as u8)
91 } else {
92 Err(anyhow::anyhow!("Expected UInt8"))
93 }
94}
95
96
97pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
109 if cluster_id != 0x0453 {
111 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0453, got {}\"}}", cluster_id);
112 }
113
114 match attribute_id {
115 0x0000 => {
116 match decode_preferred_extended_pan_id(tlv_value) {
117 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
118 Err(e) => format!("{{\"error\": \"{}\"}}", e),
119 }
120 }
121 0x0001 => {
122 match decode_thread_networks(tlv_value) {
123 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
124 Err(e) => format!("{{\"error\": \"{}\"}}", e),
125 }
126 }
127 0x0002 => {
128 match decode_thread_network_table_size(tlv_value) {
129 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
130 Err(e) => format!("{{\"error\": \"{}\"}}", e),
131 }
132 }
133 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
134 }
135}
136
137pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
142 vec![
143 (0x0000, "PreferredExtendedPanID"),
144 (0x0001, "ThreadNetworks"),
145 (0x0002, "ThreadNetworkTableSize"),
146 ]
147}
148
149#[derive(Debug, serde::Serialize)]
150pub struct OperationalDatasetResponse {
151 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
152 pub operational_dataset: Option<Vec<u8>>,
153}
154
155pub fn decode_operational_dataset_response(inp: &tlv::TlvItemValue) -> anyhow::Result<OperationalDatasetResponse> {
159 if let tlv::TlvItemValue::List(_fields) = inp {
160 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
161 Ok(OperationalDatasetResponse {
162 operational_dataset: item.get_octet_string_owned(&[0]),
163 })
164 } else {
165 Err(anyhow::anyhow!("Expected struct fields"))
166 }
167}
168