diff --git a/examples/onoff_light/src/lib.rs b/examples/onoff_light/src/lib.rs index 16264d0..43ca1b1 100644 --- a/examples/onoff_light/src/lib.rs +++ b/examples/onoff_light/src/lib.rs @@ -15,4 +15,4 @@ * limitations under the License. */ -// TODO pub mod dev_att; +pub mod dev_att; diff --git a/examples/onoff_light/src/main.rs b/examples/onoff_light/src/main.rs index b2bc448..08dece3 100644 --- a/examples/onoff_light/src/main.rs +++ b/examples/onoff_light/src/main.rs @@ -15,41 +15,114 @@ * limitations under the License. */ -// TODO -// mod dev_att; -// use matter::core::{self, CommissioningData}; -// use matter::data_model::cluster_basic_information::BasicInfoConfig; -// use matter::data_model::device_types::device_type_add_on_off_light; -// use matter::secure_channel::spake2p::VerifierData; +use std::borrow::Borrow; + +use matter::core::{CommissioningData, Matter}; +use matter::data_model::cluster_basic_information::BasicInfoConfig; +use matter::data_model::cluster_on_off; +use matter::data_model::core::DataModel; +use matter::data_model::device_types::DEV_TYPE_ON_OFF_LIGHT; +use matter::data_model::objects::*; +use matter::data_model::root_endpoint; +use matter::data_model::sdm::dev_att::DevAttDataFetcher; +use matter::interaction_model::core::InteractionModel; +use matter::secure_channel::spake2p::VerifierData; +use matter::transport::{ + mgr::RecvAction, mgr::TransportMgr, packet::Packet, packet::MAX_RX_BUF_SIZE, + packet::MAX_TX_BUF_SIZE, udp::UdpListener, +}; + +mod dev_att; fn main() { - // env_logger::init(); - // let comm_data = CommissioningData { - // // TODO: Hard-coded for now - // verifier: VerifierData::new_with_pw(123456), - // discriminator: 250, - // }; + env_logger::init(); - // // vid/pid should match those in the DAC - // let dev_info = BasicInfoConfig { - // vid: 0xFFF1, - // pid: 0x8000, - // hw_ver: 2, - // sw_ver: 1, - // sw_ver_str: "1".to_string(), - // serial_no: "aabbccdd".to_string(), - // device_name: "OnOff Light".to_string(), - // }; - // let dev_att = Box::new(dev_att::HardCodedDevAtt::new()); + // vid/pid should match those in the DAC + let dev_info = BasicInfoConfig { + vid: 0xFFF1, + pid: 0x8000, + hw_ver: 2, + sw_ver: 1, + sw_ver_str: "1", + serial_no: "aabbccdd", + device_name: "OnOff Light", + }; - // let mut matter = core::Matter::new(dev_info, dev_att, comm_data).unwrap(); - // let dm = matter.get_data_model(); - // { - // let mut node = dm.node.write().unwrap(); - // let endpoint = device_type_add_on_off_light(&mut node).unwrap(); - // println!("Added OnOff Light Device type at endpoint id: {}", endpoint); - // println!("Data Model now is: {}", node); - // } + let mut mdns = matter::sys::LinuxMdns::new().unwrap(); - // matter.start_daemon().unwrap(); + let matter = Matter::new_default(&dev_info, &mut mdns); + + let dev_att = dev_att::HardCodedDevAtt::new(); + + matter + .start::<4096>( + CommissioningData { + // TODO: Hard-coded for now + verifier: VerifierData::new_with_pw(123456, *matter.borrow()), + discriminator: 250, + }, + &mut [0; 4096], + ) + .unwrap(); + + let matter = &matter; + let dev_att = &dev_att; + + let mut transport = TransportMgr::new(matter); + + smol::block_on(async move { + let udp = UdpListener::new().await.unwrap(); + + loop { + let mut rx_buf = [0; MAX_RX_BUF_SIZE]; + let mut tx_buf = [0; MAX_TX_BUF_SIZE]; + + let (len, addr) = udp.recv(&mut rx_buf).await.unwrap(); + + let mut rx = Packet::new_rx(&mut rx_buf[..len]); + let mut tx = Packet::new_tx(&mut tx_buf); + + let mut completion = transport.recv(addr, &mut rx, &mut tx); + + while let Some(action) = completion.next_action().unwrap() { + match action { + RecvAction::Send(addr, buf) => { + udp.send(addr, buf).await.unwrap(); + } + RecvAction::Interact(mut ctx) => { + let node = Node { + id: 0, + endpoints: &[ + root_endpoint::endpoint(0), + Endpoint { + id: 1, + device_type: DEV_TYPE_ON_OFF_LIGHT, + clusters: &[cluster_on_off::CLUSTER], + }, + ], + }; + + let mut handler = handler(matter, dev_att); + + let mut im = + InteractionModel(DataModel::new(matter.borrow(), &node, &mut handler)); + + if im.handle(&mut ctx).unwrap() { + if let Some(addr) = ctx.send().unwrap() { + udp.send(addr, ctx.tx.as_slice()).await.unwrap(); + } + } + } + } + } + } + }); +} + +fn handler<'a>(matter: &'a Matter<'a>, dev_att: &'a dyn DevAttDataFetcher) -> impl Handler + 'a { + root_endpoint::handler(0, dev_att, matter).chain( + 1, + cluster_on_off::ID, + cluster_on_off::OnOffCluster::new(*matter.borrow()), + ) } diff --git a/matter/Cargo.toml b/matter/Cargo.toml index d649645..db10e77 100644 --- a/matter/Cargo.toml +++ b/matter/Cargo.toml @@ -15,7 +15,7 @@ name = "matter" path = "src/lib.rs" [features] -default = ["std", "crypto_mbedtls"] +default = ["std", "crypto_mbedtls", "nightly"] std = ["alloc", "env_logger", "chrono", "rand", "qrcode", "smol"] alloc = [] nightly = [] diff --git a/matter/src/core.rs b/matter/src/core.rs index 24e90cf..41c5307 100644 --- a/matter/src/core.rs +++ b/matter/src/core.rs @@ -99,7 +99,7 @@ impl<'a> Matter<'a> { } pub fn start( - &mut self, + &self, dev_comm: CommissioningData, buf: &mut [u8], ) -> Result<(), Error> { diff --git a/matter/src/data_model/root_endpoint.rs b/matter/src/data_model/root_endpoint.rs index ebcbb14..341b3de 100644 --- a/matter/src/data_model/root_endpoint.rs +++ b/matter/src/data_model/root_endpoint.rs @@ -12,7 +12,7 @@ use crate::{ use super::{ cluster_basic_information::{self, BasicInfoCluster, BasicInfoConfig}, - objects::{Cluster, EmptyHandler}, + objects::{Cluster, EmptyHandler, Endpoint, EndptId}, sdm::{ admin_commissioning::{self, AdminCommCluster}, dev_att::DevAttDataFetcher, @@ -47,6 +47,14 @@ pub const CLUSTERS: [Cluster<'static>; 7] = [ access_control::CLUSTER, ]; +pub fn endpoint(id: EndptId) -> Endpoint<'static> { + Endpoint { + id, + device_type: super::device_types::DEV_TYPE_ROOT_NODE, + clusters: &CLUSTERS, + } +} + pub fn handler<'a>( endpoint_id: u16, dev_att: &'a dyn DevAttDataFetcher, diff --git a/matter/src/interaction_model/core.rs b/matter/src/interaction_model/core.rs index 162d64c..fd9e130 100644 --- a/matter/src/interaction_model/core.rs +++ b/matter/src/interaction_model/core.rs @@ -710,14 +710,14 @@ impl ResumeSubscribeReq { } pub trait InteractionHandler { - fn handle<'a>(&mut self, ctx: &'a mut ProtoCtx) -> Result, Error>; + fn handle(&mut self, ctx: &mut ProtoCtx) -> Result; } impl InteractionHandler for &mut T where T: InteractionHandler, { - fn handle<'a>(&mut self, ctx: &'a mut ProtoCtx) -> Result, Error> { + fn handle(&mut self, ctx: &mut ProtoCtx) -> Result { (**self).handle(ctx) } } @@ -728,7 +728,7 @@ impl InteractionModel where T: DataHandler, { - pub fn handle<'a>(&mut self, ctx: &'a mut ProtoCtx) -> Result, Error> { + pub fn handle(&mut self, ctx: &mut ProtoCtx) -> Result { let mut transaction = Transaction::new(&mut ctx.exch_ctx); let reply = @@ -738,7 +738,7 @@ where true }; - Ok(reply.then_some(ctx.tx.as_slice())) + Ok(reply) } } @@ -747,10 +747,7 @@ impl InteractionModel where T: crate::data_model::core::asynch::AsyncDataHandler, { - pub async fn handle_async<'a>( - &mut self, - ctx: &'a mut ProtoCtx<'_, '_>, - ) -> Result, Error> { + pub async fn handle_async<'a>(&mut self, ctx: &mut ProtoCtx<'_, '_>) -> Result { let mut transaction = Transaction::new(&mut ctx.exch_ctx); let reply = @@ -760,7 +757,7 @@ where true }; - Ok(reply.then_some(ctx.tx.as_slice())) + Ok(reply) } } @@ -768,7 +765,7 @@ impl InteractionHandler for InteractionModel where T: DataHandler, { - fn handle<'a>(&mut self, ctx: &'a mut ProtoCtx) -> Result, Error> { + fn handle(&mut self, ctx: &mut ProtoCtx) -> Result { InteractionModel::handle(self, ctx) } } @@ -782,20 +779,14 @@ pub mod asynch { use super::InteractionModel; pub trait AsyncInteractionHandler { - async fn handle<'a>( - &mut self, - ctx: &'a mut ProtoCtx<'_, '_>, - ) -> Result, Error>; + async fn handle(&mut self, ctx: &mut ProtoCtx<'_, '_>) -> Result; } impl AsyncInteractionHandler for &mut T where T: AsyncInteractionHandler, { - async fn handle<'a>( - &mut self, - ctx: &'a mut ProtoCtx<'_, '_>, - ) -> Result, Error> { + async fn handle(&mut self, ctx: &mut ProtoCtx<'_, '_>) -> Result { (**self).handle(ctx).await } } @@ -804,10 +795,7 @@ pub mod asynch { where T: AsyncDataHandler, { - async fn handle<'a>( - &mut self, - ctx: &'a mut ProtoCtx<'_, '_>, - ) -> Result, Error> { + async fn handle(&mut self, ctx: &mut ProtoCtx<'_, '_>) -> Result { InteractionModel::handle_async(self, ctx).await } } diff --git a/matter/src/transport/exchange.rs b/matter/src/transport/exchange.rs index 053bf79..8e3df10 100644 --- a/matter/src/transport/exchange.rs +++ b/matter/src/transport/exchange.rs @@ -31,7 +31,10 @@ use crate::utils::rand::Rand; use heapless::LinearMap; use super::session::CloneData; -use super::{mrp::ReliableMessage, packet::Packet, session::SessionHandle, session::SessionMgr}; +use super::{ + mrp::ReliableMessage, network::Address, packet::Packet, session::SessionHandle, + session::SessionMgr, +}; pub struct ExchangeCtx<'a> { pub exch: &'a mut Exchange, @@ -40,7 +43,7 @@ pub struct ExchangeCtx<'a> { } impl<'a> ExchangeCtx<'a> { - pub fn send(&mut self, tx: &mut Packet) -> Result<(), Error> { + pub fn send(&mut self, tx: &mut Packet) -> Result, Error> { self.exch.send(tx, &mut self.sess) } } @@ -198,10 +201,10 @@ impl Exchange { &mut self, tx: &mut Packet, session: &mut SessionHandle, - ) -> Result<(), Error> { + ) -> Result, Error> { if self.state == State::Terminate { info!("Skipping tx for terminated exchange {}", self.id); - return Ok(()); + return Ok(None); } trace!("payload: {:x?}", tx.as_mut_slice()); @@ -219,7 +222,9 @@ impl Exchange { session.pre_send(tx)?; self.mrp.pre_send(tx)?; - session.send(tx) + session.send(tx)?; + + Ok(Some(session.get_peer_addr())) } } @@ -354,11 +359,13 @@ impl ExchangeMgr { } } - pub fn send(&mut self, exch_id: u16, tx: &mut Packet) -> Result<(), Error> { + pub fn send(&mut self, exch_id: u16, tx: &mut Packet) -> Result { let exchange = ExchangeMgr::_get_with_id(&mut self.exchanges, exch_id).ok_or(Error::NoExchange)?; let mut session = self.sess_mgr.get_session_handle(exchange.sess_idx); - exchange.send(tx, &mut session) + exchange.send(tx, &mut session)?; + + Ok(session.get_peer_addr()) } pub fn purge(&mut self) { @@ -381,7 +388,7 @@ impl ExchangeMgr { .map(|(exch_id, _)| *exch_id) } - pub fn evict_session(&mut self, tx: &mut Packet) -> Result { + pub fn evict_session(&mut self, tx: &mut Packet) -> Result, Error> { if let Some(index) = self.sess_mgr.get_session_for_eviction() { info!("Sessions full, vacating session with index: {}", index); // If we enter here, we have an LRU session that needs to be reclaimed @@ -423,11 +430,14 @@ impl ExchangeMgr { // Remove from exchange list self.exchanges.remove(&exch_id); } + + let addr = session.get_peer_addr(); + self.sess_mgr.remove(index); - Ok(true) + Ok(Some(addr)) } else { - Ok(false) + Ok(None) } } @@ -561,7 +571,7 @@ mod tests { let mut buf = [0; MAX_TX_BUF_SIZE]; let tx = &mut Packet::new_tx(&mut buf); let evicted = mgr.evict_session(tx).unwrap(); - assert!(evicted); + assert!(evicted.is_some()); let session = mgr .add_session(&get_clone_data(new_peer_sess_id, new_local_sess_id)) diff --git a/matter/src/transport/mgr.rs b/matter/src/transport/mgr.rs index 16925b2..c4bc2e7 100644 --- a/matter/src/transport/mgr.rs +++ b/matter/src/transport/mgr.rs @@ -32,6 +32,7 @@ use crate::transport::{exchange, packet::Packet}; use crate::utils::epoch::{Epoch, UtcCalendar}; use crate::utils::rand::Rand; +use super::network::Address; use super::proto_ctx::ProtoCtx; use super::session::CloneData; @@ -45,12 +46,13 @@ enum RecvState { } pub enum RecvAction<'r, 'p> { - Send(&'r [u8]), + Send(Address, &'r [u8]), Interact(ProtoCtx<'r, 'p>), } pub struct RecvCompletion<'r, 'a, 'p> { mgr: &'r mut TransportMgr<'a>, + addr: Address, // TODO: Not used yet rx: &'r mut Packet<'p>, tx: &'r mut Packet<'p>, state: RecvState, @@ -90,9 +92,10 @@ impl<'r, 'a, 'p> RecvCompletion<'r, 'a, 'p> { self.state = RecvState::Ack; } - if reply { - proto_ctx.send()?; - Ok(Some(Some(RecvAction::Send(self.tx.as_slice())))) + let addr = if reply { proto_ctx.send()? } else { None }; + + if let Some(addr) = addr { + Ok(Some(Some(RecvAction::Send(addr, self.tx.as_slice())))) } else { Ok(None) } @@ -125,14 +128,22 @@ impl<'r, 'a, 'p> RecvCompletion<'r, 'a, 'p> { Err(err) => Err(err), }, RecvState::EvictSession => { - self.mgr.exch_mgr.evict_session(self.tx)?; + let addr = self.mgr.exch_mgr.evict_session(self.tx)?; self.state = RecvState::OpenExchange; - Ok(Some(Some(RecvAction::Send(self.tx.as_slice())))) + if let Some(addr) = addr { + Ok(Some(Some(RecvAction::Send(addr, self.tx.as_slice())))) + } else { + Ok(None) + } } RecvState::EvictSession2(clone_data) => { - self.mgr.exch_mgr.evict_session(self.tx)?; + let addr = self.mgr.exch_mgr.evict_session(self.tx)?; self.state = RecvState::AddSession(clone_data); - Ok(Some(Some(RecvAction::Send(self.tx.as_slice())))) + if let Some(addr) = addr { + Ok(Some(Some(RecvAction::Send(addr, self.tx.as_slice())))) + } else { + Ok(None) + } } RecvState::Ack => { if let Some(exch_id) = self.mgr.exch_mgr.pending_ack() { @@ -140,8 +151,8 @@ impl<'r, 'a, 'p> RecvCompletion<'r, 'a, 'p> { ReliableMessage::prepare_ack(exch_id, self.tx); - self.mgr.exch_mgr.send(exch_id, self.tx)?; - Ok(Some(Some(RecvAction::Send(self.tx.as_slice())))) + let addr = self.mgr.exch_mgr.send(exch_id, self.tx)?; + Ok(Some(Some(RecvAction::Send(addr, self.tx.as_slice())))) } else { Ok(Some(None)) } @@ -220,11 +231,13 @@ impl<'a> TransportMgr<'a> { pub fn recv<'r, 'p>( &'r mut self, + addr: Address, rx: &'r mut Packet<'p>, tx: &'r mut Packet<'p>, ) -> RecvCompletion<'r, 'a, 'p> { RecvCompletion { mgr: self, + addr, rx, tx, state: RecvState::New, diff --git a/matter/src/transport/proto_ctx.rs b/matter/src/transport/proto_ctx.rs index c4bf7f3..c7b95db 100644 --- a/matter/src/transport/proto_ctx.rs +++ b/matter/src/transport/proto_ctx.rs @@ -18,6 +18,7 @@ use crate::error::Error; use super::exchange::ExchangeCtx; +use super::network::Address; use super::packet::Packet; /// This is the context in which a receive packet is being processed @@ -35,9 +36,7 @@ impl<'a, 'b> ProtoCtx<'a, 'b> { Self { exch_ctx, rx, tx } } - pub fn send(&mut self) -> Result<&[u8], Error> { - self.exch_ctx.exch.send(self.tx, &mut self.exch_ctx.sess)?; - - Ok(self.tx.as_slice()) + pub fn send(&mut self) -> Result, Error> { + self.exch_ctx.exch.send(self.tx, &mut self.exch_ctx.sess) } } diff --git a/matter/src/transport/udp.rs b/matter/src/transport/udp.rs index 6f7a265..7a82fb3 100644 --- a/matter/src/transport/udp.rs +++ b/matter/src/transport/udp.rs @@ -48,7 +48,7 @@ impl UdpListener { Ok((size, Address::Udp(addr))) } - pub async fn send(&self, out_buf: &[u8], addr: Address) -> Result { + pub async fn send(&self, addr: Address, out_buf: &[u8]) -> Result { match addr { Address::Udp(addr) => self.socket.send_to(out_buf, addr).await.map_err(|e| { info!("Error on the network: {:?}", e);