1use anyhow::{bail, Result};
2
3use crate::{clusters, tlv};
4
5use super::Device;
6
7const ATTR_GENERATED_CMD_LIST: u32 = 0xFFF8;
9const ATTR_ACCEPTED_CMD_LIST: u32 = 0xFFF9;
10const ATTR_EVENT_LIST: u32 = 0xFFFA;
11const ATTR_ATTRIBUTE_LIST: u32 = 0xFFFB;
12const ATTR_FEATURE_MAP: u32 = 0xFFFC;
13const ATTR_CLUSTER_REVISION: u32 = 0xFFFD;
14
15impl Device {
16 pub(super) fn setup_default_attributes(&mut self) -> Result<()> {
17 use clusters::defs::*;
18
19
20 let mut buf = tlv::TlvBuffer::new();
21 buf.write_array(2)?;
22 buf.write_anon_struct()?;
23 buf.write_uint32(0, 0x0016)?; buf.write_uint16(1, 2)?; buf.write_struct_end()?;
26 buf.write_struct_end()?;
27 self.set_attribute_raw(
28 0,
29 CLUSTER_ID_DESCRIPTOR,
30 CLUSTER_DESCRIPTOR_ATTR_ID_DEVICETYPELIST,
31 &buf.data,
32 );
33
34 let mut buf = tlv::TlvBuffer::new();
35 buf.write_array(2)?;
36 buf.write_uint32_notag(CLUSTER_ID_DESCRIPTOR)?;
37 buf.write_uint32_notag(CLUSTER_ID_ACCESS_CONTROL)?;
38 buf.write_uint32_notag(CLUSTER_ID_BASIC_INFORMATION)?;
39 buf.write_uint32_notag(CLUSTER_ID_GENERAL_COMMISSIONING)?;
40 buf.write_uint32_notag(CLUSTER_ID_NETWORK_COMMISSIONING)?;
41 buf.write_uint32_notag(CLUSTER_ID_ADMINISTRATOR_COMMISSIONING)?;
42 buf.write_uint32_notag(CLUSTER_ID_OPERATIONAL_CREDENTIALS)?;
43 buf.write_struct_end()?;
44 self.set_attribute_raw(
45 0,
46 CLUSTER_ID_DESCRIPTOR,
47 CLUSTER_DESCRIPTOR_ATTR_ID_SERVERLIST,
48 &buf.data,
49 );
50
51 self.set_empty_array(0, CLUSTER_ID_DESCRIPTOR, CLUSTER_DESCRIPTOR_ATTR_ID_CLIENTLIST);
52
53 self.set_empty_array(0, CLUSTER_ID_DESCRIPTOR, CLUSTER_DESCRIPTOR_ATTR_ID_PARTSLIST);
54
55 self.set_cluster_globals(
56 0,
57 CLUSTER_ID_DESCRIPTOR,
58 3,
59 0,
60 &[
61 CLUSTER_DESCRIPTOR_ATTR_ID_DEVICETYPELIST,
62 CLUSTER_DESCRIPTOR_ATTR_ID_SERVERLIST,
63 CLUSTER_DESCRIPTOR_ATTR_ID_CLIENTLIST,
64 CLUSTER_DESCRIPTOR_ATTR_ID_PARTSLIST,
65 ],
66 &[],
67 &[],
68 )?;
69
70 let vendor_id = self.config.vendor_id;
71 let product_id = self.config.product_id;
72 self.set_attribute_u16(
73 0,
74 CLUSTER_ID_BASIC_INFORMATION,
75 CLUSTER_BASIC_INFORMATION_ATTR_ID_DATAMODELREVISION,
76 1,
77 );
78 let vendor_name = self.config.vendor_name.clone();
79 self.set_attribute_string(
80 0,
81 CLUSTER_ID_BASIC_INFORMATION,
82 CLUSTER_BASIC_INFORMATION_ATTR_ID_VENDORNAME,
83 &vendor_name,
84 );
85 self.set_attribute_u16(
86 0,
87 CLUSTER_ID_BASIC_INFORMATION,
88 CLUSTER_BASIC_INFORMATION_ATTR_ID_VENDORID,
89 vendor_id,
90 );
91 let product_name = self.config.product_name.clone();
92 self.set_attribute_string(
93 0,
94 CLUSTER_ID_BASIC_INFORMATION,
95 CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTNAME,
96 &product_name,
97 );
98 self.set_attribute_u16(
99 0,
100 CLUSTER_ID_BASIC_INFORMATION,
101 CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTID,
102 product_id,
103 );
104 let node_label = self.config.product_name.clone();
105 self.set_attribute_string(
106 0,
107 CLUSTER_ID_BASIC_INFORMATION,
108 CLUSTER_BASIC_INFORMATION_ATTR_ID_NODELABEL,
109 &node_label,
110 );
111 self.set_attribute_string(
112 0,
113 CLUSTER_ID_BASIC_INFORMATION,
114 CLUSTER_BASIC_INFORMATION_ATTR_ID_LOCATION,
115 "XX",
116 );
117 let hardware_version = self.config.hardware_version;
118 self.set_attribute_u16(
119 0,
120 CLUSTER_ID_BASIC_INFORMATION,
121 CLUSTER_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSION,
122 hardware_version,
123 );
124 let hardware_version_string = format!("{}.0", hardware_version);
125 self.set_attribute_string(
126 0,
127 CLUSTER_ID_BASIC_INFORMATION,
128 CLUSTER_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSIONSTRING,
129 &hardware_version_string,
130 );
131 let software_version = self.config.software_version;
132 self.set_attribute_u32(
133 0,
134 CLUSTER_ID_BASIC_INFORMATION,
135 CLUSTER_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSION,
136 software_version,
137 );
138 let software_version_string = software_version.to_string();
139 self.set_attribute_string(
140 0,
141 CLUSTER_ID_BASIC_INFORMATION,
142 CLUSTER_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSIONSTRING,
143 &software_version_string,
144 );
145 let serial_number = self.config.serial_number.clone();
146 self.set_attribute_string(
147 0,
148 CLUSTER_ID_BASIC_INFORMATION,
149 CLUSTER_BASIC_INFORMATION_ATTR_ID_SERIALNUMBER,
150 &serial_number,
151 );
152 self.set_attribute_bool(
153 0,
154 CLUSTER_ID_BASIC_INFORMATION,
155 CLUSTER_BASIC_INFORMATION_ATTR_ID_LOCALCONFIGDISABLED,
156 false,
157 );
158 self.set_attribute_bool(
159 0,
160 CLUSTER_ID_BASIC_INFORMATION,
161 CLUSTER_BASIC_INFORMATION_ATTR_ID_REACHABLE,
162 true,
163 );
164 let unique_id = self.config.unique_id.clone();
165 self.set_attribute_string(
166 0,
167 CLUSTER_ID_BASIC_INFORMATION,
168 CLUSTER_BASIC_INFORMATION_ATTR_ID_UNIQUEID,
169 &unique_id,
170 );
171
172 let mut buf = tlv::TlvBuffer::new();
173 buf.write_struct(2)?;
174 buf.write_uint16(0, 3)?; buf.write_uint16(1, 3)?; buf.write_struct_end()?;
177 self.set_attribute_raw(
178 0,
179 CLUSTER_ID_BASIC_INFORMATION,
180 CLUSTER_BASIC_INFORMATION_ATTR_ID_CAPABILITYMINIMA,
181 &buf.data,
182 );
183
184 self.set_attribute_u32(
185 0,
186 CLUSTER_ID_BASIC_INFORMATION,
187 CLUSTER_BASIC_INFORMATION_ATTR_ID_SPECIFICATIONVERSION,
188 0x01030000, );
190 self.set_attribute_u16(
191 0,
192 CLUSTER_ID_BASIC_INFORMATION,
193 CLUSTER_BASIC_INFORMATION_ATTR_ID_MAXPATHSPERINVOKE,
194 1,
195 );
196
197 self.set_cluster_globals(
198 0,
199 CLUSTER_ID_BASIC_INFORMATION,
200 4,
201 0,
202 &[
203 CLUSTER_BASIC_INFORMATION_ATTR_ID_DATAMODELREVISION,
204 CLUSTER_BASIC_INFORMATION_ATTR_ID_VENDORNAME,
205 CLUSTER_BASIC_INFORMATION_ATTR_ID_VENDORID,
206 CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTNAME,
207 CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTID,
208 CLUSTER_BASIC_INFORMATION_ATTR_ID_NODELABEL,
209 CLUSTER_BASIC_INFORMATION_ATTR_ID_LOCATION,
210 CLUSTER_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSION,
211 CLUSTER_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSIONSTRING,
212 CLUSTER_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSION,
213 CLUSTER_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSIONSTRING,
214 CLUSTER_BASIC_INFORMATION_ATTR_ID_SERIALNUMBER,
215 CLUSTER_BASIC_INFORMATION_ATTR_ID_LOCALCONFIGDISABLED,
216 CLUSTER_BASIC_INFORMATION_ATTR_ID_REACHABLE,
217 CLUSTER_BASIC_INFORMATION_ATTR_ID_UNIQUEID,
218 CLUSTER_BASIC_INFORMATION_ATTR_ID_CAPABILITYMINIMA,
219 CLUSTER_BASIC_INFORMATION_ATTR_ID_SPECIFICATIONVERSION,
220 CLUSTER_BASIC_INFORMATION_ATTR_ID_MAXPATHSPERINVOKE,
221 ],
222 &[],
223 &[],
224 )?;
225
226 self.set_attribute_u64(
227 0,
228 CLUSTER_ID_GENERAL_COMMISSIONING,
229 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_BREADCRUMB,
230 0,
231 );
232
233 let mut bci_tlv = tlv::TlvBuffer::new();
234 bci_tlv.write_struct(2)?;
235 bci_tlv.write_uint16(0, 100)?;
236 bci_tlv.write_uint16(1, 200)?;
237 bci_tlv.write_struct_end()?;
238 self.set_attribute_raw(
239 0,
240 CLUSTER_ID_GENERAL_COMMISSIONING,
241 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_BASICCOMMISSIONINGINFO,
242 &bci_tlv.data,
243 );
244
245 self.set_attribute_u8(
246 0,
247 CLUSTER_ID_GENERAL_COMMISSIONING,
248 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_REGULATORYCONFIG,
249 0,
250 );
251 self.set_attribute_u8(
252 0,
253 CLUSTER_ID_GENERAL_COMMISSIONING,
254 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_LOCATIONCAPABILITY,
255 0,
256 );
257 self.set_attribute_bool(
258 0,
259 CLUSTER_ID_GENERAL_COMMISSIONING,
260 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_SUPPORTSCONCURRENTCONNECTION,
261 true,
262 );
263 self.set_attribute_bool(
264 0,
265 CLUSTER_ID_GENERAL_COMMISSIONING,
266 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_ISCOMMISSIONINGWITHOUTPOWER,
267 false,
268 );
269
270 self.set_cluster_globals(
271 0,
272 CLUSTER_ID_GENERAL_COMMISSIONING,
273 1,
274 0,
275 &[
276 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_BREADCRUMB,
277 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_BASICCOMMISSIONINGINFO,
278 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_REGULATORYCONFIG,
279 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_LOCATIONCAPABILITY,
280 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_SUPPORTSCONCURRENTCONNECTION,
281 CLUSTER_GENERAL_COMMISSIONING_ATTR_ID_ISCOMMISSIONINGWITHOUTPOWER,
282 ],
283 &[
284 CLUSTER_GENERAL_COMMISSIONING_CMD_ID_ARMFAILSAFE,
285 CLUSTER_GENERAL_COMMISSIONING_CMD_ID_SETREGULATORYCONFIG,
286 CLUSTER_GENERAL_COMMISSIONING_CMD_ID_COMMISSIONINGCOMPLETE,
287 ],
288 &[
289 CLUSTER_GENERAL_COMMISSIONING_CMD_ID_ARMFAILSAFERESPONSE,
290 CLUSTER_GENERAL_COMMISSIONING_CMD_ID_SETREGULATORYCONFIGRESPONSE,
291 CLUSTER_GENERAL_COMMISSIONING_CMD_ID_COMMISSIONINGCOMPLETERESPONSE,
292 ],
293 )?;
294
295 self.set_attribute_u8(
296 0,
297 CLUSTER_ID_OPERATIONAL_CREDENTIALS,
298 CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_SUPPORTEDFABRICS,
299 8,
300 );
301 self.set_attribute_u8(
302 0,
303 CLUSTER_ID_OPERATIONAL_CREDENTIALS,
304 CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_COMMISSIONEDFABRICS,
305 1,
306 );
307 self.set_empty_array(
308 0,
309 CLUSTER_ID_OPERATIONAL_CREDENTIALS,
310 CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_FABRICS,
311 );
312
313 self.set_cluster_globals(
314 0,
315 CLUSTER_ID_OPERATIONAL_CREDENTIALS,
316 1,
317 0,
318 &[
319 CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_NOCS,
320 CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_FABRICS,
321 CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_SUPPORTEDFABRICS,
322 CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_COMMISSIONEDFABRICS,
323 CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_TRUSTEDROOTCERTIFICATES,
324 CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_CURRENTFABRICINDEX,
325 ],
326 &[
327 CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_ATTESTATIONREQUEST,
328 CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_CERTIFICATECHAINREQUEST,
329 CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_CSRREQUEST,
330 CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_ADDTRUSTEDROOTCERTIFICATE,
331 CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_ADDNOC,
332 CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_REMOVEFABRIC,
333 ],
334 &[
335 CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_ATTESTATIONRESPONSE,
336 CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_CERTIFICATECHAINRESPONSE,
337 CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_CSRRESPONSE,
338 CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_NOCRESPONSE,
339 ],
340 )?;
341
342
343 self.set_attribute_u8(
344 0,
345 CLUSTER_ID_NETWORK_COMMISSIONING,
346 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_MAXNETWORKS,
347 1,
348 );
349 self.set_empty_array(
350 0,
351 CLUSTER_ID_NETWORK_COMMISSIONING,
352 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_NETWORKS,
353 );
354 self.set_attribute_bool(
355 0,
356 CLUSTER_ID_NETWORK_COMMISSIONING,
357 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_INTERFACEENABLED,
358 true,
359 );
360 self.set_attribute_u8(
361 0,
362 CLUSTER_ID_NETWORK_COMMISSIONING,
363 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_CONNECTMAXTIMESECONDS,
364 120,
365 );
366 self.set_attribute_u8(
367 0,
368 CLUSTER_ID_NETWORK_COMMISSIONING,
369 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_LASTNETWORKINGSTATUS,
370 0,
371 );
372 self.set_attribute_u16(
373 0,
374 CLUSTER_ID_NETWORK_COMMISSIONING,
375 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_SUPPORTEDTHREADFEATURES,
376 0,
377 );
378
379 self.set_cluster_globals(
380 0,
381 CLUSTER_ID_NETWORK_COMMISSIONING,
382 1,
383 0x04, &[
385 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_MAXNETWORKS,
386 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_NETWORKS,
387 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_CONNECTMAXTIMESECONDS,
388 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_INTERFACEENABLED,
389 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_LASTNETWORKINGSTATUS,
390 CLUSTER_NETWORK_COMMISSIONING_ATTR_ID_SUPPORTEDTHREADFEATURES,
391 ],
392 &[],
393 &[],
394 )?;
395
396 self.set_empty_array(
397 0,
398 CLUSTER_ID_ACCESS_CONTROL,
399 CLUSTER_ACCESS_CONTROL_ATTR_ID_ACL,
400 );
401 self.set_attribute_u16(
402 0,
403 CLUSTER_ID_ACCESS_CONTROL,
404 CLUSTER_ACCESS_CONTROL_ATTR_ID_SUBJECTSPERACCESSCONTROLENTRY,
405 4,
406 );
407 self.set_attribute_u16(
408 0,
409 CLUSTER_ID_ACCESS_CONTROL,
410 CLUSTER_ACCESS_CONTROL_ATTR_ID_TARGETSPERACCESSCONTROLENTRY,
411 3,
412 );
413 self.set_attribute_u16(
414 0,
415 CLUSTER_ID_ACCESS_CONTROL,
416 CLUSTER_ACCESS_CONTROL_ATTR_ID_ACCESSCONTROLENTRIESPERFABRIC,
417 4,
418 );
419
420 self.set_cluster_globals(
421 0,
422 CLUSTER_ID_ACCESS_CONTROL,
423 2,
424 0,
425 &[
426 CLUSTER_ACCESS_CONTROL_ATTR_ID_ACL,
427 CLUSTER_ACCESS_CONTROL_ATTR_ID_SUBJECTSPERACCESSCONTROLENTRY,
428 CLUSTER_ACCESS_CONTROL_ATTR_ID_TARGETSPERACCESSCONTROLENTRY,
429 CLUSTER_ACCESS_CONTROL_ATTR_ID_ACCESSCONTROLENTRIESPERFABRIC,
430 ],
431 &[],
432 &[],
433 )?;
434
435 self.set_attribute_u8(
436 0,
437 CLUSTER_ID_ADMINISTRATOR_COMMISSIONING,
438 CLUSTER_ADMINISTRATOR_COMMISSIONING_ATTR_ID_WINDOWSTATUS,
439 0, );
441 self.set_attribute_u8(
442 0,
443 CLUSTER_ID_ADMINISTRATOR_COMMISSIONING,
444 CLUSTER_ADMINISTRATOR_COMMISSIONING_ATTR_ID_ADMINFABRICINDEX,
445 0,
446 );
447 self.set_attribute_u16(
448 0,
449 CLUSTER_ID_ADMINISTRATOR_COMMISSIONING,
450 CLUSTER_ADMINISTRATOR_COMMISSIONING_ATTR_ID_ADMINVENDORID,
451 0,
452 );
453
454 self.set_cluster_globals(
455 0,
456 CLUSTER_ID_ADMINISTRATOR_COMMISSIONING,
457 1,
458 0,
459 &[
460 CLUSTER_ADMINISTRATOR_COMMISSIONING_ATTR_ID_WINDOWSTATUS,
461 CLUSTER_ADMINISTRATOR_COMMISSIONING_ATTR_ID_ADMINFABRICINDEX,
462 CLUSTER_ADMINISTRATOR_COMMISSIONING_ATTR_ID_ADMINVENDORID,
463 ],
464 &[
465 CLUSTER_ADMINISTRATOR_COMMISSIONING_CMD_ID_OPENCOMMISSIONINGWINDOW,
466 CLUSTER_ADMINISTRATOR_COMMISSIONING_CMD_ID_OPENBASICCOMMISSIONINGWINDOW,
467 CLUSTER_ADMINISTRATOR_COMMISSIONING_CMD_ID_REVOKECOMMISSIONING,
468 ],
469 &[],
470 )?;
471
472 self.set_attribute_u8(0, 0x60, 1, 3u8);
474
475 Ok(())
476 }
477
478 pub fn set_empty_array(&mut self, endpoint: u16, cluster: u32, attribute: u32) {
479 let mut buf = tlv::TlvBuffer::new();
480 let _ = buf.write_array(2);
481 let _ = buf.write_struct_end();
482 self.set_attribute_raw(endpoint, cluster, attribute, &buf.data);
483 }
484
485 #[allow(clippy::too_many_arguments)]
486 pub fn set_cluster_globals(
487 &mut self,
488 endpoint: u16,
489 cluster: u32,
490 revision: u16,
491 feature_map: u32,
492 attribute_ids: &[u32],
493 accepted_cmds: &[u32],
494 generated_cmds: &[u32],
495 ) -> Result<()> {
496 self.set_attribute_u16(endpoint, cluster, ATTR_CLUSTER_REVISION, revision);
497 self.set_attribute_u32(endpoint, cluster, ATTR_FEATURE_MAP, feature_map);
498
499 let mut buf = tlv::TlvBuffer::new();
500 buf.write_array(2)?;
501 for &id in attribute_ids {
502 buf.write_uint32_notag(id)?;
503 }
504 buf.write_uint32_notag(ATTR_ATTRIBUTE_LIST)?;
505 buf.write_uint32_notag(ATTR_FEATURE_MAP)?;
506 buf.write_uint32_notag(ATTR_CLUSTER_REVISION)?;
507 buf.write_uint32_notag(ATTR_EVENT_LIST)?;
508 buf.write_uint32_notag(ATTR_ACCEPTED_CMD_LIST)?;
509 buf.write_uint32_notag(ATTR_GENERATED_CMD_LIST)?;
510 buf.write_struct_end()?;
511 self.set_attribute_raw(endpoint, cluster, ATTR_ATTRIBUTE_LIST, &buf.data);
512
513 self.set_empty_array(endpoint, cluster, ATTR_EVENT_LIST);
514
515 let mut buf = tlv::TlvBuffer::new();
516 buf.write_array(2)?;
517 for &cmd in accepted_cmds {
518 buf.write_uint32_notag(cmd)?;
519 }
520 buf.write_struct_end()?;
521 self.set_attribute_raw(endpoint, cluster, ATTR_ACCEPTED_CMD_LIST, &buf.data);
522
523 let mut buf = tlv::TlvBuffer::new();
524 buf.write_array(2)?;
525 for &cmd in generated_cmds {
526 buf.write_uint32_notag(cmd)?;
527 }
528 buf.write_struct_end()?;
529 self.set_attribute_raw(endpoint, cluster, ATTR_GENERATED_CMD_LIST, &buf.data);
530
531 Ok(())
532 }
533
534 pub fn set_attribute_bool(&mut self, endpoint: u16, cluster: u32, attribute: u32, value: bool) {
535 let mut buf = tlv::TlvBuffer::new();
536 let _ = buf.write_bool(2, value);
537 self.attributes
538 .insert((endpoint, cluster, attribute), buf.data);
539 self.dirty_attributes.insert((endpoint, cluster, attribute));
540 }
541
542 pub fn set_attribute_u8(&mut self, endpoint: u16, cluster: u32, attribute: u32, value: u8) {
543 let mut buf = tlv::TlvBuffer::new();
544 let _ = buf.write_uint8(2, value);
545 self.attributes
546 .insert((endpoint, cluster, attribute), buf.data);
547 self.dirty_attributes.insert((endpoint, cluster, attribute));
548 }
549
550 pub fn set_attribute_u16(&mut self, endpoint: u16, cluster: u32, attribute: u32, value: u16) {
551 let mut buf = tlv::TlvBuffer::new();
552 let _ = buf.write_uint16(2, value);
553 self.attributes
554 .insert((endpoint, cluster, attribute), buf.data);
555 self.dirty_attributes.insert((endpoint, cluster, attribute));
556 }
557
558 pub fn set_attribute_u32(&mut self, endpoint: u16, cluster: u32, attribute: u32, value: u32) {
559 let mut buf = tlv::TlvBuffer::new();
560 let _ = buf.write_uint32(2, value);
561 self.attributes
562 .insert((endpoint, cluster, attribute), buf.data);
563 self.dirty_attributes.insert((endpoint, cluster, attribute));
564 }
565
566 pub fn set_attribute_u64(&mut self, endpoint: u16, cluster: u32, attribute: u32, value: u64) {
567 let mut buf = tlv::TlvBuffer::new();
568 let _ = buf.write_uint64(2, value);
569 self.attributes
570 .insert((endpoint, cluster, attribute), buf.data);
571 self.dirty_attributes.insert((endpoint, cluster, attribute));
572 }
573
574 pub fn set_attribute_string(
575 &mut self,
576 endpoint: u16,
577 cluster: u32,
578 attribute: u32,
579 value: &str,
580 ) {
581 let mut buf = tlv::TlvBuffer::new();
582 let _ = buf.write_string(2, value);
583 self.attributes
584 .insert((endpoint, cluster, attribute), buf.data);
585 self.dirty_attributes.insert((endpoint, cluster, attribute));
586 }
587
588 pub fn set_attribute_raw(&mut self, endpoint: u16, cluster: u32, attribute: u32, value: &[u8]) {
589 self.attributes
590 .insert((endpoint, cluster, attribute), value.to_vec());
591 self.dirty_attributes.insert((endpoint, cluster, attribute));
592 }
593}
594
595
596use std::collections::{HashMap, HashSet};
597
598pub struct AttrContext<'a> {
600 pub(crate) attributes: &'a mut HashMap<(u16, u32, u32), Vec<u8>>,
601 pub(crate) dirty: &'a mut HashSet<(u16, u32, u32)>,
602}
603
604impl<'a> AttrContext<'a> {
605 pub fn get_bool(&self, ep: u16, cluster: u32, attr: u32) -> Option<bool> {
606 self.attributes.get(&(ep, cluster, attr))
607 .and_then(|v| tlv::decode_tlv(v).ok())
608 .and_then(|item| item.get_bool(&[]))
609 }
610 pub fn get_u8(&self, ep: u16, cluster: u32, attr: u32) -> Option<u8> {
611 self.attributes.get(&(ep, cluster, attr))
612 .and_then(|v| tlv::decode_tlv(v).ok())
613 .and_then(|item| item.get_u8(&[]))
614 }
615 pub fn get_u16(&self, ep: u16, cluster: u32, attr: u32) -> Option<u16> {
616 self.attributes.get(&(ep, cluster, attr))
617 .and_then(|v| tlv::decode_tlv(v).ok())
618 .and_then(|item| item.get_u16(&[]))
619 }
620 pub fn get_u32(&self, ep: u16, cluster: u32, attr: u32) -> Option<u32> {
621 self.attributes.get(&(ep, cluster, attr))
622 .and_then(|v| tlv::decode_tlv(v).ok())
623 .and_then(|item| item.get_u32(&[]))
624 }
625 pub fn get_u64(&self, ep: u16, cluster: u32, attr: u32) -> Option<u64> {
626 self.attributes.get(&(ep, cluster, attr))
627 .and_then(|v| tlv::decode_tlv(v).ok())
628 .and_then(|item| item.get_u64(&[]))
629 }
630 pub fn set_bool(&mut self, ep: u16, cluster: u32, attr: u32, value: bool) {
631 let mut buf = tlv::TlvBuffer::new();
632 let _ = buf.write_bool(2, value);
633 self.attributes.insert((ep, cluster, attr), buf.data);
634 self.dirty.insert((ep, cluster, attr));
635 }
636 pub fn set_u8(&mut self, ep: u16, cluster: u32, attr: u32, value: u8) {
637 let mut buf = tlv::TlvBuffer::new();
638 let _ = buf.write_uint8(2, value);
639 self.attributes.insert((ep, cluster, attr), buf.data);
640 self.dirty.insert((ep, cluster, attr));
641 }
642 pub fn set_u16(&mut self, ep: u16, cluster: u32, attr: u32, value: u16) {
643 let mut buf = tlv::TlvBuffer::new();
644 let _ = buf.write_uint16(2, value);
645 self.attributes.insert((ep, cluster, attr), buf.data);
646 self.dirty.insert((ep, cluster, attr));
647 }
648 pub fn set_u32(&mut self, ep: u16, cluster: u32, attr: u32, value: u32) {
649 let mut buf = tlv::TlvBuffer::new();
650 let _ = buf.write_uint32(2, value);
651 self.attributes.insert((ep, cluster, attr), buf.data);
652 self.dirty.insert((ep, cluster, attr));
653 }
654 pub fn set_u64(&mut self, ep: u16, cluster: u32, attr: u32, value: u64) {
655 let mut buf = tlv::TlvBuffer::new();
656 let _ = buf.write_uint64(2, value);
657 self.attributes.insert((ep, cluster, attr), buf.data);
658 self.dirty.insert((ep, cluster, attr));
659 }
660 pub fn set_string(&mut self, ep: u16, cluster: u32, attr: u32, value: &str) {
661 let mut buf = tlv::TlvBuffer::new();
662 let _ = buf.write_string(2, value);
663 self.attributes.insert((ep, cluster, attr), buf.data);
664 self.dirty.insert((ep, cluster, attr));
665 }
666}
667
668impl Device {
669 pub fn add_endpoint(
675 &mut self,
676 endpoint: u16,
677 device_type_id: u32,
678 device_type_revision: u16,
679 ) -> Result<()> {
680 use clusters::defs::*;
681 if self.endpoints.contains(&endpoint) {
682 bail!("endpoint {} already registered", endpoint);
683 }
684
685 let mut buf = tlv::TlvBuffer::new();
686 buf.write_array(2)?;
687 buf.write_anon_struct()?;
688 buf.write_uint32(0, device_type_id)?;
689 buf.write_uint16(1, device_type_revision)?;
690 buf.write_struct_end()?;
691 buf.write_struct_end()?;
692 self.set_attribute_raw(endpoint, CLUSTER_ID_DESCRIPTOR, CLUSTER_DESCRIPTOR_ATTR_ID_DEVICETYPELIST, &buf.data);
693
694 let mut buf = tlv::TlvBuffer::new();
695 buf.write_array(2)?;
696 buf.write_uint32_notag(CLUSTER_ID_DESCRIPTOR)?;
697 buf.write_struct_end()?;
698 self.set_attribute_raw(endpoint, CLUSTER_ID_DESCRIPTOR, CLUSTER_DESCRIPTOR_ATTR_ID_SERVERLIST, &buf.data);
699
700 self.set_empty_array(endpoint, CLUSTER_ID_DESCRIPTOR, CLUSTER_DESCRIPTOR_ATTR_ID_CLIENTLIST);
701 self.set_empty_array(endpoint, CLUSTER_ID_DESCRIPTOR, CLUSTER_DESCRIPTOR_ATTR_ID_PARTSLIST);
702
703 self.set_cluster_globals(
704 endpoint,
705 CLUSTER_ID_DESCRIPTOR,
706 3,
707 0,
708 &[
709 CLUSTER_DESCRIPTOR_ATTR_ID_DEVICETYPELIST,
710 CLUSTER_DESCRIPTOR_ATTR_ID_SERVERLIST,
711 CLUSTER_DESCRIPTOR_ATTR_ID_CLIENTLIST,
712 CLUSTER_DESCRIPTOR_ATTR_ID_PARTSLIST,
713 ],
714 &[],
715 &[],
716 )?;
717
718 self.endpoints.push(endpoint);
719 self.rebuild_ep0_partslist()?;
720 Ok(())
721 }
722
723 #[allow(clippy::too_many_arguments)]
726 pub fn add_cluster(
727 &mut self,
728 endpoint: u16,
729 cluster_id: u32,
730 revision: u16,
731 feature_map: u32,
732 attr_ids: &[u32],
733 accepted_cmds: &[u32],
734 generated_cmds: &[u32],
735 ) -> Result<()> {
736 if !self.endpoints.contains(&endpoint) {
737 bail!("endpoint {} not registered; call add_endpoint first", endpoint);
738 }
739 self.set_cluster_globals(endpoint, cluster_id, revision, feature_map, attr_ids, accepted_cmds, generated_cmds)?;
740 self.rebuild_server_list(endpoint, cluster_id)?;
741 Ok(())
742 }
743
744 fn rebuild_ep0_partslist(&mut self) -> Result<()> {
746 use clusters::defs::*;
747 let mut buf = tlv::TlvBuffer::new();
748 buf.write_array(2)?;
749 for &ep in &self.endpoints {
750 if ep != 0 {
751 buf.write_uint16_notag(ep)?;
752 }
753 }
754 buf.write_struct_end()?;
755 self.set_attribute_raw(0, CLUSTER_ID_DESCRIPTOR, CLUSTER_DESCRIPTOR_ATTR_ID_PARTSLIST, &buf.data);
756 Ok(())
757 }
758
759 fn rebuild_server_list(&mut self, endpoint: u16, cluster_id: u32) -> Result<()> {
761 use clusters::defs::*;
762 let existing: Vec<u32> = self.attributes
763 .get(&(endpoint, CLUSTER_ID_DESCRIPTOR, CLUSTER_DESCRIPTOR_ATTR_ID_SERVERLIST))
764 .and_then(|data| tlv::decode_tlv(data).ok())
765 .map(|item| {
766 if let tlv::TlvItemValue::List(entries) = item.value {
767 entries.into_iter()
768 .filter_map(|e| if let tlv::TlvItemValue::Int(i) = e.value { Some(i as u32) } else { None })
769 .collect()
770 } else {
771 vec![]
772 }
773 })
774 .unwrap_or_default();
775
776 let mut buf = tlv::TlvBuffer::new();
777 buf.write_array(2)?;
778 for id in existing {
779 buf.write_uint32_notag(id)?;
780 }
781 buf.write_uint32_notag(cluster_id)?;
782 buf.write_struct_end()?;
783 self.set_attribute_raw(endpoint, CLUSTER_ID_DESCRIPTOR, CLUSTER_DESCRIPTOR_ATTR_ID_SERVERLIST, &buf.data);
784 Ok(())
785 }
786}
787