matc/clusters/codec/
diagnostics_software.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 ThreadMetrics {
18 pub id: Option<u64>,
19 pub name: Option<String>,
20 pub stack_free_current: Option<u32>,
21 pub stack_free_minimum: Option<u32>,
22 pub stack_size: Option<u32>,
23}
24
25pub fn decode_thread_metrics(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<ThreadMetrics>> {
31 let mut res = Vec::new();
32 if let tlv::TlvItemValue::List(v) = inp {
33 for item in v {
34 res.push(ThreadMetrics {
35 id: item.get_int(&[0]),
36 name: item.get_string_owned(&[1]),
37 stack_free_current: item.get_int(&[2]).map(|v| v as u32),
38 stack_free_minimum: item.get_int(&[3]).map(|v| v as u32),
39 stack_size: item.get_int(&[4]).map(|v| v as u32),
40 });
41 }
42 }
43 Ok(res)
44}
45
46pub fn decode_current_heap_free(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
48 if let tlv::TlvItemValue::Int(v) = inp {
49 Ok(*v)
50 } else {
51 Err(anyhow::anyhow!("Expected UInt64"))
52 }
53}
54
55pub fn decode_current_heap_used(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
57 if let tlv::TlvItemValue::Int(v) = inp {
58 Ok(*v)
59 } else {
60 Err(anyhow::anyhow!("Expected UInt64"))
61 }
62}
63
64pub fn decode_current_heap_high_watermark(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
66 if let tlv::TlvItemValue::Int(v) = inp {
67 Ok(*v)
68 } else {
69 Err(anyhow::anyhow!("Expected UInt64"))
70 }
71}
72
73
74pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
86 if cluster_id != 0x0034 {
88 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0034, got {}\"}}", cluster_id);
89 }
90
91 match attribute_id {
92 0x0000 => {
93 match decode_thread_metrics(tlv_value) {
94 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
95 Err(e) => format!("{{\"error\": \"{}\"}}", e),
96 }
97 }
98 0x0001 => {
99 match decode_current_heap_free(tlv_value) {
100 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
101 Err(e) => format!("{{\"error\": \"{}\"}}", e),
102 }
103 }
104 0x0002 => {
105 match decode_current_heap_used(tlv_value) {
106 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
107 Err(e) => format!("{{\"error\": \"{}\"}}", e),
108 }
109 }
110 0x0003 => {
111 match decode_current_heap_high_watermark(tlv_value) {
112 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
113 Err(e) => format!("{{\"error\": \"{}\"}}", e),
114 }
115 }
116 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
117 }
118}
119
120pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
125 vec![
126 (0x0000, "ThreadMetrics"),
127 (0x0001, "CurrentHeapFree"),
128 (0x0002, "CurrentHeapUsed"),
129 (0x0003, "CurrentHeapHighWatermark"),
130 ]
131}
132
133#[derive(Debug, serde::Serialize)]
134pub struct SoftwareFaultEvent {
135 pub id: Option<u64>,
136 pub name: Option<String>,
137 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
138 pub fault_recording: Option<Vec<u8>>,
139}
140
141pub fn decode_software_fault_event(inp: &tlv::TlvItemValue) -> anyhow::Result<SoftwareFaultEvent> {
145 if let tlv::TlvItemValue::List(_fields) = inp {
146 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
147 Ok(SoftwareFaultEvent {
148 id: item.get_int(&[0]),
149 name: item.get_string_owned(&[1]),
150 fault_recording: item.get_octet_string_owned(&[2]),
151 })
152 } else {
153 Err(anyhow::anyhow!("Expected struct fields"))
154 }
155}
156