1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11#[derive(Debug, serde::Serialize)]
14pub struct NetworkInfo {
15 pub network_id: Option<Vec<u8>>,
16 pub connected: Option<bool>,
17}
18
19#[derive(Debug, serde::Serialize)]
20pub struct ThreadInterfaceScanResult {
21 pub pan_id: Option<u16>,
22 pub extended_pan_id: Option<u64>,
23 pub network_name: Option<String>,
24 pub channel: Option<u16>,
25 pub version: Option<u8>,
26 pub extended_address: Option<u8>,
27 pub rssi: Option<i8>,
28 pub lqi: Option<u8>,
29}
30
31#[derive(Debug, serde::Serialize)]
32pub struct WiFiInterfaceScanResult {
33 pub security: Option<u8>,
34 pub ssid: Option<Vec<u8>>,
35 pub bssid: Option<Vec<u8>>,
36 pub channel: Option<u16>,
37 pub wifi_band: Option<u8>,
38 pub rssi: Option<i8>,
39}
40
41pub fn encode_scan_networks(ssid: Option<Vec<u8>>, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
45 let tlv = tlv::TlvItemEnc {
46 tag: 0,
47 value: tlv::TlvItemValueEnc::StructInvisible(vec![
48 (0, tlv::TlvItemValueEnc::OctetString(ssid.unwrap_or_default())).into(),
49 (1, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
50 ]),
51 };
52 Ok(tlv.encode()?)
53}
54
55pub fn encode_add_or_update_wifi_network(ssid: Vec<u8>, credentials: Vec<u8>, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
57 let tlv = tlv::TlvItemEnc {
58 tag: 0,
59 value: tlv::TlvItemValueEnc::StructInvisible(vec![
60 (0, tlv::TlvItemValueEnc::OctetString(ssid)).into(),
61 (1, tlv::TlvItemValueEnc::OctetString(credentials)).into(),
62 (2, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
63 ]),
64 };
65 Ok(tlv.encode()?)
66}
67
68pub fn encode_add_or_update_thread_network(operational_dataset: Vec<u8>, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
70 let tlv = tlv::TlvItemEnc {
71 tag: 0,
72 value: tlv::TlvItemValueEnc::StructInvisible(vec![
73 (0, tlv::TlvItemValueEnc::OctetString(operational_dataset)).into(),
74 (1, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
75 ]),
76 };
77 Ok(tlv.encode()?)
78}
79
80pub fn encode_remove_network(network_id: Vec<u8>, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
82 let tlv = tlv::TlvItemEnc {
83 tag: 0,
84 value: tlv::TlvItemValueEnc::StructInvisible(vec![
85 (0, tlv::TlvItemValueEnc::OctetString(network_id)).into(),
86 (1, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
87 ]),
88 };
89 Ok(tlv.encode()?)
90}
91
92pub fn encode_connect_network(network_id: Vec<u8>, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
94 let tlv = tlv::TlvItemEnc {
95 tag: 0,
96 value: tlv::TlvItemValueEnc::StructInvisible(vec![
97 (0, tlv::TlvItemValueEnc::OctetString(network_id)).into(),
98 (1, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
99 ]),
100 };
101 Ok(tlv.encode()?)
102}
103
104pub fn encode_reorder_network(network_id: Vec<u8>, network_index: u8, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
106 let tlv = tlv::TlvItemEnc {
107 tag: 0,
108 value: tlv::TlvItemValueEnc::StructInvisible(vec![
109 (0, tlv::TlvItemValueEnc::OctetString(network_id)).into(),
110 (1, tlv::TlvItemValueEnc::UInt8(network_index)).into(),
111 (2, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
112 ]),
113 };
114 Ok(tlv.encode()?)
115}
116
117pub fn decode_max_networks(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
121 if let tlv::TlvItemValue::Int(v) = inp {
122 Ok(*v as u8)
123 } else {
124 Err(anyhow::anyhow!("Expected Integer"))
125 }
126}
127
128pub fn decode_networks(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NetworkInfo>> {
130 let mut res = Vec::new();
131 if let tlv::TlvItemValue::List(v) = inp {
132 for item in v {
133 res.push(NetworkInfo {
134 network_id: item.get_octet_string_owned(&[0]),
135 connected: item.get_bool(&[1]),
136 });
137 }
138 }
139 Ok(res)
140}
141
142pub fn decode_scan_max_time_seconds(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
144 if let tlv::TlvItemValue::Int(v) = inp {
145 Ok(*v as u8)
146 } else {
147 Err(anyhow::anyhow!("Expected Integer"))
148 }
149}
150
151pub fn decode_connect_max_time_seconds(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
153 if let tlv::TlvItemValue::Int(v) = inp {
154 Ok(*v as u8)
155 } else {
156 Err(anyhow::anyhow!("Expected Integer"))
157 }
158}
159
160pub fn decode_interface_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
162 if let tlv::TlvItemValue::Bool(v) = inp {
163 Ok(*v)
164 } else {
165 Err(anyhow::anyhow!("Expected Bool"))
166 }
167}
168
169pub fn decode_last_networking_status(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
171 if let tlv::TlvItemValue::Int(v) = inp {
172 Ok(Some(*v as u8))
173 } else {
174 Ok(None)
175 }
176}
177
178pub fn decode_last_network_id(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
180 if let tlv::TlvItemValue::OctetString(v) = inp {
181 Ok(Some(v.clone()))
182 } else {
183 Ok(None)
184 }
185}
186
187pub fn decode_last_connect_error_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i32>> {
189 if let tlv::TlvItemValue::Int(v) = inp {
190 Ok(Some(*v as i32))
191 } else {
192 Ok(None)
193 }
194}
195
196pub fn decode_supported_wifi_bands(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
198 let mut res = Vec::new();
199 if let tlv::TlvItemValue::List(v) = inp {
200 for item in v {
201 if let tlv::TlvItemValue::Int(i) = &item.value {
202 res.push(*i as u8);
203 }
204 }
205 }
206 Ok(res)
207}
208
209pub fn decode_supported_thread_features(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
211 if let tlv::TlvItemValue::Int(v) = inp {
212 Ok(*v as u8)
213 } else {
214 Err(anyhow::anyhow!("Expected Integer"))
215 }
216}
217
218pub fn decode_thread_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
220 if let tlv::TlvItemValue::Int(v) = inp {
221 Ok(*v as u16)
222 } else {
223 Err(anyhow::anyhow!("Expected Integer"))
224 }
225}
226
227
228pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
240 if cluster_id != 0x0031 {
242 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0031, got {}\"}}", cluster_id);
243 }
244
245 match attribute_id {
246 0x0000 => {
247 match decode_max_networks(tlv_value) {
248 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
249 Err(e) => format!("{{\"error\": \"{}\"}}", e),
250 }
251 }
252 0x0001 => {
253 match decode_networks(tlv_value) {
254 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
255 Err(e) => format!("{{\"error\": \"{}\"}}", e),
256 }
257 }
258 0x0002 => {
259 match decode_scan_max_time_seconds(tlv_value) {
260 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
261 Err(e) => format!("{{\"error\": \"{}\"}}", e),
262 }
263 }
264 0x0003 => {
265 match decode_connect_max_time_seconds(tlv_value) {
266 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
267 Err(e) => format!("{{\"error\": \"{}\"}}", e),
268 }
269 }
270 0x0004 => {
271 match decode_interface_enabled(tlv_value) {
272 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
273 Err(e) => format!("{{\"error\": \"{}\"}}", e),
274 }
275 }
276 0x0005 => {
277 match decode_last_networking_status(tlv_value) {
278 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
279 Err(e) => format!("{{\"error\": \"{}\"}}", e),
280 }
281 }
282 0x0006 => {
283 match decode_last_network_id(tlv_value) {
284 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
285 Err(e) => format!("{{\"error\": \"{}\"}}", e),
286 }
287 }
288 0x0007 => {
289 match decode_last_connect_error_value(tlv_value) {
290 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
291 Err(e) => format!("{{\"error\": \"{}\"}}", e),
292 }
293 }
294 0x0008 => {
295 match decode_supported_wifi_bands(tlv_value) {
296 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
297 Err(e) => format!("{{\"error\": \"{}\"}}", e),
298 }
299 }
300 0x0009 => {
301 match decode_supported_thread_features(tlv_value) {
302 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
303 Err(e) => format!("{{\"error\": \"{}\"}}", e),
304 }
305 }
306 0x000A => {
307 match decode_thread_version(tlv_value) {
308 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
309 Err(e) => format!("{{\"error\": \"{}\"}}", e),
310 }
311 }
312 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
313 }
314}
315
316pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
321 vec![
322 (0x0000, "MaxNetworks"),
323 (0x0001, "Networks"),
324 (0x0002, "ScanMaxTimeSeconds"),
325 (0x0003, "ConnectMaxTimeSeconds"),
326 (0x0004, "InterfaceEnabled"),
327 (0x0005, "LastNetworkingStatus"),
328 (0x0006, "LastNetworkID"),
329 (0x0007, "LastConnectErrorValue"),
330 (0x0008, "SupportedWiFiBands"),
331 (0x0009, "SupportedThreadFeatures"),
332 (0x000A, "ThreadVersion"),
333 ]
334}
335