Merge branch 'feature/multi-admin' into mdns-disco-multi-admin
This commit is contained in:
commit
5499e6ccdc
15 changed files with 157 additions and 35 deletions
|
@ -35,11 +35,12 @@ fn main() {
|
||||||
pid: 0x8002,
|
pid: 0x8002,
|
||||||
hw_ver: 2,
|
hw_ver: 2,
|
||||||
sw_ver: 1,
|
sw_ver: 1,
|
||||||
|
serial_no: "aabbccdd".to_string(),
|
||||||
device_name: "OnOff Light".to_string(),
|
device_name: "OnOff Light".to_string(),
|
||||||
};
|
};
|
||||||
let dev_att = Box::new(dev_att::HardCodedDevAtt::new());
|
let dev_att = Box::new(dev_att::HardCodedDevAtt::new());
|
||||||
|
|
||||||
let mut matter = core::Matter::new(&dev_info, dev_att, comm_data).unwrap();
|
let mut matter = core::Matter::new(dev_info, dev_att, comm_data).unwrap();
|
||||||
let dm = matter.get_data_model();
|
let dm = matter.get_data_model();
|
||||||
{
|
{
|
||||||
let mut node = dm.node.write().unwrap();
|
let mut node = dm.node.write().unwrap();
|
||||||
|
|
|
@ -54,7 +54,7 @@ impl Matter {
|
||||||
/// requires a set of device attestation certificates and keys. It is the responsibility of
|
/// requires a set of device attestation certificates and keys. It is the responsibility of
|
||||||
/// this object to return the device attestation details when queried upon.
|
/// this object to return the device attestation details when queried upon.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
dev_det: &BasicInfoConfig,
|
dev_det: BasicInfoConfig,
|
||||||
dev_att: Box<dyn DevAttDataFetcher>,
|
dev_att: Box<dyn DevAttDataFetcher>,
|
||||||
dev_comm: CommissioningData,
|
dev_comm: CommissioningData,
|
||||||
) -> Result<Box<Matter>, Error> {
|
) -> Result<Box<Matter>, Error> {
|
||||||
|
|
|
@ -17,13 +17,18 @@
|
||||||
|
|
||||||
use super::objects::*;
|
use super::objects::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
use num_derive::FromPrimitive;
|
||||||
|
|
||||||
pub const ID: u32 = 0x0028;
|
pub const ID: u32 = 0x0028;
|
||||||
|
|
||||||
|
#[derive(FromPrimitive)]
|
||||||
enum Attributes {
|
enum Attributes {
|
||||||
|
DMRevision = 0,
|
||||||
VendorId = 2,
|
VendorId = 2,
|
||||||
ProductId = 4,
|
ProductId = 4,
|
||||||
HwVer = 7,
|
HwVer = 7,
|
||||||
SwVer = 9,
|
SwVer = 9,
|
||||||
|
SerialNo = 0x0f,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -32,6 +37,16 @@ pub struct BasicInfoConfig {
|
||||||
pub pid: u16,
|
pub pid: u16,
|
||||||
pub hw_ver: u16,
|
pub hw_ver: u16,
|
||||||
pub sw_ver: u32,
|
pub sw_ver: u32,
|
||||||
|
pub serial_no: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attr_dm_rev_new() -> Result<Attribute, Error> {
|
||||||
|
Attribute::new(
|
||||||
|
Attributes::DMRevision as u16,
|
||||||
|
AttrValue::Uint8(1),
|
||||||
|
Access::RV,
|
||||||
|
Quality::FIXED,
|
||||||
|
)
|
||||||
/// Device name; up to 32 characters
|
/// Device name; up to 32 characters
|
||||||
pub device_name: String,
|
pub device_name: String,
|
||||||
}
|
}
|
||||||
|
@ -72,19 +87,31 @@ fn attr_sw_ver_new(sw_ver: u32) -> Result<Attribute, Error> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn attr_serial_no_new(label: String) -> Result<Attribute, Error> {
|
||||||
|
Attribute::new(
|
||||||
|
Attributes::SerialNo as u16,
|
||||||
|
AttrValue::Utf8(label),
|
||||||
|
Access::RV,
|
||||||
|
Quality::FIXED,
|
||||||
|
)
|
||||||
|
}
|
||||||
pub struct BasicInfoCluster {
|
pub struct BasicInfoCluster {
|
||||||
base: Cluster,
|
base: Cluster,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BasicInfoCluster {
|
impl BasicInfoCluster {
|
||||||
pub fn new(cfg: &BasicInfoConfig) -> Result<Box<Self>, Error> {
|
pub fn new(cfg: BasicInfoConfig) -> Result<Box<Self>, Error> {
|
||||||
let mut cluster = Box::new(BasicInfoCluster {
|
let mut cluster = Box::new(BasicInfoCluster {
|
||||||
base: Cluster::new(ID)?,
|
base: Cluster::new(ID)?,
|
||||||
});
|
});
|
||||||
|
cluster.base.add_attribute(attr_dm_rev_new()?)?;
|
||||||
cluster.base.add_attribute(attr_vid_new(cfg.vid)?)?;
|
cluster.base.add_attribute(attr_vid_new(cfg.vid)?)?;
|
||||||
cluster.base.add_attribute(attr_pid_new(cfg.pid)?)?;
|
cluster.base.add_attribute(attr_pid_new(cfg.pid)?)?;
|
||||||
cluster.base.add_attribute(attr_hw_ver_new(cfg.hw_ver)?)?;
|
cluster.base.add_attribute(attr_hw_ver_new(cfg.hw_ver)?)?;
|
||||||
cluster.base.add_attribute(attr_sw_ver_new(cfg.sw_ver)?)?;
|
cluster.base.add_attribute(attr_sw_ver_new(cfg.sw_ver)?)?;
|
||||||
|
cluster
|
||||||
|
.base
|
||||||
|
.add_attribute(attr_serial_no_new(cfg.serial_no)?)?;
|
||||||
Ok(cluster)
|
Ok(cluster)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ pub struct DataModel {
|
||||||
|
|
||||||
impl DataModel {
|
impl DataModel {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
dev_details: &BasicInfoConfig,
|
dev_details: BasicInfoConfig,
|
||||||
dev_att: Box<dyn DevAttDataFetcher>,
|
dev_att: Box<dyn DevAttDataFetcher>,
|
||||||
fabric_mgr: Arc<FabricMgr>,
|
fabric_mgr: Arc<FabricMgr>,
|
||||||
acl_mgr: Arc<AclMgr>,
|
acl_mgr: Arc<AclMgr>,
|
||||||
|
@ -84,7 +84,7 @@ impl DataModel {
|
||||||
) -> Result<AttrValue, IMStatusCode> {
|
) -> Result<AttrValue, IMStatusCode> {
|
||||||
let node = self.node.read().unwrap();
|
let node = self.node.read().unwrap();
|
||||||
let cluster = node.get_cluster(endpoint, cluster)?;
|
let cluster = node.get_cluster(endpoint, cluster)?;
|
||||||
cluster.base().read_attribute_raw(attr).map(|a| *a)
|
cluster.base().read_attribute_raw(attr).map(|a| a.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode a write attribute from a path that may or may not be wildcard
|
// Encode a write attribute from a path that may or may not be wildcard
|
||||||
|
|
|
@ -32,18 +32,23 @@ use crate::secure_channel::pake::PaseMgr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::RwLockWriteGuard;
|
use std::sync::RwLockWriteGuard;
|
||||||
|
|
||||||
|
pub const DEV_TYPE_ROOT_NODE: DeviceType = DeviceType {
|
||||||
|
dtype: 0x0016,
|
||||||
|
drev: 1,
|
||||||
|
};
|
||||||
|
|
||||||
type WriteNode<'a> = RwLockWriteGuard<'a, Box<Node>>;
|
type WriteNode<'a> = RwLockWriteGuard<'a, Box<Node>>;
|
||||||
|
|
||||||
pub fn device_type_add_root_node(
|
pub fn device_type_add_root_node(
|
||||||
node: &mut WriteNode,
|
node: &mut WriteNode,
|
||||||
dev_info: &BasicInfoConfig,
|
dev_info: BasicInfoConfig,
|
||||||
dev_att: Box<dyn DevAttDataFetcher>,
|
dev_att: Box<dyn DevAttDataFetcher>,
|
||||||
fabric_mgr: Arc<FabricMgr>,
|
fabric_mgr: Arc<FabricMgr>,
|
||||||
acl_mgr: Arc<AclMgr>,
|
acl_mgr: Arc<AclMgr>,
|
||||||
pase_mgr: PaseMgr,
|
pase_mgr: PaseMgr,
|
||||||
) -> Result<u32, Error> {
|
) -> Result<u32, Error> {
|
||||||
// Add the root endpoint
|
// Add the root endpoint
|
||||||
let endpoint = node.add_endpoint()?;
|
let endpoint = node.add_endpoint(DEV_TYPE_ROOT_NODE)?;
|
||||||
if endpoint != 0 {
|
if endpoint != 0 {
|
||||||
// Somehow endpoint 0 was already added, this shouldn't be the case
|
// Somehow endpoint 0 was already added, this shouldn't be the case
|
||||||
return Err(Error::Invalid);
|
return Err(Error::Invalid);
|
||||||
|
@ -63,8 +68,13 @@ pub fn device_type_add_root_node(
|
||||||
Ok(endpoint)
|
Ok(endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEV_TYPE_ON_OFF_LIGHT: DeviceType = DeviceType {
|
||||||
|
dtype: 0x0100,
|
||||||
|
drev: 2,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn device_type_add_on_off_light(node: &mut WriteNode) -> Result<u32, Error> {
|
pub fn device_type_add_on_off_light(node: &mut WriteNode) -> Result<u32, Error> {
|
||||||
let endpoint = node.add_endpoint()?;
|
let endpoint = node.add_endpoint(DEV_TYPE_ON_OFF_LIGHT)?;
|
||||||
node.add_cluster(endpoint, OnOffCluster::new()?)?;
|
node.add_cluster(endpoint, OnOffCluster::new()?)?;
|
||||||
Ok(endpoint)
|
Ok(endpoint)
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ bitflags! {
|
||||||
* - instead of arrays, can use linked-lists to conserve space and avoid the internal fragmentation
|
* - instead of arrays, can use linked-lists to conserve space and avoid the internal fragmentation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
pub enum AttrValue {
|
pub enum AttrValue {
|
||||||
Int64(i64),
|
Int64(i64),
|
||||||
Uint8(u8),
|
Uint8(u8),
|
||||||
|
@ -96,6 +96,7 @@ pub enum AttrValue {
|
||||||
Uint32(u32),
|
Uint32(u32),
|
||||||
Uint64(u64),
|
Uint64(u64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
|
Utf8(String),
|
||||||
Custom,
|
Custom,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +109,7 @@ impl Debug for AttrValue {
|
||||||
AttrValue::Uint32(v) => write!(f, "{:?}", *v),
|
AttrValue::Uint32(v) => write!(f, "{:?}", *v),
|
||||||
AttrValue::Uint64(v) => write!(f, "{:?}", *v),
|
AttrValue::Uint64(v) => write!(f, "{:?}", *v),
|
||||||
AttrValue::Bool(v) => write!(f, "{:?}", *v),
|
AttrValue::Bool(v) => write!(f, "{:?}", *v),
|
||||||
|
AttrValue::Utf8(v) => write!(f, "{:?}", *v),
|
||||||
AttrValue::Custom => write!(f, "custom-attribute"),
|
AttrValue::Custom => write!(f, "custom-attribute"),
|
||||||
}?;
|
}?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -123,6 +125,7 @@ impl ToTLV for AttrValue {
|
||||||
AttrValue::Uint16(v) => tw.u16(tag_type, *v),
|
AttrValue::Uint16(v) => tw.u16(tag_type, *v),
|
||||||
AttrValue::Uint32(v) => tw.u32(tag_type, *v),
|
AttrValue::Uint32(v) => tw.u32(tag_type, *v),
|
||||||
AttrValue::Uint64(v) => tw.u64(tag_type, *v),
|
AttrValue::Uint64(v) => tw.u64(tag_type, *v),
|
||||||
|
AttrValue::Utf8(v) => tw.utf8(tag_type, v.as_bytes()),
|
||||||
_ => {
|
_ => {
|
||||||
error!("Attribute type not yet supported");
|
error!("Attribute type not yet supported");
|
||||||
Err(Error::AttributeNotFound)
|
Err(Error::AttributeNotFound)
|
||||||
|
|
|
@ -87,7 +87,6 @@ pub trait ClusterType {
|
||||||
pub struct Cluster {
|
pub struct Cluster {
|
||||||
pub(super) id: u32,
|
pub(super) id: u32,
|
||||||
attributes: Vec<Attribute>,
|
attributes: Vec<Attribute>,
|
||||||
feature_map: Option<u32>,
|
|
||||||
data_ver: u32,
|
data_ver: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +95,6 @@ impl Cluster {
|
||||||
let mut c = Cluster {
|
let mut c = Cluster {
|
||||||
id,
|
id,
|
||||||
attributes: Vec::with_capacity(ATTRS_PER_CLUSTER),
|
attributes: Vec::with_capacity(ATTRS_PER_CLUSTER),
|
||||||
feature_map: None,
|
|
||||||
data_ver: rand::thread_rng().gen_range(0..0xFFFFFFFF),
|
data_ver: rand::thread_rng().gen_range(0..0xFFFFFFFF),
|
||||||
};
|
};
|
||||||
c.add_default_attributes()?;
|
c.add_default_attributes()?;
|
||||||
|
@ -112,22 +110,20 @@ impl Cluster {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_feature_map(&mut self, map: u32) -> Result<(), Error> {
|
pub fn set_feature_map(&mut self, map: u32) -> Result<(), Error> {
|
||||||
if self.feature_map.is_none() {
|
self.write_attribute_raw(GlobalElements::FeatureMap as u16, AttrValue::Uint32(map))
|
||||||
self.add_attribute(Attribute::new(
|
.map_err(|_| Error::Invalid)?;
|
||||||
GlobalElements::FeatureMap as u16,
|
|
||||||
AttrValue::Uint32(map),
|
|
||||||
Access::RV,
|
|
||||||
Quality::NONE,
|
|
||||||
)?)?;
|
|
||||||
} else {
|
|
||||||
self.write_attribute_raw(GlobalElements::FeatureMap as u16, AttrValue::Uint32(map))
|
|
||||||
.map_err(|_| Error::Invalid)?;
|
|
||||||
}
|
|
||||||
self.feature_map = Some(map);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_default_attributes(&mut self) -> Result<(), Error> {
|
fn add_default_attributes(&mut self) -> Result<(), Error> {
|
||||||
|
// Default feature map is 0
|
||||||
|
self.add_attribute(Attribute::new(
|
||||||
|
GlobalElements::FeatureMap as u16,
|
||||||
|
AttrValue::Uint32(0),
|
||||||
|
Access::RV,
|
||||||
|
Quality::NONE,
|
||||||
|
)?)?;
|
||||||
|
|
||||||
self.add_attribute(Attribute::new(
|
self.add_attribute(Attribute::new(
|
||||||
GlobalElements::AttributeList as u16,
|
GlobalElements::AttributeList as u16,
|
||||||
AttrValue::Custom,
|
AttrValue::Custom,
|
||||||
|
@ -233,8 +229,7 @@ impl Cluster {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GlobalElements::FeatureMap => {
|
GlobalElements::FeatureMap => {
|
||||||
let val = if let Some(m) = self.feature_map { m } else { 0 };
|
encoder.encode(EncodeValue::Value(&attr.value));
|
||||||
encoder.encode(EncodeValue::Value(&val));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -284,7 +279,7 @@ impl Cluster {
|
||||||
) -> Result<(), IMStatusCode> {
|
) -> Result<(), IMStatusCode> {
|
||||||
let a = self.get_attribute_mut(attr_id)?;
|
let a = self.get_attribute_mut(attr_id)?;
|
||||||
if a.value != AttrValue::Custom {
|
if a.value != AttrValue::Custom {
|
||||||
let mut value = a.value;
|
let mut value = a.value.clone();
|
||||||
value
|
value
|
||||||
.update_from_tlv(data)
|
.update_from_tlv(data)
|
||||||
.map_err(|_| IMStatusCode::Failure)?;
|
.map_err(|_| IMStatusCode::Failure)?;
|
||||||
|
|
|
@ -115,3 +115,9 @@ pub trait Encoder {
|
||||||
/// Encode a status report
|
/// Encode a status report
|
||||||
fn encode_status(&mut self, status: IMStatusCode, cluster_status: u16);
|
fn encode_status(&mut self, status: IMStatusCode, cluster_status: u16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(ToTLV, Copy, Clone)]
|
||||||
|
pub struct DeviceType {
|
||||||
|
pub dtype: u16,
|
||||||
|
pub drev: u16,
|
||||||
|
}
|
||||||
|
|
|
@ -19,17 +19,21 @@ use crate::{data_model::objects::ClusterType, error::*, interaction_model::core:
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use super::DeviceType;
|
||||||
|
|
||||||
pub const CLUSTERS_PER_ENDPT: usize = 9;
|
pub const CLUSTERS_PER_ENDPT: usize = 9;
|
||||||
|
|
||||||
pub struct Endpoint {
|
pub struct Endpoint {
|
||||||
|
dev_type: DeviceType,
|
||||||
clusters: Vec<Box<dyn ClusterType>>,
|
clusters: Vec<Box<dyn ClusterType>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BoxedClusters = [Box<dyn ClusterType>];
|
pub type BoxedClusters = [Box<dyn ClusterType>];
|
||||||
|
|
||||||
impl Endpoint {
|
impl Endpoint {
|
||||||
pub fn new() -> Result<Box<Endpoint>, Error> {
|
pub fn new(dev_type: DeviceType) -> Result<Box<Endpoint>, Error> {
|
||||||
Ok(Box::new(Endpoint {
|
Ok(Box::new(Endpoint {
|
||||||
|
dev_type,
|
||||||
clusters: Vec::with_capacity(CLUSTERS_PER_ENDPT),
|
clusters: Vec::with_capacity(CLUSTERS_PER_ENDPT),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -43,6 +47,10 @@ impl Endpoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_dev_type(&self) -> &DeviceType {
|
||||||
|
&self.dev_type
|
||||||
|
}
|
||||||
|
|
||||||
fn get_cluster_index(&self, cluster_id: u32) -> Option<usize> {
|
fn get_cluster_index(&self, cluster_id: u32) -> Option<usize> {
|
||||||
self.clusters.iter().position(|c| c.base().id == cluster_id)
|
self.clusters.iter().position(|c| c.base().id == cluster_id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use super::DeviceType;
|
||||||
|
|
||||||
pub trait ChangeConsumer {
|
pub trait ChangeConsumer {
|
||||||
fn endpoint_added(&self, id: u16, endpoint: &mut Endpoint) -> Result<(), Error>;
|
fn endpoint_added(&self, id: u16, endpoint: &mut Endpoint) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
@ -59,13 +61,13 @@ impl Node {
|
||||||
self.changes_cb = Some(consumer);
|
self.changes_cb = Some(consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_endpoint(&mut self) -> Result<u32, Error> {
|
pub fn add_endpoint(&mut self, dev_type: DeviceType) -> Result<u32, Error> {
|
||||||
let index = self
|
let index = self
|
||||||
.endpoints
|
.endpoints
|
||||||
.iter()
|
.iter()
|
||||||
.position(|x| x.is_none())
|
.position(|x| x.is_none())
|
||||||
.ok_or(Error::NoSpace)?;
|
.ok_or(Error::NoSpace)?;
|
||||||
let mut endpoint = Endpoint::new()?;
|
let mut endpoint = Endpoint::new(dev_type)?;
|
||||||
if let Some(cb) = &self.changes_cb {
|
if let Some(cb) = &self.changes_cb {
|
||||||
cb.endpoint_added(index as u16, &mut endpoint)?;
|
cb.endpoint_added(index as u16, &mut endpoint)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::data_model::core::DataModel;
|
||||||
use crate::data_model::objects::*;
|
use crate::data_model::objects::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::interaction_model::messages::GenericPath;
|
use crate::interaction_model::messages::GenericPath;
|
||||||
use crate::tlv::{TLVWriter, TagType};
|
use crate::tlv::{TLVWriter, TagType, ToTLV};
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
pub const ID: u32 = 0x001D;
|
pub const ID: u32 = 0x001D;
|
||||||
|
@ -48,11 +48,28 @@ impl DescriptorCluster {
|
||||||
data_model,
|
data_model,
|
||||||
base: Cluster::new(ID)?,
|
base: Cluster::new(ID)?,
|
||||||
});
|
});
|
||||||
|
c.base.add_attribute(attr_devtypelist_new()?)?;
|
||||||
c.base.add_attribute(attr_serverlist_new()?)?;
|
c.base.add_attribute(attr_serverlist_new()?)?;
|
||||||
c.base.add_attribute(attr_partslist_new()?)?;
|
c.base.add_attribute(attr_partslist_new()?)?;
|
||||||
Ok(c)
|
Ok(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encode_devtype_list(&self, tag: TagType, tw: &mut TLVWriter) {
|
||||||
|
let path = GenericPath {
|
||||||
|
endpoint: Some(self.endpoint_id),
|
||||||
|
cluster: None,
|
||||||
|
leaf: None,
|
||||||
|
};
|
||||||
|
let _ = tw.start_array(tag);
|
||||||
|
let dm = self.data_model.node.read().unwrap();
|
||||||
|
let _ = dm.for_each_endpoint(&path, |_, e| {
|
||||||
|
let dev_type = e.get_dev_type();
|
||||||
|
let _ = dev_type.to_tlv(tw, TagType::Anonymous);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
let _ = tw.end_container();
|
||||||
|
}
|
||||||
|
|
||||||
fn encode_server_list(&self, tag: TagType, tw: &mut TLVWriter) {
|
fn encode_server_list(&self, tag: TagType, tw: &mut TLVWriter) {
|
||||||
let path = GenericPath {
|
let path = GenericPath {
|
||||||
endpoint: Some(self.endpoint_id),
|
endpoint: Some(self.endpoint_id),
|
||||||
|
@ -69,8 +86,24 @@ impl DescriptorCluster {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_parts_list(&self, tag: TagType, tw: &mut TLVWriter) {
|
fn encode_parts_list(&self, tag: TagType, tw: &mut TLVWriter) {
|
||||||
// TODO: Support Partslist
|
let path = GenericPath {
|
||||||
|
endpoint: None,
|
||||||
|
cluster: None,
|
||||||
|
leaf: None,
|
||||||
|
};
|
||||||
let _ = tw.start_array(tag);
|
let _ = tw.start_array(tag);
|
||||||
|
if self.endpoint_id == 0 {
|
||||||
|
// TODO: If endpoint is another than 0, need to figure out what to do
|
||||||
|
let dm = self.data_model.node.read().unwrap();
|
||||||
|
let _ = dm.for_each_endpoint(&path, |current_path, _| {
|
||||||
|
if let Some(endpoint_id) = current_path.endpoint {
|
||||||
|
if endpoint_id != 0 {
|
||||||
|
let _ = tw.u16(TagType::Anonymous, endpoint_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
let _ = tw.end_container();
|
let _ = tw.end_container();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,6 +118,9 @@ impl ClusterType for DescriptorCluster {
|
||||||
|
|
||||||
fn read_custom_attribute(&self, encoder: &mut dyn Encoder, attr: &AttrDetails) {
|
fn read_custom_attribute(&self, encoder: &mut dyn Encoder, attr: &AttrDetails) {
|
||||||
match num::FromPrimitive::from_u16(attr.attr_id) {
|
match num::FromPrimitive::from_u16(attr.attr_id) {
|
||||||
|
Some(Attributes::DeviceTypeList) => encoder.encode(EncodeValue::Closure(&|tag, tw| {
|
||||||
|
self.encode_devtype_list(tag, tw)
|
||||||
|
})),
|
||||||
Some(Attributes::ServerList) => encoder.encode(EncodeValue::Closure(&|tag, tw| {
|
Some(Attributes::ServerList) => encoder.encode(EncodeValue::Closure(&|tag, tw| {
|
||||||
self.encode_server_list(tag, tw)
|
self.encode_server_list(tag, tw)
|
||||||
})),
|
})),
|
||||||
|
@ -98,6 +134,14 @@ impl ClusterType for DescriptorCluster {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn attr_devtypelist_new() -> Result<Attribute, Error> {
|
||||||
|
Attribute::new(
|
||||||
|
Attributes::DeviceTypeList as u16,
|
||||||
|
AttrValue::Custom,
|
||||||
|
Access::RV,
|
||||||
|
Quality::NONE,
|
||||||
|
)
|
||||||
|
}
|
||||||
fn attr_serverlist_new() -> Result<Attribute, Error> {
|
fn attr_serverlist_new() -> Result<Attribute, Error> {
|
||||||
Attribute::new(
|
Attribute::new(
|
||||||
Attributes::ServerList as u16,
|
Attributes::ServerList as u16,
|
||||||
|
|
|
@ -50,12 +50,13 @@
|
||||||
//! pid: 0xFFF1,
|
//! pid: 0xFFF1,
|
||||||
//! hw_ver: 2,
|
//! hw_ver: 2,
|
||||||
//! sw_ver: 1,
|
//! sw_ver: 1,
|
||||||
|
//! serial_no: "aabbcc".to_string(),
|
||||||
//! device_name: "OnOff Light".to_string(),
|
//! device_name: "OnOff Light".to_string(),
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
//! /// Get the Matter Object
|
//! /// Get the Matter Object
|
||||||
//! /// The dev_att is an object that implements the DevAttDataFetcher trait.
|
//! /// The dev_att is an object that implements the DevAttDataFetcher trait.
|
||||||
//! let mut matter = Matter::new(&dev_info, dev_att, comm_data).unwrap();
|
//! let mut matter = Matter::new(dev_info, dev_att, comm_data).unwrap();
|
||||||
//! let dm = matter.get_data_model();
|
//! let dm = matter.get_data_model();
|
||||||
//! {
|
//! {
|
||||||
//! let mut node = dm.node.write().unwrap();
|
//! let mut node = dm.node.write().unwrap();
|
||||||
|
|
|
@ -94,6 +94,7 @@ impl ImEngine {
|
||||||
pid: 11,
|
pid: 11,
|
||||||
hw_ver: 12,
|
hw_ver: 12,
|
||||||
sw_ver: 13,
|
sw_ver: 13,
|
||||||
|
serial_no: "aabbccdd".to_string(),
|
||||||
device_name: "Test Device".to_string(),
|
device_name: "Test Device".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,7 +107,14 @@ impl ImEngine {
|
||||||
// Only allow the standard peer node id of the IM Engine
|
// Only allow the standard peer node id of the IM Engine
|
||||||
default_acl.add_subject(IM_ENGINE_PEER_ID).unwrap();
|
default_acl.add_subject(IM_ENGINE_PEER_ID).unwrap();
|
||||||
acl_mgr.add(default_acl).unwrap();
|
acl_mgr.add(default_acl).unwrap();
|
||||||
let dm = DataModel::new(&dev_det, dev_att, fabric_mgr, acl_mgr.clone(), pase_mgr).unwrap();
|
let dm = DataModel::new(
|
||||||
|
dev_det,
|
||||||
|
dev_att,
|
||||||
|
fabric_mgr.clone(),
|
||||||
|
acl_mgr.clone(),
|
||||||
|
pase_mgr,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut d = dm.node.write().unwrap();
|
let mut d = dm.node.write().unwrap();
|
||||||
|
|
|
@ -204,10 +204,10 @@ fn read_cluster_id_write_attr(im: &ImEngine, endpoint: u16) -> AttrValue {
|
||||||
let node = im.dm.node.read().unwrap();
|
let node = im.dm.node.read().unwrap();
|
||||||
let echo = node.get_cluster(endpoint, echo_cluster::ID).unwrap();
|
let echo = node.get_cluster(endpoint, echo_cluster::ID).unwrap();
|
||||||
|
|
||||||
*echo
|
echo.base()
|
||||||
.base()
|
|
||||||
.read_attribute_raw(echo_cluster::Attributes::AttWrite as u16)
|
.read_attribute_raw(echo_cluster::Attributes::AttWrite as u16)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_cluster_id_data_ver(im: &ImEngine, endpoint: u16) -> u32 {
|
fn read_cluster_id_data_ver(im: &ImEngine, endpoint: u16) -> u32 {
|
||||||
|
|
|
@ -238,6 +238,7 @@ fn test_read_wc_endpoint_wc_attribute() {
|
||||||
let attr_list_tlvs = get_tlvs(
|
let attr_list_tlvs = get_tlvs(
|
||||||
&mut buf,
|
&mut buf,
|
||||||
&[
|
&[
|
||||||
|
GlobalElements::FeatureMap as u16,
|
||||||
GlobalElements::AttributeList as u16,
|
GlobalElements::AttributeList as u16,
|
||||||
echo_cluster::Attributes::Att1 as u16,
|
echo_cluster::Attributes::Att1 as u16,
|
||||||
echo_cluster::Attributes::Att2 as u16,
|
echo_cluster::Attributes::Att2 as u16,
|
||||||
|
@ -247,6 +248,14 @@ fn test_read_wc_endpoint_wc_attribute() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let expected = &[
|
let expected = &[
|
||||||
|
attr_data!(
|
||||||
|
GenericPath::new(
|
||||||
|
Some(0),
|
||||||
|
Some(echo_cluster::ID),
|
||||||
|
Some(GlobalElements::FeatureMap as u32),
|
||||||
|
),
|
||||||
|
ElementType::U8(0)
|
||||||
|
),
|
||||||
attr_data!(
|
attr_data!(
|
||||||
GenericPath::new(
|
GenericPath::new(
|
||||||
Some(0),
|
Some(0),
|
||||||
|
@ -279,6 +288,14 @@ fn test_read_wc_endpoint_wc_attribute() {
|
||||||
),
|
),
|
||||||
ElementType::U32(echo_cluster::ATTR_CUSTOM_VALUE)
|
ElementType::U32(echo_cluster::ATTR_CUSTOM_VALUE)
|
||||||
),
|
),
|
||||||
|
attr_data!(
|
||||||
|
GenericPath::new(
|
||||||
|
Some(1),
|
||||||
|
Some(echo_cluster::ID),
|
||||||
|
Some(GlobalElements::FeatureMap as u32),
|
||||||
|
),
|
||||||
|
ElementType::U8(0)
|
||||||
|
),
|
||||||
attr_data!(
|
attr_data!(
|
||||||
GenericPath::new(
|
GenericPath::new(
|
||||||
Some(1),
|
Some(1),
|
||||||
|
|
Loading…
Add table
Reference in a new issue