matc/clusters/codec/
target_navigator.rs1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
17#[repr(u8)]
18pub enum Status {
19 Success = 0,
21 Targetnotfound = 1,
23 Notallowed = 2,
25}
26
27impl Status {
28 pub fn from_u8(value: u8) -> Option<Self> {
30 match value {
31 0 => Some(Status::Success),
32 1 => Some(Status::Targetnotfound),
33 2 => Some(Status::Notallowed),
34 _ => None,
35 }
36 }
37
38 pub fn to_u8(self) -> u8 {
40 self as u8
41 }
42}
43
44impl From<Status> for u8 {
45 fn from(val: Status) -> Self {
46 val as u8
47 }
48}
49
50#[derive(Debug, serde::Serialize)]
53pub struct TargetInfo {
54 pub identifier: Option<u8>,
55 pub name: Option<String>,
56}
57
58pub fn encode_navigate_target(target: u8, data: String) -> anyhow::Result<Vec<u8>> {
62 let tlv = tlv::TlvItemEnc {
63 tag: 0,
64 value: tlv::TlvItemValueEnc::StructInvisible(vec![
65 (0, tlv::TlvItemValueEnc::UInt8(target)).into(),
66 (1, tlv::TlvItemValueEnc::String(data)).into(),
67 ]),
68 };
69 Ok(tlv.encode()?)
70}
71
72pub fn decode_target_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<TargetInfo>> {
76 let mut res = Vec::new();
77 if let tlv::TlvItemValue::List(v) = inp {
78 for item in v {
79 res.push(TargetInfo {
80 identifier: item.get_int(&[0]).map(|v| v as u8),
81 name: item.get_string_owned(&[1]),
82 });
83 }
84 }
85 Ok(res)
86}
87
88pub fn decode_current_target(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
90 if let tlv::TlvItemValue::Int(v) = inp {
91 Ok(*v as u8)
92 } else {
93 Err(anyhow::anyhow!("Expected UInt8"))
94 }
95}
96
97
98pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
110 if cluster_id != 0x0505 {
112 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0505, got {}\"}}", cluster_id);
113 }
114
115 match attribute_id {
116 0x0000 => {
117 match decode_target_list(tlv_value) {
118 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
119 Err(e) => format!("{{\"error\": \"{}\"}}", e),
120 }
121 }
122 0x0001 => {
123 match decode_current_target(tlv_value) {
124 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
125 Err(e) => format!("{{\"error\": \"{}\"}}", e),
126 }
127 }
128 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
129 }
130}
131
132pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
137 vec![
138 (0x0000, "TargetList"),
139 (0x0001, "CurrentTarget"),
140 ]
141}
142
143#[derive(Debug, serde::Serialize)]
144pub struct NavigateTargetResponse {
145 pub status: Option<Status>,
146 pub data: Option<String>,
147}
148
149pub fn decode_navigate_target_response(inp: &tlv::TlvItemValue) -> anyhow::Result<NavigateTargetResponse> {
153 if let tlv::TlvItemValue::List(_fields) = inp {
154 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
155 Ok(NavigateTargetResponse {
156 status: item.get_int(&[0]).and_then(|v| Status::from_u8(v as u8)),
157 data: item.get_string_owned(&[1]),
158 })
159 } else {
160 Err(anyhow::anyhow!("Expected struct fields"))
161 }
162}
163
164#[derive(Debug, serde::Serialize)]
165pub struct TargetUpdatedEvent {
166 pub target_list: Option<Vec<TargetInfo>>,
167 pub current_target: Option<u8>,
168 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
169 pub data: Option<Vec<u8>>,
170}
171
172pub fn decode_target_updated_event(inp: &tlv::TlvItemValue) -> anyhow::Result<TargetUpdatedEvent> {
176 if let tlv::TlvItemValue::List(_fields) = inp {
177 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
178 Ok(TargetUpdatedEvent {
179 target_list: {
180 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
181 let mut items = Vec::new();
182 for list_item in l {
183 items.push(TargetInfo {
184 identifier: list_item.get_int(&[0]).map(|v| v as u8),
185 name: list_item.get_string_owned(&[1]),
186 });
187 }
188 Some(items)
189 } else {
190 None
191 }
192 },
193 current_target: item.get_int(&[1]).map(|v| v as u8),
194 data: item.get_octet_string_owned(&[2]),
195 })
196 } else {
197 Err(anyhow::anyhow!("Expected struct fields"))
198 }
199}
200