Skip to content

Commit dd47aa9

Browse files
committed
ReadRequest: Basic stuff works across multi-hop reads
1 parent 487124c commit dd47aa9

File tree

6 files changed

+77
-47
lines changed

6 files changed

+77
-47
lines changed

matter/src/data_model/core/mod.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use crate::{
3737
InteractionConsumer, Transaction,
3838
},
3939
secure_channel::pake::PaseMgr,
40-
tlv::{TLVArray, TLVWriter, TagType, ToTLV},
40+
tlv::{self, FromTLV, TLVArray, TLVWriter, TagType, ToTLV},
4141
transport::{
4242
proto_demux::ResponseRequired,
4343
session::{Session, SessionMode},
@@ -259,13 +259,17 @@ impl InteractionConsumer for DataModel {
259259

260260
fn consume_read_attr(
261261
&self,
262-
req: &ReadReq,
262+
rx_buf: &[u8],
263263
trans: &mut Transaction,
264264
tw: &mut TLVWriter,
265265
) -> Result<(), Error> {
266-
let resume = self.handle_read_attr_array(req, trans, tw)?;
267-
if let Some(resume) = resume {
266+
let mut resume_from = None;
267+
let root = tlv::get_root_node(rx_buf)?;
268+
let req = ReadReq::from_tlv(&root)?;
269+
self.handle_read_attr_array(&req, trans, tw, &mut resume_from)?;
270+
if resume_from.is_some() {
268271
// This is a multi-hop read transaction, remember this read request
272+
let resume = read::ResumeReadReq::new(rx_buf, &resume_from)?;
269273
if !trans.exch.is_data_none() {
270274
error!("Exchange data already set, and multi-hop read");
271275
return Err(Error::InvalidState);
@@ -316,15 +320,16 @@ impl InteractionConsumer for DataModel {
316320
trans: &mut Transaction,
317321
tw: &mut TLVWriter,
318322
) -> Result<(OpCode, ResponseRequired), Error> {
319-
if let Some(resume) = trans.exch.take_data_boxed::<ResumeReq>() {
320-
match *resume {
321-
ResumeReq::Read(_) => Ok((OpCode::Reserved, ResponseRequired::No)),
323+
if let Some(mut resume) = trans.exch.take_data_boxed::<ResumeReq>() {
324+
let result = match *resume {
325+
ResumeReq::Read(ref mut read) => self.handle_resume_read(read, trans, tw)?,
326+
322327
ResumeReq::Subscribe(mut ctx) => {
323-
let result = self.handle_subscription_confirm(trans, tw, &mut ctx)?;
324-
trans.exch.set_data_boxed(resume);
325-
Ok(result)
328+
self.handle_subscription_confirm(trans, tw, &mut ctx)?
326329
}
327-
}
330+
};
331+
trans.exch.set_data_boxed(resume);
332+
Ok(result)
328333
} else {
329334
// Nothing to do for now
330335
trans.complete();

matter/src/data_model/core/read.rs

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,23 @@
1616
*/
1717

1818
use crate::data_model::{core::DataModel, objects::*};
19+
use crate::interaction_model::core::OpCode;
20+
use crate::tlv::FromTLV;
1921
use crate::transport::packet::Packet;
20-
use crate::utils::writebuf::WriteBuf;
22+
use crate::transport::proto_demux::ResponseRequired;
2123
use crate::{
2224
acl::{AccessReq, Accessor},
2325
error::*,
2426
interaction_model::{
2527
core::IMStatusCode,
2628
messages::{
2729
ib::{self, DataVersionFilter},
28-
msg::{self, ReadReq, ReportDataTag::MoreChunkedMsgs},
30+
msg::{self, ReadReq, ReportDataTag::MoreChunkedMsgs, ReportDataTag::SupressResponse},
2931
GenericPath,
3032
},
3133
Transaction,
3234
},
33-
tlv::{TLVArray, TLVWriter, TagType, ToTLV},
35+
tlv::{self, TLVArray, TLVWriter, TagType, ToTLV},
3436
};
3537

3638
/// Encoder for generating a response to a read request
@@ -112,7 +114,21 @@ pub struct ResumeReadReq {
112114
/// will start encoding from this attribute onwards.
113115
/// Note that given wildcard reads, one PendingPath in the member above can generated
114116
/// multiple encode paths. Hence this has to be maintained separately.
115-
resume_encode: Option<GenericPath>,
117+
resume_from: Option<GenericPath>,
118+
}
119+
impl ResumeReadReq {
120+
pub fn new(rx_buf: &[u8], resume_from: &Option<GenericPath>) -> Result<Self, Error> {
121+
let mut packet = Packet::new_rx()?;
122+
let dst = packet.as_borrow_slice();
123+
124+
let src_len = rx_buf.len();
125+
dst[..src_len].copy_from_slice(rx_buf);
126+
packet.get_parsebuf()?.set_len(src_len);
127+
Ok(ResumeReadReq {
128+
pending_req: Some(packet),
129+
resume_from: *resume_from,
130+
})
131+
}
116132
}
117133

118134
impl DataModel {
@@ -195,9 +211,8 @@ impl DataModel {
195211
read_req: &ReadReq,
196212
trans: &mut Transaction,
197213
tw: &mut TLVWriter,
198-
) -> Result<Option<ResumeReadReq>, Error> {
199-
let mut resume_read_req: ResumeReadReq = Default::default();
200-
214+
resume_from: &mut Option<GenericPath>,
215+
) -> Result<(), Error> {
201216
let mut attr_encoder = AttrReadEncoder::new(tw);
202217
if let Some(filters) = &read_req.dataver_filters {
203218
attr_encoder.set_data_ver_filters(filters);
@@ -221,33 +236,43 @@ impl DataModel {
221236
&accessor,
222237
&mut attr_encoder,
223238
&mut attr_details,
224-
&mut resume_read_req.resume_encode,
239+
resume_from,
225240
);
226241
}
227242
tw.end_container()?;
228243
if result.is_err() {
229244
// If there was an error, indicate chunking. The resume_read_req would have been
230245
// already populated from in the loop above.
231246
tw.bool(TagType::Context(MoreChunkedMsgs as u8), true)?;
232-
// Retain the entire request, because we need the data-filters, and subsequent attr-reads, if any
233-
// when we resume this read in the next hop
234-
resume_read_req.pending_req = Some(copy_read_req_to_packet(read_req)?);
235-
return Ok(Some(resume_read_req));
247+
return Ok(());
236248
}
237249
}
238-
Ok(None)
250+
// A None resume_from indicates no chunking
251+
*resume_from = None;
252+
Ok(())
239253
}
240-
}
241254

242-
fn copy_read_req_to_packet(read_req: &ReadReq) -> Result<Packet<'static>, Error> {
243-
let mut packet = Packet::new_rx()?;
244-
let backup = packet.as_borrow_slice();
245-
let backup_len = backup.len();
246-
let mut wb = WriteBuf::new(backup, backup_len);
247-
let mut tw = TLVWriter::new(&mut wb);
248-
// TODO: This is unnecessarily wasteful, could directly copy &[u8] if accessible
249-
read_req.to_tlv(&mut tw, TagType::Anonymous)?;
250-
let data_len = wb.as_borrow_slice().len();
251-
packet.get_parsebuf()?.set_len(data_len);
252-
Ok(packet)
255+
pub fn handle_resume_read(
256+
&self,
257+
resume_read_req: &mut ResumeReadReq,
258+
trans: &mut Transaction,
259+
tw: &mut TLVWriter,
260+
) -> Result<(OpCode, ResponseRequired), Error> {
261+
if let Some(packet) = resume_read_req.pending_req.as_mut() {
262+
let rx_buf = packet.get_parsebuf()?.as_borrow_slice();
263+
let root = tlv::get_root_node(rx_buf)?;
264+
let req = ReadReq::from_tlv(&root)?;
265+
266+
tw.start_struct(TagType::Anonymous)?;
267+
self.handle_read_attr_array(&req, trans, tw, &mut resume_read_req.resume_from)?;
268+
269+
if resume_read_req.resume_from.is_none() {
270+
tw.bool(TagType::Context(SupressResponse as u8), true)?;
271+
// Mark transaction complete, if not chunked
272+
trans.complete();
273+
}
274+
tw.end_container()?;
275+
}
276+
Ok((OpCode::ReportData, ResponseRequired::Yes))
277+
}
253278
}

matter/src/data_model/core/subscribe.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ impl DataModel {
5050
TagType::Context(msg::ReportDataTag::SubscriptionId as u8),
5151
ctx.id,
5252
)?;
53-
self.handle_read_attr_array(&read_req, trans, tw)?;
53+
let mut resume_from = None;
54+
self.handle_read_attr_array(&read_req, trans, tw, &mut resume_from)?;
5455
tw.end_container()?;
5556

5657
Ok(ctx)

matter/src/interaction_model/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::{
2323

2424
use self::{
2525
core::OpCode,
26-
messages::msg::{InvReq, ReadReq, StatusResp, SubscribeReq, WriteReq},
26+
messages::msg::{InvReq, StatusResp, SubscribeReq, WriteReq},
2727
};
2828

2929
#[derive(PartialEq)]
@@ -47,7 +47,9 @@ pub trait InteractionConsumer {
4747

4848
fn consume_read_attr(
4949
&self,
50-
req: &ReadReq,
50+
// TODO: This handling is different from the other APIs here, identify
51+
// consistent options for this trait
52+
req: &[u8],
5153
trans: &mut Transaction,
5254
tw: &mut TLVWriter,
5355
) -> Result<(), Error>;

matter/src/interaction_model/read.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@
1818
use crate::{
1919
error::Error,
2020
interaction_model::core::OpCode,
21-
tlv::{get_root_node_struct, FromTLV, TLVWriter, TagType},
21+
tlv::{TLVWriter, TagType},
2222
transport::{packet::Packet, proto_demux::ResponseRequired},
2323
utils::writebuf::WriteBuf,
2424
wb_shrink, wb_unshrink,
2525
};
2626

27-
use super::{messages::msg::ReadReq, InteractionModel, Transaction};
27+
use super::{InteractionModel, Transaction};
2828

2929
impl InteractionModel {
3030
pub fn handle_read_req(
@@ -40,13 +40,11 @@ impl InteractionModel {
4040
let proto_tx_wb = proto_tx.get_writebuf()?;
4141
let mut child_wb = wb_shrink!(proto_tx_wb, RESERVE_SIZE);
4242
let mut tw = TLVWriter::new(&mut child_wb);
43-
let root = get_root_node_struct(rx_buf)?;
44-
let read_req = ReadReq::from_tlv(&root)?;
4543

4644
tw.start_struct(TagType::Anonymous)?;
47-
self.consumer.consume_read_attr(&read_req, trans, &mut tw)?;
45+
self.consumer.consume_read_attr(rx_buf, trans, &mut tw)?;
4846

49-
// Now that we have everything, start using the proto_tx_wb, by unshrinking it
47+
//Now that we have everything, start using the proto_tx_wb, by unshrinking it
5048
wb_unshrink!(proto_tx_wb, child_wb);
5149
let mut tw = TLVWriter::new(proto_tx_wb);
5250
tw.end_container()?;

matter/tests/interaction_model.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use boxslab::Slab;
1919
use matter::error::Error;
2020
use matter::interaction_model::core::OpCode;
2121
use matter::interaction_model::messages::msg::InvReq;
22-
use matter::interaction_model::messages::msg::ReadReq;
2322
use matter::interaction_model::messages::msg::WriteReq;
2423
use matter::interaction_model::InteractionConsumer;
2524
use matter::interaction_model::InteractionModel;
@@ -94,7 +93,7 @@ impl InteractionConsumer for DataModel {
9493

9594
fn consume_read_attr(
9695
&self,
97-
_req: &ReadReq,
96+
_req: &[u8],
9897
_trans: &mut Transaction,
9998
_tlvwriter: &mut TLVWriter,
10099
) -> Result<(), Error> {

0 commit comments

Comments
 (0)