matc/clusters/codec/
thread_border_router_diagnostics.rs1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum BorderRouterOperationalStatus {
18 Running = 0,
20 Stopped = 1,
22 Disabled = 2,
24}
25
26impl BorderRouterOperationalStatus {
27 pub fn from_u8(value: u8) -> Option<Self> {
29 match value {
30 0 => Some(BorderRouterOperationalStatus::Running),
31 1 => Some(BorderRouterOperationalStatus::Stopped),
32 2 => Some(BorderRouterOperationalStatus::Disabled),
33 _ => None,
34 }
35 }
36
37 pub fn to_u8(self) -> u8 {
39 self as u8
40 }
41}
42
43impl From<BorderRouterOperationalStatus> for u8 {
44 fn from(val: BorderRouterOperationalStatus) -> Self {
45 val as u8
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
50#[repr(u8)]
51pub enum ThreadBorderRouterFault {
52 Brgeneralfault = 0,
54 Adjacentinfraiffault = 1,
56 Servicesatcapacity = 2,
58 Childrenatcapacity = 3,
60}
61
62impl ThreadBorderRouterFault {
63 pub fn from_u8(value: u8) -> Option<Self> {
65 match value {
66 0 => Some(ThreadBorderRouterFault::Brgeneralfault),
67 1 => Some(ThreadBorderRouterFault::Adjacentinfraiffault),
68 2 => Some(ThreadBorderRouterFault::Servicesatcapacity),
69 3 => Some(ThreadBorderRouterFault::Childrenatcapacity),
70 _ => None,
71 }
72 }
73
74 pub fn to_u8(self) -> u8 {
76 self as u8
77 }
78}
79
80impl From<ThreadBorderRouterFault> for u8 {
81 fn from(val: ThreadBorderRouterFault) -> Self {
82 val as u8
83 }
84}
85
86pub fn decode_br_status(inp: &tlv::TlvItemValue) -> anyhow::Result<BorderRouterOperationalStatus> {
90 if let tlv::TlvItemValue::Int(v) = inp {
91 BorderRouterOperationalStatus::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
92 } else {
93 Err(anyhow::anyhow!("Expected Integer"))
94 }
95}
96
97pub fn decode_active_tbr_faults_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<ThreadBorderRouterFault>> {
99 let mut res = Vec::new();
100 if let tlv::TlvItemValue::List(v) = inp {
101 for item in v {
102 if let tlv::TlvItemValue::Int(i) = &item.value {
103 if let Some(enum_val) = ThreadBorderRouterFault::from_u8(*i as u8) {
104 res.push(enum_val);
105 }
106 }
107 }
108 }
109 Ok(res)
110}
111
112
113pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
125 if cluster_id != 0x0454 {
127 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0454, got {}\"}}", cluster_id);
128 }
129
130 match attribute_id {
131 0x0000 => {
132 match decode_br_status(tlv_value) {
133 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
134 Err(e) => format!("{{\"error\": \"{}\"}}", e),
135 }
136 }
137 0x0001 => {
138 match decode_active_tbr_faults_list(tlv_value) {
139 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
140 Err(e) => format!("{{\"error\": \"{}\"}}", e),
141 }
142 }
143 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
144 }
145}
146
147pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
152 vec![
153 (0x0000, "BrStatus"),
154 (0x0001, "ActiveTbrFaultsList"),
155 ]
156}
157
158pub async fn read_br_status(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<BorderRouterOperationalStatus> {
162 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THREAD_BORDER_ROUTER_DIAGNOSTICS, crate::clusters::defs::CLUSTER_THREAD_BORDER_ROUTER_DIAGNOSTICS_ATTR_ID_BRSTATUS).await?;
163 decode_br_status(&tlv)
164}
165
166pub async fn read_active_tbr_faults_list(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<ThreadBorderRouterFault>> {
168 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THREAD_BORDER_ROUTER_DIAGNOSTICS, crate::clusters::defs::CLUSTER_THREAD_BORDER_ROUTER_DIAGNOSTICS_ATTR_ID_ACTIVETBRFAULTSLIST).await?;
169 decode_active_tbr_faults_list(&tlv)
170}
171