matc/clusters/codec/
diagnostics_wifi.rs

1//! Matter TLV encoders and decoders for Wi-Fi Network Diagnostics Cluster
2//! Cluster ID: 0x0036
3//!
4//! This file is automatically generated from DiagnosticsWiFi.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Enum definitions
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum AssociationFailureCause {
18    /// The reason for the failure is unknown.
19    Unknown = 0,
20    /// An error occurred during association.
21    Associationfailed = 1,
22    /// An error occurred during authentication.
23    Authenticationfailed = 2,
24    /// The specified SSID could not be found.
25    Ssidnotfound = 3,
26}
27
28impl AssociationFailureCause {
29    /// Convert from u8 value
30    pub fn from_u8(value: u8) -> Option<Self> {
31        match value {
32            0 => Some(AssociationFailureCause::Unknown),
33            1 => Some(AssociationFailureCause::Associationfailed),
34            2 => Some(AssociationFailureCause::Authenticationfailed),
35            3 => Some(AssociationFailureCause::Ssidnotfound),
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<AssociationFailureCause> for u8 {
47    fn from(val: AssociationFailureCause) -> Self {
48        val as u8
49    }
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
53#[repr(u8)]
54pub enum ConnectionStatus {
55    /// Indicate the node is connected
56    Connected = 0,
57    /// Indicate the node is not connected
58    Notconnected = 1,
59}
60
61impl ConnectionStatus {
62    /// Convert from u8 value
63    pub fn from_u8(value: u8) -> Option<Self> {
64        match value {
65            0 => Some(ConnectionStatus::Connected),
66            1 => Some(ConnectionStatus::Notconnected),
67            _ => None,
68        }
69    }
70
71    /// Convert to u8 value
72    pub fn to_u8(self) -> u8 {
73        self as u8
74    }
75}
76
77impl From<ConnectionStatus> for u8 {
78    fn from(val: ConnectionStatus) -> Self {
79        val as u8
80    }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
84#[repr(u8)]
85pub enum SecurityType {
86    /// Indicate the usage of an unspecified Wi-Fi security type
87    Unspecified = 0,
88    /// Indicate the usage of no Wi-Fi security
89    None = 1,
90    /// Indicate the usage of WEP Wi-Fi security
91    Wep = 2,
92    /// Indicate the usage of WPA Wi-Fi security
93    Wpa = 3,
94    /// Indicate the usage of WPA2 Wi-Fi security
95    Wpa2 = 4,
96    /// Indicate the usage of WPA3 Wi-Fi security
97    Wpa3 = 5,
98}
99
100impl SecurityType {
101    /// Convert from u8 value
102    pub fn from_u8(value: u8) -> Option<Self> {
103        match value {
104            0 => Some(SecurityType::Unspecified),
105            1 => Some(SecurityType::None),
106            2 => Some(SecurityType::Wep),
107            3 => Some(SecurityType::Wpa),
108            4 => Some(SecurityType::Wpa2),
109            5 => Some(SecurityType::Wpa3),
110            _ => None,
111        }
112    }
113
114    /// Convert to u8 value
115    pub fn to_u8(self) -> u8 {
116        self as u8
117    }
118}
119
120impl From<SecurityType> for u8 {
121    fn from(val: SecurityType) -> Self {
122        val as u8
123    }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
127#[repr(u8)]
128pub enum WiFiVersion {
129    /// Indicate the network interface is currently using IEEE 802.11a against the wireless access point.
130    A = 0,
131    /// Indicate the network interface is currently using IEEE 802.11b against the wireless access point.
132    B = 1,
133    /// Indicate the network interface is currently using IEEE 802.11g against the wireless access point.
134    G = 2,
135    /// Indicate the network interface is currently using IEEE 802.11n against the wireless access point.
136    N = 3,
137    /// Indicate the network interface is currently using IEEE 802.11ac against the wireless access point.
138    Ac = 4,
139    /// Indicate the network interface is currently using IEEE 802.11ax against the wireless access point.
140    Ax = 5,
141    /// Indicate the network interface is currently using IEEE 802.11ah against the wireless access point.
142    Ah = 6,
143}
144
145impl WiFiVersion {
146    /// Convert from u8 value
147    pub fn from_u8(value: u8) -> Option<Self> {
148        match value {
149            0 => Some(WiFiVersion::A),
150            1 => Some(WiFiVersion::B),
151            2 => Some(WiFiVersion::G),
152            3 => Some(WiFiVersion::N),
153            4 => Some(WiFiVersion::Ac),
154            5 => Some(WiFiVersion::Ax),
155            6 => Some(WiFiVersion::Ah),
156            _ => None,
157        }
158    }
159
160    /// Convert to u8 value
161    pub fn to_u8(self) -> u8 {
162        self as u8
163    }
164}
165
166impl From<WiFiVersion> for u8 {
167    fn from(val: WiFiVersion) -> Self {
168        val as u8
169    }
170}
171
172// Command encoders
173
174// Attribute decoders
175
176/// Decode BSSID attribute (0x0000)
177pub fn decode_bssid(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
178    if let tlv::TlvItemValue::OctetString(v) = inp {
179        Ok(Some(v.clone()))
180    } else {
181        Ok(None)
182    }
183}
184
185/// Decode SecurityType attribute (0x0001)
186pub fn decode_security_type(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<SecurityType>> {
187    if let tlv::TlvItemValue::Int(v) = inp {
188        Ok(SecurityType::from_u8(*v as u8))
189    } else {
190        Ok(None)
191    }
192}
193
194/// Decode WiFiVersion attribute (0x0002)
195pub fn decode_wifi_version(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<WiFiVersion>> {
196    if let tlv::TlvItemValue::Int(v) = inp {
197        Ok(WiFiVersion::from_u8(*v as u8))
198    } else {
199        Ok(None)
200    }
201}
202
203/// Decode ChannelNumber attribute (0x0003)
204pub fn decode_channel_number(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
205    if let tlv::TlvItemValue::Int(v) = inp {
206        Ok(Some(*v as u16))
207    } else {
208        Ok(None)
209    }
210}
211
212/// Decode RSSI attribute (0x0004)
213pub fn decode_rssi(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i8>> {
214    if let tlv::TlvItemValue::Int(v) = inp {
215        Ok(Some(*v as i8))
216    } else {
217        Ok(None)
218    }
219}
220
221/// Decode BeaconLostCount attribute (0x0005)
222pub fn decode_beacon_lost_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
223    if let tlv::TlvItemValue::Int(v) = inp {
224        Ok(Some(*v as u32))
225    } else {
226        Ok(None)
227    }
228}
229
230/// Decode BeaconRxCount attribute (0x0006)
231pub fn decode_beacon_rx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
232    if let tlv::TlvItemValue::Int(v) = inp {
233        Ok(Some(*v as u32))
234    } else {
235        Ok(None)
236    }
237}
238
239/// Decode PacketMulticastRxCount attribute (0x0007)
240pub fn decode_packet_multicast_rx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
241    if let tlv::TlvItemValue::Int(v) = inp {
242        Ok(Some(*v as u32))
243    } else {
244        Ok(None)
245    }
246}
247
248/// Decode PacketMulticastTxCount attribute (0x0008)
249pub fn decode_packet_multicast_tx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
250    if let tlv::TlvItemValue::Int(v) = inp {
251        Ok(Some(*v as u32))
252    } else {
253        Ok(None)
254    }
255}
256
257/// Decode PacketUnicastRxCount attribute (0x0009)
258pub fn decode_packet_unicast_rx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
259    if let tlv::TlvItemValue::Int(v) = inp {
260        Ok(Some(*v as u32))
261    } else {
262        Ok(None)
263    }
264}
265
266/// Decode PacketUnicastTxCount attribute (0x000A)
267pub fn decode_packet_unicast_tx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
268    if let tlv::TlvItemValue::Int(v) = inp {
269        Ok(Some(*v as u32))
270    } else {
271        Ok(None)
272    }
273}
274
275/// Decode CurrentMaxRate attribute (0x000B)
276pub fn decode_current_max_rate(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
277    if let tlv::TlvItemValue::Int(v) = inp {
278        Ok(Some(*v))
279    } else {
280        Ok(None)
281    }
282}
283
284/// Decode OverrunCount attribute (0x000C)
285pub fn decode_overrun_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
286    if let tlv::TlvItemValue::Int(v) = inp {
287        Ok(Some(*v))
288    } else {
289        Ok(None)
290    }
291}
292
293
294// JSON dispatcher function
295
296/// Decode attribute value and return as JSON string
297///
298/// # Parameters
299/// * `cluster_id` - The cluster identifier
300/// * `attribute_id` - The attribute identifier
301/// * `tlv_value` - The TLV value to decode
302///
303/// # Returns
304/// JSON string representation of the decoded value or error
305pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
306    // Verify this is the correct cluster
307    if cluster_id != 0x0036 {
308        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0036, got {}\"}}", cluster_id);
309    }
310
311    match attribute_id {
312        0x0000 => {
313            match decode_bssid(tlv_value) {
314                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
315                Err(e) => format!("{{\"error\": \"{}\"}}", e),
316            }
317        }
318        0x0001 => {
319            match decode_security_type(tlv_value) {
320                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
321                Err(e) => format!("{{\"error\": \"{}\"}}", e),
322            }
323        }
324        0x0002 => {
325            match decode_wifi_version(tlv_value) {
326                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
327                Err(e) => format!("{{\"error\": \"{}\"}}", e),
328            }
329        }
330        0x0003 => {
331            match decode_channel_number(tlv_value) {
332                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
333                Err(e) => format!("{{\"error\": \"{}\"}}", e),
334            }
335        }
336        0x0004 => {
337            match decode_rssi(tlv_value) {
338                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
339                Err(e) => format!("{{\"error\": \"{}\"}}", e),
340            }
341        }
342        0x0005 => {
343            match decode_beacon_lost_count(tlv_value) {
344                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
345                Err(e) => format!("{{\"error\": \"{}\"}}", e),
346            }
347        }
348        0x0006 => {
349            match decode_beacon_rx_count(tlv_value) {
350                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
351                Err(e) => format!("{{\"error\": \"{}\"}}", e),
352            }
353        }
354        0x0007 => {
355            match decode_packet_multicast_rx_count(tlv_value) {
356                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
357                Err(e) => format!("{{\"error\": \"{}\"}}", e),
358            }
359        }
360        0x0008 => {
361            match decode_packet_multicast_tx_count(tlv_value) {
362                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
363                Err(e) => format!("{{\"error\": \"{}\"}}", e),
364            }
365        }
366        0x0009 => {
367            match decode_packet_unicast_rx_count(tlv_value) {
368                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
369                Err(e) => format!("{{\"error\": \"{}\"}}", e),
370            }
371        }
372        0x000A => {
373            match decode_packet_unicast_tx_count(tlv_value) {
374                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
375                Err(e) => format!("{{\"error\": \"{}\"}}", e),
376            }
377        }
378        0x000B => {
379            match decode_current_max_rate(tlv_value) {
380                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
381                Err(e) => format!("{{\"error\": \"{}\"}}", e),
382            }
383        }
384        0x000C => {
385            match decode_overrun_count(tlv_value) {
386                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
387                Err(e) => format!("{{\"error\": \"{}\"}}", e),
388            }
389        }
390        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
391    }
392}
393
394/// Get list of all attributes supported by this cluster
395///
396/// # Returns
397/// Vector of tuples containing (attribute_id, attribute_name)
398pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
399    vec![
400        (0x0000, "BSSID"),
401        (0x0001, "SecurityType"),
402        (0x0002, "WiFiVersion"),
403        (0x0003, "ChannelNumber"),
404        (0x0004, "RSSI"),
405        (0x0005, "BeaconLostCount"),
406        (0x0006, "BeaconRxCount"),
407        (0x0007, "PacketMulticastRxCount"),
408        (0x0008, "PacketMulticastTxCount"),
409        (0x0009, "PacketUnicastRxCount"),
410        (0x000A, "PacketUnicastTxCount"),
411        (0x000B, "CurrentMaxRate"),
412        (0x000C, "OverrunCount"),
413    ]
414}
415
416// Command listing
417
418pub fn get_command_list() -> Vec<(u32, &'static str)> {
419    vec![
420        (0x00, "ResetCounts"),
421    ]
422}
423
424pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
425    match cmd_id {
426        0x00 => Some("ResetCounts"),
427        _ => None,
428    }
429}
430
431pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
432    match cmd_id {
433        0x00 => Some(vec![]),
434        _ => None,
435    }
436}
437
438pub fn encode_command_json(cmd_id: u32, _args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
439    match cmd_id {
440        0x00 => Ok(vec![]),
441        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
442    }
443}
444
445// Typed facade (invokes + reads)
446
447/// Invoke `ResetCounts` command on cluster `Wi-Fi Network Diagnostics`.
448pub async fn reset_counts(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
449    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_CMD_ID_RESETCOUNTS, &[]).await?;
450    Ok(())
451}
452
453/// Read `BSSID` attribute from cluster `Wi-Fi Network Diagnostics`.
454pub async fn read_bssid(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
455    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_BSSID).await?;
456    decode_bssid(&tlv)
457}
458
459/// Read `SecurityType` attribute from cluster `Wi-Fi Network Diagnostics`.
460pub async fn read_security_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<SecurityType>> {
461    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_SECURITYTYPE).await?;
462    decode_security_type(&tlv)
463}
464
465/// Read `WiFiVersion` attribute from cluster `Wi-Fi Network Diagnostics`.
466pub async fn read_wifi_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<WiFiVersion>> {
467    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_WIFIVERSION).await?;
468    decode_wifi_version(&tlv)
469}
470
471/// Read `ChannelNumber` attribute from cluster `Wi-Fi Network Diagnostics`.
472pub async fn read_channel_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u16>> {
473    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_CHANNELNUMBER).await?;
474    decode_channel_number(&tlv)
475}
476
477/// Read `RSSI` attribute from cluster `Wi-Fi Network Diagnostics`.
478pub async fn read_rssi(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<i8>> {
479    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_RSSI).await?;
480    decode_rssi(&tlv)
481}
482
483/// Read `BeaconLostCount` attribute from cluster `Wi-Fi Network Diagnostics`.
484pub async fn read_beacon_lost_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
485    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_BEACONLOSTCOUNT).await?;
486    decode_beacon_lost_count(&tlv)
487}
488
489/// Read `BeaconRxCount` attribute from cluster `Wi-Fi Network Diagnostics`.
490pub async fn read_beacon_rx_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
491    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_BEACONRXCOUNT).await?;
492    decode_beacon_rx_count(&tlv)
493}
494
495/// Read `PacketMulticastRxCount` attribute from cluster `Wi-Fi Network Diagnostics`.
496pub async fn read_packet_multicast_rx_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
497    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_PACKETMULTICASTRXCOUNT).await?;
498    decode_packet_multicast_rx_count(&tlv)
499}
500
501/// Read `PacketMulticastTxCount` attribute from cluster `Wi-Fi Network Diagnostics`.
502pub async fn read_packet_multicast_tx_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
503    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_PACKETMULTICASTTXCOUNT).await?;
504    decode_packet_multicast_tx_count(&tlv)
505}
506
507/// Read `PacketUnicastRxCount` attribute from cluster `Wi-Fi Network Diagnostics`.
508pub async fn read_packet_unicast_rx_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
509    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_PACKETUNICASTRXCOUNT).await?;
510    decode_packet_unicast_rx_count(&tlv)
511}
512
513/// Read `PacketUnicastTxCount` attribute from cluster `Wi-Fi Network Diagnostics`.
514pub async fn read_packet_unicast_tx_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
515    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_PACKETUNICASTTXCOUNT).await?;
516    decode_packet_unicast_tx_count(&tlv)
517}
518
519/// Read `CurrentMaxRate` attribute from cluster `Wi-Fi Network Diagnostics`.
520pub async fn read_current_max_rate(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u64>> {
521    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_CURRENTMAXRATE).await?;
522    decode_current_max_rate(&tlv)
523}
524
525/// Read `OverrunCount` attribute from cluster `Wi-Fi Network Diagnostics`.
526pub async fn read_overrun_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u64>> {
527    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_OVERRUNCOUNT).await?;
528    decode_overrun_count(&tlv)
529}
530
531#[derive(Debug, serde::Serialize)]
532pub struct DisconnectionEvent {
533    pub reason_code: Option<u16>,
534}
535
536#[derive(Debug, serde::Serialize)]
537pub struct AssociationFailureEvent {
538    pub association_failure_cause: Option<AssociationFailureCause>,
539    pub status: Option<u16>,
540}
541
542#[derive(Debug, serde::Serialize)]
543pub struct ConnectionStatusEvent {
544    pub connection_status: Option<ConnectionStatus>,
545}
546
547// Event decoders
548
549/// Decode Disconnection event (0x00, priority: info)
550pub fn decode_disconnection_event(inp: &tlv::TlvItemValue) -> anyhow::Result<DisconnectionEvent> {
551    if let tlv::TlvItemValue::List(_fields) = inp {
552        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
553        Ok(DisconnectionEvent {
554                                reason_code: item.get_int(&[0]).map(|v| v as u16),
555        })
556    } else {
557        Err(anyhow::anyhow!("Expected struct fields"))
558    }
559}
560
561/// Decode AssociationFailure event (0x01, priority: info)
562pub fn decode_association_failure_event(inp: &tlv::TlvItemValue) -> anyhow::Result<AssociationFailureEvent> {
563    if let tlv::TlvItemValue::List(_fields) = inp {
564        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
565        Ok(AssociationFailureEvent {
566                                association_failure_cause: item.get_int(&[0]).and_then(|v| AssociationFailureCause::from_u8(v as u8)),
567                                status: item.get_int(&[1]).map(|v| v as u16),
568        })
569    } else {
570        Err(anyhow::anyhow!("Expected struct fields"))
571    }
572}
573
574/// Decode ConnectionStatus event (0x02, priority: info)
575pub fn decode_connection_status_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ConnectionStatusEvent> {
576    if let tlv::TlvItemValue::List(_fields) = inp {
577        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
578        Ok(ConnectionStatusEvent {
579                                connection_status: item.get_int(&[0]).and_then(|v| ConnectionStatus::from_u8(v as u8)),
580        })
581    } else {
582        Err(anyhow::anyhow!("Expected struct fields"))
583    }
584}
585