1use crate::{
19 data_model::objects::{ClusterId, EndptId},
20 error::{Error, ErrorCode},
21 tlv::{FromTLV, TLVWriter, TagType, ToTLV},
22};
23
24#[derive(Default, Clone, Debug, PartialEq, FromTLV, ToTLV)]
27#[tlvargs(datatype = "list")]
28pub struct GenericPath {
29 pub endpoint: Option<EndptId>,
30 pub cluster: Option<ClusterId>,
31 pub leaf: Option<u32>,
32}
33
34impl GenericPath {
35 pub fn new(endpoint: Option<EndptId>, cluster: Option<ClusterId>, leaf: Option<u32>) -> Self {
36 Self {
37 endpoint,
38 cluster,
39 leaf,
40 }
41 }
42
43 pub fn not_wildcard(&self) -> Result<(EndptId, ClusterId, u32), Error> {
45 match *self {
46 GenericPath {
47 endpoint: Some(e),
48 cluster: Some(c),
49 leaf: Some(l),
50 } => Ok((e, c, l)),
51 _ => Err(ErrorCode::Invalid.into()),
52 }
53 }
54 pub fn is_wildcard(&self) -> bool {
56 !matches!(
57 *self,
58 GenericPath {
59 endpoint: Some(_),
60 cluster: Some(_),
61 leaf: Some(_),
62 }
63 )
64 }
65}
66
67pub mod msg {
68
69 use crate::{
70 error::Error,
71 interaction_model::core::IMStatusCode,
72 tlv::{FromTLV, TLVArray, TLVWriter, TagType, ToTLV},
73 };
74
75 use super::ib::{
76 self, AttrData, AttrPath, AttrResp, AttrStatus, CmdData, DataVersionFilter, EventFilter,
77 EventPath,
78 };
79
80 #[derive(Debug, Default, FromTLV, ToTLV)]
81 #[tlvargs(lifetime = "'a")]
82 pub struct SubscribeReq<'a> {
83 pub keep_subs: bool,
84 pub min_int_floor: u16,
85 pub max_int_ceil: u16,
86 pub attr_requests: Option<TLVArray<'a, AttrPath>>,
87 event_requests: Option<TLVArray<'a, EventPath>>,
88 event_filters: Option<TLVArray<'a, EventFilter>>,
89 _dummy: Option<bool>,
91 pub fabric_filtered: bool,
92 pub dataver_filters: Option<TLVArray<'a, DataVersionFilter>>,
93 }
94
95 impl<'a> SubscribeReq<'a> {
96 pub fn new(fabric_filtered: bool, min_int_floor: u16, max_int_ceil: u16) -> Self {
97 Self {
98 fabric_filtered,
99 min_int_floor,
100 max_int_ceil,
101 ..Default::default()
102 }
103 }
104
105 pub fn set_attr_requests(mut self, requests: &'a [AttrPath]) -> Self {
106 self.attr_requests = Some(TLVArray::new(requests));
107 self
108 }
109 }
110
111 #[derive(Debug, FromTLV, ToTLV)]
112 pub struct SubscribeResp {
113 pub subs_id: u32,
114 _dummy: Option<u32>,
116 pub max_int: u16,
117 }
118
119 impl SubscribeResp {
120 pub fn new(subs_id: u32, max_int: u16) -> Self {
121 Self {
122 subs_id,
123 _dummy: None,
124 max_int,
125 }
126 }
127 }
128
129 #[derive(FromTLV, ToTLV)]
130 pub struct TimedReq {
131 pub timeout: u16,
132 }
133
134 #[derive(FromTLV, ToTLV)]
135 pub struct StatusResp {
136 pub status: IMStatusCode,
137 }
138
139 pub enum InvReqTag {
140 SupressResponse = 0,
141 TimedReq = 1,
142 InvokeRequests = 2,
143 }
144
145 #[derive(FromTLV, ToTLV)]
146 #[tlvargs(lifetime = "'a")]
147 pub struct InvReq<'a> {
148 pub suppress_response: Option<bool>,
149 pub timed_request: Option<bool>,
150 pub inv_requests: Option<TLVArray<'a, CmdData<'a>>>,
151 }
152
153 #[derive(FromTLV, ToTLV, Debug)]
154 #[tlvargs(lifetime = "'a")]
155 pub struct InvResp<'a> {
156 pub suppress_response: Option<bool>,
157 pub inv_responses: Option<TLVArray<'a, ib::InvResp<'a>>>,
158 }
159
160 pub enum InvRespTag {
163 SupressResponse = 0,
164 InvokeResponses = 1,
165 }
166
167 #[derive(Default, ToTLV, FromTLV, Debug)]
168 #[tlvargs(lifetime = "'a")]
169 pub struct ReadReq<'a> {
170 pub attr_requests: Option<TLVArray<'a, AttrPath>>,
171 event_requests: Option<TLVArray<'a, EventPath>>,
172 event_filters: Option<TLVArray<'a, EventFilter>>,
173 pub fabric_filtered: bool,
174 pub dataver_filters: Option<TLVArray<'a, DataVersionFilter>>,
175 }
176
177 impl<'a> ReadReq<'a> {
178 pub fn new(fabric_filtered: bool) -> Self {
179 Self {
180 fabric_filtered,
181 ..Default::default()
182 }
183 }
184
185 pub fn set_attr_requests(mut self, requests: &'a [AttrPath]) -> Self {
186 self.attr_requests = Some(TLVArray::new(requests));
187 self
188 }
189 }
190
191 #[derive(FromTLV, ToTLV, Debug)]
192 #[tlvargs(lifetime = "'a")]
193 pub struct WriteReq<'a> {
194 pub supress_response: Option<bool>,
195 timed_request: Option<bool>,
196 pub write_requests: TLVArray<'a, AttrData<'a>>,
197 more_chunked: Option<bool>,
198 }
199
200 impl<'a> WriteReq<'a> {
201 pub fn new(supress_response: bool, write_requests: &'a [AttrData<'a>]) -> Self {
202 let mut w = Self {
203 supress_response: None,
204 write_requests: TLVArray::new(write_requests),
205 timed_request: None,
206 more_chunked: None,
207 };
208 if supress_response {
209 w.supress_response = Some(true);
210 }
211 w
212 }
213 }
214
215 #[derive(FromTLV, ToTLV, Debug)]
217 #[tlvargs(lifetime = "'a")]
218 pub struct ReportDataMsg<'a> {
219 pub subscription_id: Option<u32>,
220 pub attr_reports: Option<TLVArray<'a, AttrResp<'a>>>,
221 pub event_reports: Option<bool>,
223 pub more_chunks: Option<bool>,
224 pub suppress_response: Option<bool>,
225 }
226
227 pub enum ReportDataTag {
228 SubscriptionId = 0,
229 AttributeReports = 1,
230 _EventReport = 2,
231 MoreChunkedMsgs = 3,
232 SupressResponse = 4,
233 }
234
235 #[derive(ToTLV, FromTLV, Debug)]
237 #[tlvargs(lifetime = "'a")]
238 pub struct WriteResp<'a> {
239 pub write_responses: TLVArray<'a, AttrStatus>,
240 }
241
242 pub enum WriteRespTag {
243 WriteResponses = 0,
244 }
245}
246
247pub mod ib {
248 use core::fmt::Debug;
249
250 use crate::{
251 data_model::objects::{AttrDetails, AttrId, ClusterId, CmdId, EncodeValue, EndptId},
252 error::{Error, ErrorCode},
253 interaction_model::core::IMStatusCode,
254 tlv::{FromTLV, Nullable, TLVElement, TLVWriter, TagType, ToTLV},
255 };
256 use log::error;
257
258 use super::GenericPath;
259
260 #[derive(Clone, FromTLV, ToTLV, Debug)]
262 #[tlvargs(lifetime = "'a")]
263 pub enum InvResp<'a> {
264 Cmd(CmdData<'a>),
265 Status(CmdStatus),
266 }
267
268 impl<'a> InvResp<'a> {
269 pub fn status_new(cmd_path: CmdPath, status: IMStatusCode, cluster_status: u16) -> Self {
270 Self::Status(CmdStatus {
271 path: cmd_path,
272 status: Status::new(status, cluster_status),
273 })
274 }
275 }
276
277 impl<'a> From<CmdData<'a>> for InvResp<'a> {
278 fn from(value: CmdData<'a>) -> Self {
279 Self::Cmd(value)
280 }
281 }
282
283 pub enum InvRespTag {
284 Cmd = 0,
285 Status = 1,
286 }
287
288 impl<'a> From<CmdStatus> for InvResp<'a> {
289 fn from(value: CmdStatus) -> Self {
290 Self::Status(value)
291 }
292 }
293
294 #[derive(FromTLV, ToTLV, Clone, PartialEq, Debug)]
295 pub struct CmdStatus {
296 path: CmdPath,
297 status: Status,
298 }
299
300 impl CmdStatus {
301 pub fn new(path: CmdPath, status: IMStatusCode, cluster_status: u16) -> Self {
302 Self {
303 path,
304 status: Status {
305 status,
306 cluster_status,
307 },
308 }
309 }
310 }
311
312 #[derive(Debug, Clone, FromTLV, ToTLV)]
313 #[tlvargs(lifetime = "'a")]
314 pub struct CmdData<'a> {
315 pub path: CmdPath,
316 pub data: EncodeValue<'a>,
317 }
318
319 impl<'a> CmdData<'a> {
320 pub fn new(path: CmdPath, data: EncodeValue<'a>) -> Self {
321 Self { path, data }
322 }
323 }
324
325 pub enum CmdDataTag {
326 Path = 0,
327 Data = 1,
328 }
329
330 #[derive(Debug, Clone, PartialEq, FromTLV, ToTLV)]
332 pub struct Status {
333 pub status: IMStatusCode,
334 pub cluster_status: u16,
335 }
336
337 impl Status {
338 pub fn new(status: IMStatusCode, cluster_status: u16) -> Status {
339 Status {
340 status,
341 cluster_status,
342 }
343 }
344 }
345
346 #[derive(Clone, FromTLV, ToTLV, PartialEq, Debug)]
348 #[tlvargs(lifetime = "'a")]
349 pub enum AttrResp<'a> {
350 Status(AttrStatus),
351 Data(AttrData<'a>),
352 }
353
354 impl<'a> AttrResp<'a> {
355 pub fn unwrap_data(self) -> AttrData<'a> {
356 match self {
357 AttrResp::Data(d) => d,
358 _ => {
359 panic!("No data exists");
360 }
361 }
362 }
363 }
364
365 impl<'a> From<AttrData<'a>> for AttrResp<'a> {
366 fn from(value: AttrData<'a>) -> Self {
367 Self::Data(value)
368 }
369 }
370
371 impl<'a> From<AttrStatus> for AttrResp<'a> {
372 fn from(value: AttrStatus) -> Self {
373 Self::Status(value)
374 }
375 }
376
377 pub enum AttrRespTag {
378 Status = 0,
379 Data = 1,
380 }
381
382 #[derive(Clone, PartialEq, FromTLV, ToTLV, Debug)]
384 #[tlvargs(lifetime = "'a")]
385 pub struct AttrData<'a> {
386 pub data_ver: Option<u32>,
387 pub path: AttrPath,
388 pub data: EncodeValue<'a>,
389 }
390
391 impl<'a> AttrData<'a> {
392 pub fn new(data_ver: Option<u32>, path: AttrPath, data: EncodeValue<'a>) -> Self {
393 Self {
394 data_ver,
395 path,
396 data,
397 }
398 }
399 }
400
401 pub enum AttrDataTag {
402 DataVer = 0,
403 Path = 1,
404 Data = 2,
405 }
406
407 #[derive(Debug)]
408 pub enum ListOperation {
410 AddItem,
412 EditItem(u16),
414 DeleteItem(u16),
416 DeleteList,
418 }
419
420 pub fn attr_list_write<F>(attr: &AttrDetails, data: &TLVElement, mut f: F) -> Result<(), Error>
422 where
423 F: FnMut(ListOperation, &TLVElement) -> Result<(), Error>,
424 {
425 if let Some(Nullable::NotNull(index)) = attr.list_index {
426 if data.null().is_ok() {
429 f(ListOperation::DeleteItem(index), data)
431 } else {
432 f(ListOperation::EditItem(index), data)
433 }
434 } else if data.confirm_array().is_ok() {
435 f(ListOperation::DeleteList, data)?;
438 let container = data.enter().ok_or(ErrorCode::Invalid)?;
441 for d in container {
442 f(ListOperation::AddItem, &d)?;
443 }
444 Ok(())
445 } else {
446 f(ListOperation::AddItem, data)
448 }
449 }
450
451 #[derive(Debug, Clone, PartialEq, FromTLV, ToTLV)]
452 pub struct AttrStatus {
453 path: AttrPath,
454 status: Status,
455 }
456
457 impl AttrStatus {
458 pub fn new(path: &GenericPath, status: IMStatusCode, cluster_status: u16) -> Self {
459 Self {
460 path: AttrPath::new(path),
461 status: super::ib::Status::new(status, cluster_status),
462 }
463 }
464 }
465
466 #[derive(Default, Clone, Debug, PartialEq, FromTLV, ToTLV)]
468 #[tlvargs(datatype = "list")]
469 pub struct AttrPath {
470 pub tag_compression: Option<bool>,
471 pub node: Option<u64>,
472 pub endpoint: Option<EndptId>,
473 pub cluster: Option<ClusterId>,
474 pub attr: Option<AttrId>,
475 pub list_index: Option<Nullable<u16>>,
476 }
477
478 impl AttrPath {
479 pub fn new(path: &GenericPath) -> Self {
480 Self {
481 endpoint: path.endpoint,
482 cluster: path.cluster,
483 attr: path.leaf.map(|x| x as u16),
484 ..Default::default()
485 }
486 }
487
488 pub fn to_gp(&self) -> GenericPath {
489 GenericPath::new(self.endpoint, self.cluster, self.attr.map(|x| x as u32))
490 }
491 }
492
493 #[derive(Default, Debug, Clone, PartialEq)]
495 pub struct CmdPath {
496 pub path: GenericPath,
497 }
498
499 #[macro_export]
500 macro_rules! cmd_path_ib {
501 ($endpoint:literal,$cluster:ident,$command:expr) => {{
502 use $crate::interaction_model::messages::{ib::CmdPath, GenericPath};
503 CmdPath {
504 path: GenericPath {
505 endpoint: Some($endpoint),
506 cluster: Some($cluster),
507 leaf: Some($command as u32),
508 },
509 }
510 }};
511 }
512
513 impl CmdPath {
514 pub fn new(
515 endpoint: Option<EndptId>,
516 cluster: Option<ClusterId>,
517 command: Option<CmdId>,
518 ) -> Self {
519 Self {
520 path: GenericPath {
521 endpoint,
522 cluster,
523 leaf: command,
524 },
525 }
526 }
527 }
528
529 impl FromTLV<'_> for CmdPath {
530 fn from_tlv(cmd_path: &TLVElement) -> Result<Self, Error> {
531 let c = CmdPath {
532 path: GenericPath::from_tlv(cmd_path)?,
533 };
534
535 if c.path.leaf.is_none() {
536 error!("Wildcard command parameter not supported");
537 Err(ErrorCode::CommandNotFound.into())
538 } else {
539 Ok(c)
540 }
541 }
542 }
543
544 impl ToTLV for CmdPath {
545 fn to_tlv(&self, tw: &mut TLVWriter, tag_type: TagType) -> Result<(), Error> {
546 self.path.to_tlv(tw, tag_type)
547 }
548 }
549
550 #[derive(FromTLV, ToTLV, Clone, Debug)]
551 pub struct ClusterPath {
552 pub node: Option<u64>,
553 pub endpoint: EndptId,
554 pub cluster: ClusterId,
555 }
556
557 #[derive(FromTLV, ToTLV, Clone, Debug)]
558 pub struct DataVersionFilter {
559 pub path: ClusterPath,
560 pub data_ver: u32,
561 }
562
563 #[derive(FromTLV, ToTLV, Clone, Debug)]
564 #[tlvargs(datatype = "list")]
565 pub struct EventPath {
566 pub node: Option<u64>,
567 pub endpoint: Option<EndptId>,
568 pub cluster: Option<ClusterId>,
569 pub event: Option<u32>,
570 pub is_urgent: Option<bool>,
571 }
572
573 #[derive(FromTLV, ToTLV, Clone, Debug)]
574 pub struct EventFilter {
575 pub node: Option<u64>,
576 pub event_min: Option<u64>,
577 }
578}