matc/clusters/codec/
diagnostic_logs_cluster.rs

1//! Matter TLV encoders and decoders for Diagnostic Logs Cluster
2//! Cluster ID: 0x0032
3//!
4//! This file is automatically generated from DiagnosticLogsCluster.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Import serialization helpers for octet strings
14use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
15
16// Enum definitions
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum Intent {
21    /// Logs to be used for end-user support
22    Endusersupport = 0,
23    /// Logs to be used for network diagnostics
24    Networkdiag = 1,
25    /// Obtain crash logs from the Node
26    Crashlogs = 2,
27}
28
29impl Intent {
30    /// Convert from u8 value
31    pub fn from_u8(value: u8) -> Option<Self> {
32        match value {
33            0 => Some(Intent::Endusersupport),
34            1 => Some(Intent::Networkdiag),
35            2 => Some(Intent::Crashlogs),
36            _ => None,
37        }
38    }
39
40    /// Convert to u8 value
41    pub fn to_u8(self) -> u8 {
42        self as u8
43    }
44}
45
46impl From<Intent> for u8 {
47    fn from(val: Intent) -> Self {
48        val as u8
49    }
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
53#[repr(u8)]
54pub enum Status {
55    /// Successful transfer of logs
56    Success = 0,
57    /// All logs have been transferred
58    Exhausted = 1,
59    /// No logs of the requested type available
60    Nologs = 2,
61    /// Unable to handle request, retry later
62    Busy = 3,
63    /// The request is denied, no logs being transferred
64    Denied = 4,
65}
66
67impl Status {
68    /// Convert from u8 value
69    pub fn from_u8(value: u8) -> Option<Self> {
70        match value {
71            0 => Some(Status::Success),
72            1 => Some(Status::Exhausted),
73            2 => Some(Status::Nologs),
74            3 => Some(Status::Busy),
75            4 => Some(Status::Denied),
76            _ => None,
77        }
78    }
79
80    /// Convert to u8 value
81    pub fn to_u8(self) -> u8 {
82        self as u8
83    }
84}
85
86impl From<Status> for u8 {
87    fn from(val: Status) -> Self {
88        val as u8
89    }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
93#[repr(u8)]
94pub enum TransferProtocol {
95    /// Logs to be returned as a response
96    Responsepayload = 0,
97    /// Logs to be returned using BDX
98    Bdx = 1,
99}
100
101impl TransferProtocol {
102    /// Convert from u8 value
103    pub fn from_u8(value: u8) -> Option<Self> {
104        match value {
105            0 => Some(TransferProtocol::Responsepayload),
106            1 => Some(TransferProtocol::Bdx),
107            _ => None,
108        }
109    }
110
111    /// Convert to u8 value
112    pub fn to_u8(self) -> u8 {
113        self as u8
114    }
115}
116
117impl From<TransferProtocol> for u8 {
118    fn from(val: TransferProtocol) -> Self {
119        val as u8
120    }
121}
122
123// Command encoders
124
125/// Encode RetrieveLogsRequest command (0x00)
126pub fn encode_retrieve_logs_request(intent: Intent, requested_protocol: TransferProtocol, transfer_file_designator: String) -> anyhow::Result<Vec<u8>> {
127    let tlv = tlv::TlvItemEnc {
128        tag: 0,
129        value: tlv::TlvItemValueEnc::StructInvisible(vec![
130        (0, tlv::TlvItemValueEnc::UInt8(intent.to_u8())).into(),
131        (1, tlv::TlvItemValueEnc::UInt8(requested_protocol.to_u8())).into(),
132        (2, tlv::TlvItemValueEnc::String(transfer_file_designator)).into(),
133        ]),
134    };
135    Ok(tlv.encode()?)
136}
137
138// Command listing
139
140pub fn get_command_list() -> Vec<(u32, &'static str)> {
141    vec![
142        (0x00, "RetrieveLogsRequest"),
143    ]
144}
145
146pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
147    match cmd_id {
148        0x00 => Some("RetrieveLogsRequest"),
149        _ => None,
150    }
151}
152
153pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
154    match cmd_id {
155        0x00 => Some(vec![
156            crate::clusters::codec::CommandField { tag: 0, name: "intent", kind: crate::clusters::codec::FieldKind::Enum { name: "Intent", variants: &[(0, "Endusersupport"), (1, "Networkdiag"), (2, "Crashlogs")] }, optional: false, nullable: false },
157            crate::clusters::codec::CommandField { tag: 1, name: "requested_protocol", kind: crate::clusters::codec::FieldKind::Enum { name: "TransferProtocol", variants: &[(0, "Responsepayload"), (1, "Bdx")] }, optional: false, nullable: false },
158            crate::clusters::codec::CommandField { tag: 2, name: "transfer_file_designator", kind: crate::clusters::codec::FieldKind::String, optional: true, nullable: false },
159        ]),
160        _ => None,
161    }
162}
163
164pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
165    match cmd_id {
166        0x00 => {
167        let intent = {
168            let n = crate::clusters::codec::json_util::get_u64(args, "intent")?;
169            Intent::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid Intent: {}", n))?
170        };
171        let requested_protocol = {
172            let n = crate::clusters::codec::json_util::get_u64(args, "requested_protocol")?;
173            TransferProtocol::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid TransferProtocol: {}", n))?
174        };
175        let transfer_file_designator = crate::clusters::codec::json_util::get_string(args, "transfer_file_designator")?;
176        encode_retrieve_logs_request(intent, requested_protocol, transfer_file_designator)
177        }
178        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
179    }
180}
181
182#[derive(Debug, serde::Serialize)]
183pub struct RetrieveLogsResponse {
184    pub status: Option<Status>,
185    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
186    pub log_content: Option<Vec<u8>>,
187    pub utc_time_stamp: Option<u64>,
188    pub time_since_boot: Option<u8>,
189}
190
191// Command response decoders
192
193/// Decode RetrieveLogsResponse command response (01)
194pub fn decode_retrieve_logs_response(inp: &tlv::TlvItemValue) -> anyhow::Result<RetrieveLogsResponse> {
195    if let tlv::TlvItemValue::List(_fields) = inp {
196        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
197        Ok(RetrieveLogsResponse {
198                status: item.get_int(&[0]).and_then(|v| Status::from_u8(v as u8)),
199                log_content: item.get_octet_string_owned(&[1]),
200                utc_time_stamp: item.get_int(&[2]),
201                time_since_boot: item.get_int(&[3]).map(|v| v as u8),
202        })
203    } else {
204        Err(anyhow::anyhow!("Expected struct fields"))
205    }
206}
207
208// Typed facade (invokes + reads)
209
210/// Invoke `RetrieveLogsRequest` command on cluster `Diagnostic Logs`.
211pub async fn retrieve_logs_request(conn: &crate::controller::Connection, endpoint: u16, intent: Intent, requested_protocol: TransferProtocol, transfer_file_designator: String) -> anyhow::Result<RetrieveLogsResponse> {
212    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DIAGNOSTIC_LOGS, crate::clusters::defs::CLUSTER_DIAGNOSTIC_LOGS_CMD_ID_RETRIEVELOGSREQUEST, &encode_retrieve_logs_request(intent, requested_protocol, transfer_file_designator)?).await?;
213    decode_retrieve_logs_response(&tlv)
214}
215