Skip to content

Commit 7357d6d

Browse files
authored
Merge pull request project-chip#14 from kedars/feature/subscription_support
Draft: IM: Include baseline support for Subscription Transaction
2 parents 78586f3 + cc96c9d commit 7357d6d

File tree

4 files changed

+206
-4
lines changed

4 files changed

+206
-4
lines changed

matter/src/interaction_model/core.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,26 @@ impl InteractionModel {
100100
InteractionModel { consumer }
101101
}
102102

103+
pub fn handle_status_resp(
104+
&mut self,
105+
trans: &mut Transaction,
106+
rx_buf: &[u8],
107+
proto_tx: &mut Packet,
108+
) -> Result<ResponseRequired, Error> {
109+
let root = get_root_node_struct(rx_buf)?;
110+
let req = StatusResp::from_tlv(&root)?;
111+
112+
let mut handled = false;
113+
let result = self.handle_subscription_confirm(trans, proto_tx, &mut handled);
114+
if handled {
115+
result
116+
} else {
117+
// Nothing to do for now
118+
info!("Received status report with status {:?}", req.status);
119+
Ok(ResponseRequired::No)
120+
}
121+
}
122+
103123
pub fn handle_timed_req(
104124
&mut self,
105125
trans: &mut Transaction,
@@ -162,6 +182,8 @@ impl proto_demux::HandleProto for InteractionModel {
162182
OpCode::ReadRequest => self.handle_read_req(&mut trans, buf, &mut ctx.tx)?,
163183
OpCode::WriteRequest => self.handle_write_req(&mut trans, buf, &mut ctx.tx)?,
164184
OpCode::TimedRequest => self.handle_timed_req(&mut trans, buf, &mut ctx.tx)?,
185+
OpCode::SubscribeRequest => self.handle_subscribe_req(&mut trans, buf, &mut ctx.tx)?,
186+
OpCode::StatusResponse => self.handle_status_resp(&mut trans, buf, &mut ctx.tx)?,
165187
_ => {
166188
error!("Opcode Not Handled: {:?}", proto_opcode);
167189
return Err(Error::InvalidOpcode);

matter/src/interaction_model/messages.rs

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,55 @@ pub mod msg {
7171
tlv::{FromTLV, TLVArray, TLVElement, TLVWriter, TagType, ToTLV},
7272
};
7373

74-
use super::ib::{self, AttrData, AttrPath, AttrResp, AttrStatus, CmdData, DataVersionFilter};
74+
use super::ib::{
75+
self, AttrData, AttrPath, AttrResp, AttrStatus, CmdData, DataVersionFilter, EventFilter,
76+
EventPath,
77+
};
78+
79+
#[derive(FromTLV)]
80+
#[tlvargs(lifetime = "'a")]
81+
pub struct SubscribeReq<'a> {
82+
pub keep_subs: bool,
83+
pub min_int_floor: u16,
84+
pub max_int_ceil: u16,
85+
pub attr_requests: Option<TLVArray<'a, AttrPath>>,
86+
event_requests: Option<TLVArray<'a, EventPath>>,
87+
event_filters: Option<TLVArray<'a, EventFilter>>,
88+
// The Context Tags are discontiguous for some reason
89+
_dummy: Option<bool>,
90+
pub fabric_filtered: bool,
91+
pub dataver_filters: Option<TLVArray<'a, DataVersionFilter>>,
92+
}
93+
94+
impl<'a> SubscribeReq<'a> {
95+
pub fn to_read_req(&self) -> ReadReq<'a> {
96+
ReadReq {
97+
attr_requests: self.attr_requests,
98+
event_requests: self.event_requests,
99+
event_filters: self.event_filters,
100+
fabric_filtered: self.fabric_filtered,
101+
dataver_filters: self.dataver_filters,
102+
}
103+
}
104+
}
105+
106+
#[derive(ToTLV)]
107+
pub struct SubscribeResp {
108+
pub subs_id: u32,
109+
// The Context Tags are discontiguous for some reason
110+
_dummy: Option<u32>,
111+
pub max_int: u16,
112+
}
113+
114+
impl SubscribeResp {
115+
pub fn new(subs_id: u32, max_int: u16) -> Self {
116+
Self {
117+
subs_id,
118+
_dummy: None,
119+
max_int,
120+
}
121+
}
122+
}
75123

76124
#[derive(FromTLV, ToTLV)]
77125
pub struct TimedReq {
@@ -115,8 +163,8 @@ pub mod msg {
115163
#[tlvargs(lifetime = "'a")]
116164
pub struct ReadReq<'a> {
117165
pub attr_requests: Option<TLVArray<'a, AttrPath>>,
118-
event_requests: Option<bool>,
119-
event_filters: Option<bool>,
166+
event_requests: Option<TLVArray<'a, EventPath>>,
167+
event_filters: Option<TLVArray<'a, EventFilter>>,
120168
pub fabric_filtered: bool,
121169
pub dataver_filters: Option<TLVArray<'a, DataVersionFilter>>,
122170
}
@@ -172,7 +220,7 @@ pub mod msg {
172220
}
173221

174222
pub enum ReportDataTag {
175-
_SubscriptionId = 0,
223+
SubscriptionId = 0,
176224
AttributeReports = 1,
177225
_EventReport = 2,
178226
_MoreChunkedMsgs = 3,
@@ -472,4 +520,20 @@ pub mod ib {
472520
pub path: ClusterPath,
473521
pub data_ver: u32,
474522
}
523+
524+
#[derive(FromTLV, ToTLV, Copy, Clone)]
525+
#[tlvargs(datatype = "list")]
526+
pub struct EventPath {
527+
pub node: Option<u64>,
528+
pub endpoint: Option<u16>,
529+
pub cluster: Option<u32>,
530+
pub event: Option<u32>,
531+
pub is_urgent: Option<bool>,
532+
}
533+
534+
#[derive(FromTLV, ToTLV, Copy, Clone)]
535+
pub struct EventFilter {
536+
pub node: Option<u64>,
537+
pub event_min: Option<u64>,
538+
}
475539
}

matter/src/interaction_model/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,5 @@ pub mod command;
6464
pub mod core;
6565
pub mod messages;
6666
pub mod read;
67+
pub mod subscribe;
6768
pub mod write;
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
*
3+
* Copyright (c) 2023 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
use std::sync::atomic::{AtomicU32, Ordering};
19+
20+
use crate::{
21+
error::Error,
22+
interaction_model::core::OpCode,
23+
tlv::{get_root_node_struct, FromTLV, TLVWriter, TagType, ToTLV},
24+
transport::{packet::Packet, proto_demux::ResponseRequired},
25+
};
26+
27+
use log::error;
28+
29+
use super::{
30+
messages::msg::{self, SubscribeReq, SubscribeResp},
31+
InteractionModel, Transaction,
32+
};
33+
34+
static SUBS_ID: AtomicU32 = AtomicU32::new(1);
35+
36+
impl InteractionModel {
37+
pub fn handle_subscribe_req(
38+
&mut self,
39+
trans: &mut Transaction,
40+
rx_buf: &[u8],
41+
proto_tx: &mut Packet,
42+
) -> Result<ResponseRequired, Error> {
43+
proto_tx.set_proto_opcode(OpCode::ReportData as u8);
44+
45+
let mut tw = TLVWriter::new(proto_tx.get_writebuf()?);
46+
let root = get_root_node_struct(rx_buf)?;
47+
let req = SubscribeReq::from_tlv(&root)?;
48+
49+
let ctx = Box::new(SubsCtx {
50+
state: SubsState::Confirming,
51+
// TODO
52+
id: SUBS_ID.fetch_add(1, Ordering::SeqCst),
53+
});
54+
55+
let read_req = req.to_read_req();
56+
tw.start_struct(TagType::Anonymous)?;
57+
tw.u32(
58+
TagType::Context(msg::ReportDataTag::SubscriptionId as u8),
59+
ctx.id,
60+
)?;
61+
self.consumer.consume_read_attr(&read_req, trans, &mut tw)?;
62+
tw.bool(
63+
TagType::Context(msg::ReportDataTag::SupressResponse as u8),
64+
false,
65+
)?;
66+
tw.end_container()?;
67+
68+
if !trans.exch.is_data_none() {
69+
error!("Exchange data already set!");
70+
return Err(Error::InvalidState);
71+
}
72+
trans.exch.set_data_boxed(ctx);
73+
74+
Ok(ResponseRequired::Yes)
75+
}
76+
77+
pub fn handle_subscription_confirm(
78+
&mut self,
79+
trans: &mut Transaction,
80+
proto_tx: &mut Packet,
81+
request_handled: &mut bool,
82+
) -> Result<ResponseRequired, Error> {
83+
*request_handled = false;
84+
if let Some(ctx) = trans.exch.get_data_boxed::<SubsCtx>() {
85+
if ctx.state != SubsState::Confirming {
86+
// Not relevant for us
87+
return Err(Error::Invalid);
88+
}
89+
*request_handled = true;
90+
ctx.state = SubsState::Confirmed;
91+
proto_tx.set_proto_opcode(OpCode::SubscriptResponse as u8);
92+
93+
// TODO
94+
let resp = SubscribeResp::new(ctx.id, 40);
95+
let mut tw = TLVWriter::new(proto_tx.get_writebuf()?);
96+
resp.to_tlv(&mut tw, TagType::Anonymous)?;
97+
trans.complete();
98+
Ok(ResponseRequired::Yes)
99+
} else {
100+
trans.complete();
101+
Err(Error::Invalid)
102+
}
103+
}
104+
}
105+
106+
#[derive(PartialEq)]
107+
enum SubsState {
108+
Confirming,
109+
Confirmed,
110+
}
111+
112+
struct SubsCtx {
113+
state: SubsState,
114+
id: u32,
115+
}

0 commit comments

Comments
 (0)