diff --git a/matter/src/interaction_model/messages.rs b/matter/src/interaction_model/messages.rs index 3eb5e72..c5c1ca0 100644 --- a/matter/src/interaction_model/messages.rs +++ b/matter/src/interaction_model/messages.rs @@ -71,7 +71,7 @@ pub mod msg { tlv::{FromTLV, TLVArray, TLVElement, TLVWriter, TagType, ToTLV}, }; - use super::ib::{AttrData, AttrPath, AttrResp, CmdData, DataVersionFilter}; + use super::ib::{self, AttrData, AttrPath, AttrResp, AttrStatus, CmdData, DataVersionFilter}; #[derive(FromTLV, ToTLV)] pub struct TimedReq { @@ -83,6 +83,12 @@ pub mod msg { pub status: IMStatusCode, } + pub enum InvReqTag { + SupressResponse = 0, + TimedReq = 1, + InvokeRequests = 2, + } + #[derive(FromTLV, ToTLV)] #[tlvargs(lifetime = "'a")] pub struct InvReq<'a> { @@ -91,15 +97,18 @@ pub mod msg { pub inv_requests: Option>>, } + // This enum is helpful when we are constructing the response + // step by step in incremental manner pub enum InvRespTag { SupressResponse = 0, InvokeResponses = 1, } - pub enum InvReqTag { - SupressResponse = 0, - TimedReq = 1, - InvokeRequests = 2, + #[derive(FromTLV, ToTLV, Debug)] + #[tlvargs(lifetime = "'a")] + pub struct InvResp<'a> { + pub suppress_response: Option, + pub inv_responses: Option>>, } #[derive(Default, ToTLV, FromTLV)] @@ -171,6 +180,12 @@ pub mod msg { } // Write Response + #[derive(ToTLV, FromTLV)] + #[tlvargs(lifetime = "'a")] + pub struct WriteResp<'a> { + pub write_responses: TLVArray<'a, AttrStatus>, + } + pub enum WriteRespTag { WriteResponses = 0, } @@ -190,7 +205,7 @@ pub mod ib { use super::GenericPath; // Command Response - #[derive(Clone, Copy, FromTLV, ToTLV)] + #[derive(Clone, Copy, FromTLV, ToTLV, Debug)] #[tlvargs(lifetime = "'a")] pub enum InvResp<'a> { Cmd(CmdData<'a>), diff --git a/matter/src/tlv/traits.rs b/matter/src/tlv/traits.rs index a4d2ae3..ab03a63 100644 --- a/matter/src/tlv/traits.rs +++ b/matter/src/tlv/traits.rs @@ -19,6 +19,7 @@ use super::{ElementType, TLVContainerIterator, TLVElement, TLVWriter, TagType}; use crate::error::Error; use core::slice::Iter; use log::error; +use std::fmt::Debug; pub trait FromTLV<'a> { fn from_tlv(t: &TLVElement<'a>) -> Result @@ -282,6 +283,7 @@ impl TLVArrayOwned { } } +#[derive(Copy, Clone)] pub enum TLVArray<'a, T> { // This is used for the to-tlv path Slice(&'a [T]), @@ -342,6 +344,27 @@ impl<'a, T: FromTLV<'a> + Copy> Iterator for TLVArrayIter<'a, T> { } } +impl<'a, T> PartialEq<&[T]> for TLVArray<'a, T> +where + T: ToTLV + FromTLV<'a> + Copy + PartialEq, +{ + fn eq(&self, other: &&[T]) -> bool { + let mut iter1 = self.iter(); + let mut iter2 = other.into_iter(); + loop { + match (iter1.next(), iter2.next()) { + (None, None) => return true, + (Some(x), Some(y)) => { + if x != *y { + return false; + } + } + _ => return false, + } + } + } +} + impl<'a, T: ToTLV> ToTLV for TLVArray<'a, T> { fn to_tlv(&self, tw: &mut TLVWriter, tag_type: TagType) -> Result<(), Error> { match *self { @@ -364,6 +387,15 @@ impl<'a, T> FromTLV<'a> for TLVArray<'a, T> { } } +impl<'a, T: Debug + ToTLV + FromTLV<'a> + Copy> Debug for TLVArray<'a, T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for i in self.iter() { + writeln!(f, "{:?}", i)?; + } + writeln!(f, "") + } +} + #[cfg(test)] mod tests { use super::{FromTLV, OctetStr, TLVElement, TLVWriter, TagType, ToTLV}; diff --git a/matter/tests/common/attributes.rs b/matter/tests/common/attributes.rs index 42d4c83..1131c27 100644 --- a/matter/tests/common/attributes.rs +++ b/matter/tests/common/attributes.rs @@ -21,6 +21,7 @@ use matter::interaction_model::{messages::ib::AttrResp, messages::msg::ReportDat pub fn assert_attr_report(received: &ReportDataMsg, expected: &[AttrResp]) { let mut index = 0; + // We can't use assert_eq because it will also try to match data-version for inv_response in received.attr_reports.as_ref().unwrap().iter() { println!("Validating index {}", index); match expected[index] { @@ -34,14 +35,7 @@ pub fn assert_attr_report(received: &ReportDataMsg, expected: &[AttrResp]) { panic!("Invalid response, expected AttrRespIn::Data"); } }, - AttrResp::Status(e_s) => match inv_response { - AttrResp::Status(s) => { - assert_eq!(e_s, s); - } - _ => { - panic!("Invalid response, expected AttrRespIn::Status"); - } - }, + AttrResp::Status(s) => assert_eq!(AttrResp::Status(s), inv_response), } println!("Index {} success", index); index += 1; diff --git a/matter/tests/data_model/attributes.rs b/matter/tests/data_model/attributes.rs index 07a88ad..1ff64a4 100644 --- a/matter/tests/data_model/attributes.rs +++ b/matter/tests/data_model/attributes.rs @@ -23,11 +23,11 @@ use matter::{ }, interaction_model::{ core::{IMStatusCode, OpCode}, + messages::GenericPath, messages::{ ib::{AttrData, AttrPath, AttrResp, AttrStatus}, - msg::{ReadReq, ReportDataMsg, WriteReq}, + msg::{ReadReq, ReportDataMsg, WriteReq, WriteResp}, }, - messages::{msg, GenericPath}, }, tlv::{self, ElementType, FromTLV, TLVElement, TLVList, TLVWriter, TagType, ToTLV}, utils::writebuf::WriteBuf, @@ -73,26 +73,10 @@ fn handle_write_reqs(input: &[AttrData], expected: &[AttrStatus]) -> DataModel { write_req.to_tlv(&mut tw, TagType::Anonymous).unwrap(); let (dm, _, out_buf) = im_engine(OpCode::WriteRequest, wb.as_borrow_slice(), &mut out_buf); - tlv::print_tlv_list(out_buf); let root = tlv::get_root_node_struct(out_buf).unwrap(); + let response = WriteResp::from_tlv(&root).unwrap(); + assert_eq!(response.write_responses, expected); - let mut index = 0; - - let response_iter = root - .find_tag(msg::WriteRespTag::WriteResponses as u32) - .unwrap() - .confirm_array() - .unwrap() - .enter() - .unwrap(); - for response in response_iter { - println!("Validating index {}", index); - let status = AttrStatus::from_tlv(&response).unwrap(); - assert_eq!(expected[index], status); - println!("Index {} success", index); - index += 1; - } - assert_eq!(index, expected.len()); dm } diff --git a/matter/tests/data_model/commands.rs b/matter/tests/data_model/commands.rs index 9583a34..c97b672 100644 --- a/matter/tests/data_model/commands.rs +++ b/matter/tests/data_model/commands.rs @@ -56,17 +56,10 @@ fn handle_commands(input: &[CmdData], expected: &[ExpectedInvResp]) { tlv::print_tlv_list(out_buf); let root = tlv::get_root_node_struct(out_buf).unwrap(); + let resp = msg::InvResp::from_tlv(&root).unwrap(); let mut index = 0; - let cmd_list_iter = root - .find_tag(msg::InvRespTag::InvokeResponses as u32) - .unwrap() - .confirm_array() - .unwrap() - .enter() - .unwrap(); - for response in cmd_list_iter { + for inv_response in resp.inv_responses.unwrap().iter() { println!("Validating index {}", index); - let inv_response = InvResp::from_tlv(&response).unwrap(); match expected[index] { ExpectedInvResp::Cmd(e_c, e_d) => match inv_response { InvResp::Cmd(c) => { diff --git a/matter/tests/data_model/timed_requests.rs b/matter/tests/data_model/timed_requests.rs index a22454f..6d2dc00 100644 --- a/matter/tests/data_model/timed_requests.rs +++ b/matter/tests/data_model/timed_requests.rs @@ -25,11 +25,11 @@ use matter::{ }, interaction_model::{ core::{IMStatusCode, OpCode}, + messages::GenericPath, messages::{ ib::{AttrData, AttrPath, AttrStatus}, - msg::{StatusResp, TimedReq, WriteReq}, + msg::{StatusResp, TimedReq, WriteReq, WriteResp}, }, - messages::{msg, GenericPath}, }, tlv::{self, FromTLV, TLVWriter, TagType, ToTLV}, transport::exchange::{self, Exchange}, @@ -86,29 +86,14 @@ fn handle_timed_write_reqs( tlv::print_tlv_list(out_buf); let root = tlv::get_root_node_struct(out_buf).unwrap(); - let mut index = 0; - match expected { WriteResponse::TransactionSuccess(t) => { assert_eq!( num::FromPrimitive::from_u8(resp_opcode), Some(OpCode::WriteResponse) ); - let response_iter = root - .find_tag(msg::WriteRespTag::WriteResponses as u32) - .unwrap() - .confirm_array() - .unwrap() - .enter() - .unwrap(); - for response in response_iter { - println!("Validating index {}", index); - let status = AttrStatus::from_tlv(&response).unwrap(); - assert_eq!(t[index], status); - println!("Index {} success", index); - index += 1; - } - assert_eq!(index, t.len()); + let resp = WriteResp::from_tlv(&root).unwrap(); + assert_eq!(resp.write_responses, t); } WriteResponse::TransactionError => { assert_eq!(