rs_matter/dm/networks/wireless/
thread.rs1use core::fmt::{Debug, Display};
21
22use crate::dm::clusters::net_comm::WirelessCreds;
23use crate::error::{Error, ErrorCode};
24use crate::tlv::{FromTLV, OctetsOwned, ToTLV};
25use crate::utils::init::{init, Init, IntoFallibleInit};
26use crate::utils::storage::Vec;
27
28use super::{WirelessNetwork, WirelessNetworks};
29
30pub type ThreadNetworks<const N: usize> = WirelessNetworks<N, Thread>;
31
32#[derive(Debug, Clone, Eq, PartialEq, Hash, ToTLV, FromTLV)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub struct Thread {
36 pub dataset: OctetsOwned<256>,
38}
39
40impl Default for Thread {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl Thread {
47 pub const fn new() -> Self {
49 Self {
50 dataset: OctetsOwned { vec: Vec::new() },
51 }
52 }
53
54 pub fn init() -> impl Init<Self> {
56 init!(Self {
57 dataset <- OctetsOwned::init(),
58 })
59 }
60
61 pub fn dataset_ext_pan_id(dataset_tlv: &[u8]) -> Result<&[u8], Error> {
63 ThreadTLV::new(dataset_tlv).ext_pan_id()
64 }
65
66 pub fn ext_pan_id(&self) -> &[u8] {
68 unwrap!(Self::dataset_ext_pan_id(&self.dataset.vec))
72 }
73}
74
75impl WirelessNetwork for Thread {
76 fn id(&self) -> &[u8] {
77 self.ext_pan_id()
78 }
79
80 #[cfg(not(feature = "defmt"))]
81 fn display_id(id: &[u8]) -> impl Display {
82 use super::DisplayId;
83
84 DisplayId::Thread(id)
85 }
86
87 #[cfg(feature = "defmt")]
88 fn display_id(id: &[u8]) -> impl Display + defmt::Format {
89 use super::DisplayId;
90
91 DisplayId::Thread(id)
92 }
93
94 fn init_from<'a>(creds: &'a WirelessCreds<'a>) -> impl Init<Self, Error> + 'a {
95 Self::init().into_fallible().chain(move |network| {
96 let WirelessCreds::Thread { dataset_tlv } = creds else {
97 return Err(ErrorCode::InvalidData.into());
98 };
99
100 network
101 .dataset
102 .vec
103 .extend_from_slice(dataset_tlv)
104 .map_err(|_| ErrorCode::InvalidData)?;
105
106 Ok(())
107 })
108 }
109
110 fn update(&mut self, creds: &WirelessCreds<'_>) -> Result<(), Error> {
111 let WirelessCreds::Thread { dataset_tlv } = creds else {
112 return Err(ErrorCode::InvalidData.into());
113 };
114
115 if dataset_tlv.len() > self.dataset.vec.capacity() {
116 return Err(ErrorCode::InvalidData.into());
117 }
118
119 self.dataset.vec.clear();
120
121 unwrap!(self.dataset.vec.extend_from_slice(dataset_tlv));
122
123 Ok(())
124 }
125
126 fn creds(&self) -> WirelessCreds<'_> {
127 WirelessCreds::Thread {
128 dataset_tlv: &self.dataset.vec,
129 }
130 }
131}
132
133#[derive(Debug, Copy, Clone)]
135#[cfg_attr(feature = "defmt", derive(defmt::Format))]
136pub struct ThreadTLV<'a>(&'a [u8]);
137
138impl<'a> ThreadTLV<'a> {
139 pub const fn new(tlv: &'a [u8]) -> Self {
141 Self(tlv)
142 }
143
144 pub fn ext_pan_id(&mut self) -> Result<&'a [u8], Error> {
146 const EXT_PAN_ID: u8 = 2;
147
148 let ext_pan_id =
149 self.find_map(|(tlv_type, tlv_value)| (tlv_type == EXT_PAN_ID).then_some(tlv_value));
150
151 let Some(ext_pan_id) = ext_pan_id else {
152 return Err(ErrorCode::InvalidData.into());
153 };
154
155 Ok(ext_pan_id)
156 }
157
158 pub fn next_tlv(&mut self) -> Option<(u8, &'a [u8])> {
163 const LONG_VALUE_ID: u8 = 255;
164
165 let mut slice = self.0;
169
170 (slice.len() >= 2).then_some(())?;
171
172 let tlv_type = slice[0];
173 slice = &slice[1..];
174
175 let tlv_len_size = if slice[0] == LONG_VALUE_ID {
176 slice = &slice[1..];
177 3
178 } else {
179 1
180 };
181
182 (slice.len() >= tlv_len_size).then_some(())?;
183
184 let tlv_len = if tlv_len_size == 1 {
185 slice[0] as usize
186 } else {
187 u32::from_be_bytes([0, slice[0], slice[1], slice[2]]) as usize
188 };
189
190 slice = &slice[tlv_len_size..];
191 (slice.len() >= tlv_len).then_some(())?;
192
193 let tlv_value = &slice[..tlv_len];
194
195 slice = &slice[tlv_len..];
196
197 self.0 = slice;
198
199 Some((tlv_type, tlv_value))
200 }
201}
202
203impl<'a> Iterator for ThreadTLV<'a> {
204 type Item = (u8, &'a [u8]);
205
206 fn next(&mut self) -> Option<Self::Item> {
207 self.next_tlv()
208 }
209}