1#![allow(
5 clippy::all,
6 clippy::pedantic,
7 dead_code,
8 unreachable_pub,
9 unused_imports
10)]
11
12use crate::datatypes::SemanticTagStruct;
13use crate::error::ClusterError;
14use crate::types::Nullable;
15use matter_codec::{ContainerKind, Element, Tag, TlvReader, TlvWriter, Value};
16
17pub const CLUSTER_ID: u32 = 0x0004;
19pub const CLUSTER_REVISION: u16 = 4;
21
22pub mod command_id {
24 pub const ADD_GROUP: u32 = 0x00;
26 pub const ADD_GROUP_RESPONSE: u32 = 0x00;
28 pub const VIEW_GROUP: u32 = 0x01;
30 pub const VIEW_GROUP_RESPONSE: u32 = 0x01;
32 pub const GET_GROUP_MEMBERSHIP: u32 = 0x02;
34 pub const GET_GROUP_MEMBERSHIP_RESPONSE: u32 = 0x02;
36 pub const REMOVE_GROUP: u32 = 0x03;
38 pub const REMOVE_GROUP_RESPONSE: u32 = 0x03;
40 pub const REMOVE_ALL_GROUPS: u32 = 0x04;
42 pub const ADD_GROUP_IF_IDENTIFYING: u32 = 0x05;
44}
45
46pub mod attribute_id {
48 pub const NAME_SUPPORT: u32 = 0x0000;
50}
51
52bitflags::bitflags! {
53 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
55 pub struct Feature: u32 {
56 const GN = 1 << 0;
58 }
59}
60
61bitflags::bitflags! {
62 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
64 pub struct NameSupportBitmap: u8 {
65 const GROUP_NAMES = 1 << 7;
67 }
68}
69
70pub fn decode_name_support(tlv: &[u8]) -> Result<NameSupportBitmap, ClusterError> {
75 let mut r = TlvReader::new(tlv);
76 match r.next()? {
77 Some(Element::Scalar {
78 value: Value::Uint(v),
79 ..
80 }) => Ok(NameSupportBitmap::from_bits_retain(
81 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("NameSupport"))?,
82 )),
83 _ => Err(ClusterError::UnexpectedType {
84 context: "NameSupport",
85 }),
86 }
87}
88
89#[must_use]
91#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_add_group(group_id: u16, group_name: &String) -> Vec<u8> {
93 let mut buf = Vec::new();
94 let mut w = TlvWriter::new(&mut buf);
95 w.start_structure(Tag::Anonymous)
96 .expect("infallible: vec writer");
97 w.put_uint(Tag::Context(0), u64::from(group_id))
98 .expect("infallible: vec writer");
99 w.put_utf8(Tag::Context(1), &group_name)
100 .expect("infallible: vec writer");
101 w.end_container().expect("infallible: vec writer");
102 buf
103}
104
105#[derive(Clone, Debug, PartialEq)]
107#[non_exhaustive]
108pub struct AddGroupResponse {
109 pub status: u8,
111 pub group_id: u16,
113}
114
115impl AddGroupResponse {
116 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
122 let mut f_status: Option<u8> = None;
123 let mut f_group_id: Option<u16> = None;
124 loop {
125 match r.next()? {
126 Some(Element::ContainerEnd) => break,
127 Some(Element::Scalar {
128 tag: Tag::Context(0),
129 value: Value::Uint(v),
130 }) => {
131 f_status =
132 Some(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Status"))?)
133 }
134 Some(Element::Scalar {
135 tag: Tag::Context(1),
136 value: Value::Uint(v),
137 }) => {
138 f_group_id =
139 Some(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("GroupId"))?)
140 }
141 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
142 Some(Element::ContainerStart { .. }) => r.skip_container()?,
143 Some(_) => {} }
145 }
146 Ok(Self {
147 status: f_status.ok_or(ClusterError::MissingField("Status"))?,
148 group_id: f_group_id.ok_or(ClusterError::MissingField("GroupId"))?,
149 })
150 }
151 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
156 let mut r = TlvReader::new(tlv);
157 match r.next()? {
158 Some(Element::ContainerStart {
159 kind: ContainerKind::Structure,
160 ..
161 }) => {}
162 _ => {
163 return Err(ClusterError::UnexpectedType {
164 context: "AddGroupResponse",
165 })
166 }
167 }
168 Self::decode_from(&mut r)
169 }
170}
171
172#[must_use]
174#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_view_group(group_id: u16) -> Vec<u8> {
176 let mut buf = Vec::new();
177 let mut w = TlvWriter::new(&mut buf);
178 w.start_structure(Tag::Anonymous)
179 .expect("infallible: vec writer");
180 w.put_uint(Tag::Context(0), u64::from(group_id))
181 .expect("infallible: vec writer");
182 w.end_container().expect("infallible: vec writer");
183 buf
184}
185
186#[derive(Clone, Debug, PartialEq)]
188#[non_exhaustive]
189pub struct ViewGroupResponse {
190 pub status: u8,
192 pub group_id: u16,
194 pub group_name: String,
196}
197
198impl ViewGroupResponse {
199 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
205 let mut f_status: Option<u8> = None;
206 let mut f_group_id: Option<u16> = None;
207 let mut f_group_name: Option<String> = None;
208 loop {
209 match r.next()? {
210 Some(Element::ContainerEnd) => break,
211 Some(Element::Scalar {
212 tag: Tag::Context(0),
213 value: Value::Uint(v),
214 }) => {
215 f_status =
216 Some(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Status"))?)
217 }
218 Some(Element::Scalar {
219 tag: Tag::Context(1),
220 value: Value::Uint(v),
221 }) => {
222 f_group_id =
223 Some(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("GroupId"))?)
224 }
225 Some(Element::Scalar {
226 tag: Tag::Context(2),
227 value: Value::Utf8(v),
228 }) => f_group_name = Some(v),
229 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
230 Some(Element::ContainerStart { .. }) => r.skip_container()?,
231 Some(_) => {} }
233 }
234 Ok(Self {
235 status: f_status.ok_or(ClusterError::MissingField("Status"))?,
236 group_id: f_group_id.ok_or(ClusterError::MissingField("GroupId"))?,
237 group_name: f_group_name.ok_or(ClusterError::MissingField("GroupName"))?,
238 })
239 }
240 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
245 let mut r = TlvReader::new(tlv);
246 match r.next()? {
247 Some(Element::ContainerStart {
248 kind: ContainerKind::Structure,
249 ..
250 }) => {}
251 _ => {
252 return Err(ClusterError::UnexpectedType {
253 context: "ViewGroupResponse",
254 })
255 }
256 }
257 Self::decode_from(&mut r)
258 }
259}
260
261#[must_use]
263#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_get_group_membership(group_list: &Vec<u16>) -> Vec<u8> {
265 let mut buf = Vec::new();
266 let mut w = TlvWriter::new(&mut buf);
267 w.start_structure(Tag::Anonymous)
268 .expect("infallible: vec writer");
269 w.start_array(Tag::Context(0))
270 .expect("infallible: vec writer");
271 for el in group_list.iter().copied() {
272 w.put_uint(Tag::Anonymous, u64::from(el))
273 .expect("infallible: vec writer");
274 }
275 w.end_container().expect("infallible: vec writer");
276 w.end_container().expect("infallible: vec writer");
277 buf
278}
279
280#[derive(Clone, Debug, PartialEq)]
282#[non_exhaustive]
283pub struct GetGroupMembershipResponse {
284 pub capacity: Nullable<u8>,
286 pub group_list: Vec<u16>,
288}
289
290impl GetGroupMembershipResponse {
291 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
297 let mut f_capacity: Option<Nullable<u8>> = None;
298 let mut f_group_list: Option<Vec<u16>> = None;
299 loop {
300 match r.next()? {
301 Some(Element::ContainerEnd) => break,
302 Some(Element::Scalar {
303 tag: Tag::Context(0),
304 value: Value::Null,
305 }) => f_capacity = Some(Nullable::Null),
306 Some(Element::Scalar {
307 tag: Tag::Context(0),
308 value: Value::Uint(v),
309 }) => {
310 f_capacity = Some(Nullable::Value(
311 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Capacity"))?,
312 ))
313 }
314 Some(Element::ContainerStart {
315 tag: Tag::Context(1),
316 kind: ContainerKind::Array,
317 }) => {
318 let mut out = Vec::new();
319 loop {
320 match r.next()? {
321 Some(Element::ContainerEnd) => break,
322 Some(Element::Scalar {
323 value: Value::Uint(v),
324 ..
325 }) => out.push(
326 u16::try_from(v)
327 .map_err(|_| ClusterError::InvalidLength("GroupList"))?,
328 ),
329 None => {
330 return Err(ClusterError::Tlv(
331 matter_codec::Error::UnclosedContainer,
332 ))
333 }
334 Some(Element::ContainerStart { .. }) => r.skip_container()?,
335 Some(_) => {} }
337 }
338 f_group_list = Some(out);
339 }
340 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
341 Some(Element::ContainerStart { .. }) => r.skip_container()?,
342 Some(_) => {} }
344 }
345 Ok(Self {
346 capacity: f_capacity.ok_or(ClusterError::MissingField("Capacity"))?,
347 group_list: f_group_list.ok_or(ClusterError::MissingField("GroupList"))?,
348 })
349 }
350 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
355 let mut r = TlvReader::new(tlv);
356 match r.next()? {
357 Some(Element::ContainerStart {
358 kind: ContainerKind::Structure,
359 ..
360 }) => {}
361 _ => {
362 return Err(ClusterError::UnexpectedType {
363 context: "GetGroupMembershipResponse",
364 })
365 }
366 }
367 Self::decode_from(&mut r)
368 }
369}
370
371#[must_use]
373#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_remove_group(group_id: u16) -> Vec<u8> {
375 let mut buf = Vec::new();
376 let mut w = TlvWriter::new(&mut buf);
377 w.start_structure(Tag::Anonymous)
378 .expect("infallible: vec writer");
379 w.put_uint(Tag::Context(0), u64::from(group_id))
380 .expect("infallible: vec writer");
381 w.end_container().expect("infallible: vec writer");
382 buf
383}
384
385#[derive(Clone, Debug, PartialEq)]
387#[non_exhaustive]
388pub struct RemoveGroupResponse {
389 pub status: u8,
391 pub group_id: u16,
393}
394
395impl RemoveGroupResponse {
396 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
402 let mut f_status: Option<u8> = None;
403 let mut f_group_id: Option<u16> = None;
404 loop {
405 match r.next()? {
406 Some(Element::ContainerEnd) => break,
407 Some(Element::Scalar {
408 tag: Tag::Context(0),
409 value: Value::Uint(v),
410 }) => {
411 f_status =
412 Some(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Status"))?)
413 }
414 Some(Element::Scalar {
415 tag: Tag::Context(1),
416 value: Value::Uint(v),
417 }) => {
418 f_group_id =
419 Some(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("GroupId"))?)
420 }
421 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
422 Some(Element::ContainerStart { .. }) => r.skip_container()?,
423 Some(_) => {} }
425 }
426 Ok(Self {
427 status: f_status.ok_or(ClusterError::MissingField("Status"))?,
428 group_id: f_group_id.ok_or(ClusterError::MissingField("GroupId"))?,
429 })
430 }
431 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
436 let mut r = TlvReader::new(tlv);
437 match r.next()? {
438 Some(Element::ContainerStart {
439 kind: ContainerKind::Structure,
440 ..
441 }) => {}
442 _ => {
443 return Err(ClusterError::UnexpectedType {
444 context: "RemoveGroupResponse",
445 })
446 }
447 }
448 Self::decode_from(&mut r)
449 }
450}
451
452#[must_use]
454#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_remove_all_groups() -> Vec<u8> {
456 let mut buf = Vec::new();
457 let mut w = TlvWriter::new(&mut buf);
458 w.start_structure(Tag::Anonymous)
459 .expect("infallible: vec writer");
460 w.end_container().expect("infallible: vec writer");
461 buf
462}
463
464#[must_use]
466#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_add_group_if_identifying(group_id: u16, group_name: &String) -> Vec<u8> {
468 let mut buf = Vec::new();
469 let mut w = TlvWriter::new(&mut buf);
470 w.start_structure(Tag::Anonymous)
471 .expect("infallible: vec writer");
472 w.put_uint(Tag::Context(0), u64::from(group_id))
473 .expect("infallible: vec writer");
474 w.put_utf8(Tag::Context(1), &group_name)
475 .expect("infallible: vec writer");
476 w.end_container().expect("infallible: vec writer");
477 buf
478}