/* * * Copyright (c) 2020-2022 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ use rs_matter::{ interaction_model::{messages::ib::AttrResp, messages::msg::ReportDataMsg}, tlv::{TLVElement, TLVList, TLVWriter, TagType, ToTLV}, utils::writebuf::WriteBuf, }; /// Assert that the data received in the outbuf matches our expectations pub fn __assert_attr_report(received: &ReportDataMsg, expected: &[AttrResp], skip_data: bool) { 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] { AttrResp::Data(e_d) => match inv_response { AttrResp::Data(d) => { // We don't match the data-version assert_eq!(e_d.path, d.path); if !skip_data { assert_eq!(e_d.data, d.data); } } _ => { panic!("Invalid response, expected AttrRespIn::Data"); } }, AttrResp::Status(s) => assert_eq!(AttrResp::Status(s.clone()), inv_response), } println!("Index {} success", index); index += 1; } assert_eq!(index, expected.len()); } pub fn assert_attr_report(received: &ReportDataMsg, expected: &[AttrResp]) { __assert_attr_report(received, expected, false) } pub fn assert_attr_report_skip_data(received: &ReportDataMsg, expected: &[AttrResp]) { __assert_attr_report(received, expected, true) } // We have to hard-code this here, and it should match the tag // of the 'data' part in AttrData pub const ATTR_DATA_TAG_DATA: u8 = 2; #[macro_export] macro_rules! attr_data { ($endpoint:expr, $cluster:expr, $attr: expr, $data:expr) => { AttrResp::Data(AttrData { data_ver: None, path: AttrPath { endpoint: Some($endpoint), cluster: Some($cluster), attr: Some($attr as u16), ..Default::default() }, data: EncodeValue::Tlv(TLVElement::new(TagType::Context(ATTR_DATA_TAG_DATA), $data)), }) }; } #[macro_export] macro_rules! attr_data_path { ($path:expr, $data:expr) => { AttrResp::Data(AttrData { data_ver: None, path: AttrPath { endpoint: $path.endpoint, cluster: $path.cluster, attr: $path.leaf.map(|x| x as u16), ..Default::default() }, data: EncodeValue::Tlv(TLVElement::new(TagType::Context(ATTR_DATA_TAG_DATA), $data)), }) }; } #[macro_export] macro_rules! attr_status { ($path:expr, $status:expr) => { AttrResp::Status(AttrStatus::new($path, $status, 0)) }; } pub struct TLVHolder { buf: [u8; 100], used_len: usize, } impl TLVHolder { pub fn new_array<'a, T, I>(ctx_tag: u8, data: I) -> Self where T: ToTLV + 'a, I: IntoIterator, { let mut s = Self { buf: [0; 100], used_len: 0, }; let mut wb = WriteBuf::new(&mut s.buf); let mut tw = TLVWriter::new(&mut wb); let _ = tw.start_array(TagType::Context(ctx_tag)); for e in data { let _ = e.to_tlv(&mut tw, TagType::Anonymous); } let _ = tw.end_container(); s.used_len = wb.as_slice().len(); s } pub fn to_tlv(&self) -> TLVElement { let s = &self.buf[..self.used_len]; TLVList::new(s).iter().next().unwrap() } }