matc/clusters/codec/
target_navigator.rs

1//! Matter TLV encoders and decoders for Target Navigator Cluster
2//! Cluster ID: 0x0505
3//!
4//! This file is automatically generated from TargetNavigator.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Import serialization helpers for octet strings
12use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
13
14// Enum definitions
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
17#[repr(u8)]
18pub enum Status {
19    /// Command succeeded
20    Success = 0,
21    /// Requested target was not found in the TargetList
22    Targetnotfound = 1,
23    /// Target request is not allowed in current state.
24    Notallowed = 2,
25}
26
27impl Status {
28    /// Convert from u8 value
29    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    /// Convert to u8 value
39    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// Struct definitions
51
52#[derive(Debug, serde::Serialize)]
53pub struct TargetInfo {
54    pub identifier: Option<u8>,
55    pub name: Option<String>,
56}
57
58// Command encoders
59
60/// Encode NavigateTarget command (0x00)
61pub 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
72// Attribute decoders
73
74/// Decode TargetList attribute (0x0000)
75pub 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
88/// Decode CurrentTarget attribute (0x0001)
89pub 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
98// JSON dispatcher function
99
100/// Decode attribute value and return as JSON string
101///
102/// # Parameters
103/// * `cluster_id` - The cluster identifier
104/// * `attribute_id` - The attribute identifier
105/// * `tlv_value` - The TLV value to decode
106///
107/// # Returns
108/// JSON string representation of the decoded value or error
109pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
110    // Verify this is the correct cluster
111    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
132/// Get list of all attributes supported by this cluster
133///
134/// # Returns
135/// Vector of tuples containing (attribute_id, attribute_name)
136pub 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
149// Command response decoders
150
151/// Decode NavigateTargetResponse command response (01)
152pub 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
172// Event decoders
173
174/// Decode TargetUpdated event (0x00, priority: info)
175pub 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