/* * * 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 boxslab::Slab; use matter::error::Error; use matter::interaction_model::core::OpCode; use matter::interaction_model::messages::msg::InvReq; use matter::interaction_model::messages::msg::WriteReq; use matter::interaction_model::InteractionConsumer; use matter::interaction_model::InteractionModel; use matter::interaction_model::Transaction; use matter::tlv::TLVWriter; use matter::transport::exchange::Exchange; use matter::transport::exchange::ExchangeCtx; use matter::transport::network::Address; use matter::transport::packet::Packet; use matter::transport::packet::PacketPool; use matter::transport::proto_demux::HandleProto; use matter::transport::proto_demux::ProtoCtx; use matter::transport::proto_demux::ResponseRequired; use matter::transport::session::SessionMgr; use std::net::Ipv4Addr; use std::net::SocketAddr; use std::sync::{Arc, Mutex}; struct Node { pub endpoint: u16, pub cluster: u32, pub command: u32, pub variable: u8, } struct DataModel { node: Arc>, } impl DataModel { pub fn new(node: Node) -> Self { DataModel { node: Arc::new(Mutex::new(node)), } } } impl Clone for DataModel { fn clone(&self) -> Self { Self { node: self.node.clone(), } } } impl InteractionConsumer for DataModel { fn consume_invoke_cmd( &self, inv_req_msg: &InvReq, _trans: &mut Transaction, _tlvwriter: &mut TLVWriter, ) -> Result<(), Error> { if let Some(inv_requests) = &inv_req_msg.inv_requests { for i in inv_requests.iter() { let data = if let Some(data) = i.data.unwrap_tlv() { data } else { continue; }; let cmd_path_ib = i.path; let mut common_data = self.node.lock().unwrap(); common_data.endpoint = cmd_path_ib.path.endpoint.unwrap_or(1); common_data.cluster = cmd_path_ib.path.cluster.unwrap_or(0); common_data.command = cmd_path_ib.path.leaf.unwrap_or(0); data.confirm_struct().unwrap(); common_data.variable = data.find_tag(0).unwrap().u8().unwrap(); } } Ok(()) } fn consume_read_attr( &self, _req: &[u8], _trans: &mut Transaction, _tlvwriter: &mut TLVWriter, ) -> Result<(), Error> { Ok(()) } fn consume_write_attr( &self, _req: &WriteReq, _trans: &mut Transaction, _tlvwriter: &mut TLVWriter, ) -> Result<(), Error> { Ok(()) } fn consume_status_report( &self, _req: &matter::interaction_model::messages::msg::StatusResp, _trans: &mut Transaction, _tw: &mut TLVWriter, ) -> Result<(OpCode, ResponseRequired), Error> { Ok((OpCode::StatusResponse, ResponseRequired::No)) } fn consume_subscribe( &self, _req: &[u8], _trans: &mut Transaction, _tw: &mut TLVWriter, ) -> Result<(OpCode, matter::transport::proto_demux::ResponseRequired), Error> { Ok((OpCode::StatusResponse, ResponseRequired::No)) } } fn handle_data(action: OpCode, data_in: &[u8], data_out: &mut [u8]) -> (DataModel, usize) { let data_model = DataModel::new(Node { endpoint: 0, cluster: 0, command: 0, variable: 0, }); let mut interaction_model = InteractionModel::new(Box::new(data_model.clone())); let mut exch: Exchange = Default::default(); let mut sess_mgr: SessionMgr = Default::default(); let sess_idx = sess_mgr .get_or_add( 0, Address::Udp(SocketAddr::new( std::net::IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 5542, )), None, false, ) .unwrap(); let sess = sess_mgr.get_session_handle(sess_idx); let exch_ctx = ExchangeCtx { exch: &mut exch, sess, }; let mut rx = Slab::::try_new(Packet::new_rx().unwrap()).unwrap(); let tx = Slab::::try_new(Packet::new_tx().unwrap()).unwrap(); // Create fake rx packet rx.set_proto_id(0x01); rx.set_proto_opcode(action as u8); rx.peer = Address::default(); let in_data_len = data_in.len(); let rx_buf = rx.as_borrow_slice(); rx_buf[..in_data_len].copy_from_slice(data_in); let mut ctx = ProtoCtx::new(exch_ctx, rx, tx); interaction_model.handle_proto_id(&mut ctx).unwrap(); let out_len = ctx.tx.as_borrow_slice().len(); data_out[..out_len].copy_from_slice(ctx.tx.as_borrow_slice()); (data_model, out_len) } #[test] fn test_valid_invoke_cmd() -> Result<(), Error> { // An invoke command for endpoint 0, cluster 49, command 12 and a u8 variable value of 0x05 let b = [ 0x15, 0x28, 0x00, 0x28, 0x01, 0x36, 0x02, 0x15, 0x37, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x01, 0x31, 0x00, 0x00, 0x00, 0x26, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x18, 0x35, 0x01, 0x24, 0x00, 0x05, 0x18, 0x18, 0x18, 0x18, ]; let mut out_buf: [u8; 20] = [0; 20]; let (data_model, _) = handle_data(OpCode::InvokeRequest, &b, &mut out_buf); let data = data_model.node.lock().unwrap(); assert_eq!(data.endpoint, 0); assert_eq!(data.cluster, 49); assert_eq!(data.command, 12); assert_eq!(data.variable, 5); Ok(()) }