Merge branch 'feature/multi-admin' into mdns-disco-multi-admin

This commit is contained in:
Marcel 2023-01-14 15:59:10 +01:00
commit 5499e6ccdc
15 changed files with 157 additions and 35 deletions

View file

@ -35,11 +35,12 @@ fn main() {
pid: 0x8002,
hw_ver: 2,
sw_ver: 1,
serial_no: "aabbccdd".to_string(),
device_name: "OnOff Light".to_string(),
};
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 mut node = dm.node.write().unwrap();

View file

@ -54,7 +54,7 @@ impl Matter {
/// 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.
pub fn new(
dev_det: &BasicInfoConfig,
dev_det: BasicInfoConfig,
dev_att: Box<dyn DevAttDataFetcher>,
dev_comm: CommissioningData,
) -> Result<Box<Matter>, Error> {

View file

@ -17,13 +17,18 @@
use super::objects::*;
use crate::error::*;
use num_derive::FromPrimitive;
pub const ID: u32 = 0x0028;
#[derive(FromPrimitive)]
enum Attributes {
DMRevision = 0,
VendorId = 2,
ProductId = 4,
HwVer = 7,
SwVer = 9,
SerialNo = 0x0f,
}
#[derive(Default)]
@ -32,6 +37,16 @@ pub struct BasicInfoConfig {
pub pid: u16,
pub hw_ver: u16,
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
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 {
base: Cluster,
}
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 {
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_pid_new(cfg.pid)?)?;
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_serial_no_new(cfg.serial_no)?)?;
Ok(cluster)
}
}

View file

@ -51,7 +51,7 @@ pub struct DataModel {
impl DataModel {
pub fn new(
dev_details: &BasicInfoConfig,
dev_details: BasicInfoConfig,
dev_att: Box<dyn DevAttDataFetcher>,
fabric_mgr: Arc<FabricMgr>,
acl_mgr: Arc<AclMgr>,
@ -84,7 +84,7 @@ impl DataModel {
) -> Result<AttrValue, IMStatusCode> {
let node = self.node.read().unwrap();
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

View file

@ -32,18 +32,23 @@ use crate::secure_channel::pake::PaseMgr;
use std::sync::Arc;
use std::sync::RwLockWriteGuard;
pub const DEV_TYPE_ROOT_NODE: DeviceType = DeviceType {
dtype: 0x0016,
drev: 1,
};
type WriteNode<'a> = RwLockWriteGuard<'a, Box<Node>>;
pub fn device_type_add_root_node(
node: &mut WriteNode,
dev_info: &BasicInfoConfig,
dev_info: BasicInfoConfig,
dev_att: Box<dyn DevAttDataFetcher>,
fabric_mgr: Arc<FabricMgr>,
acl_mgr: Arc<AclMgr>,
pase_mgr: PaseMgr,
) -> Result<u32, Error> {
// Add the root endpoint
let endpoint = node.add_endpoint()?;
let endpoint = node.add_endpoint(DEV_TYPE_ROOT_NODE)?;
if endpoint != 0 {
// Somehow endpoint 0 was already added, this shouldn't be the case
return Err(Error::Invalid);
@ -63,8 +68,13 @@ pub fn device_type_add_root_node(
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> {
let endpoint = node.add_endpoint()?;
let endpoint = node.add_endpoint(DEV_TYPE_ON_OFF_LIGHT)?;
node.add_cluster(endpoint, OnOffCluster::new()?)?;
Ok(endpoint)
}

View file

@ -88,7 +88,7 @@ bitflags! {
* - 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 {
Int64(i64),
Uint8(u8),
@ -96,6 +96,7 @@ pub enum AttrValue {
Uint32(u32),
Uint64(u64),
Bool(bool),
Utf8(String),
Custom,
}
@ -108,6 +109,7 @@ impl Debug for AttrValue {
AttrValue::Uint32(v) => write!(f, "{:?}", *v),
AttrValue::Uint64(v) => write!(f, "{:?}", *v),
AttrValue::Bool(v) => write!(f, "{:?}", *v),
AttrValue::Utf8(v) => write!(f, "{:?}", *v),
AttrValue::Custom => write!(f, "custom-attribute"),
}?;
Ok(())
@ -123,6 +125,7 @@ impl ToTLV for AttrValue {
AttrValue::Uint16(v) => tw.u16(tag_type, *v),
AttrValue::Uint32(v) => tw.u32(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");
Err(Error::AttributeNotFound)

View file

@ -87,7 +87,6 @@ pub trait ClusterType {
pub struct Cluster {
pub(super) id: u32,
attributes: Vec<Attribute>,
feature_map: Option<u32>,
data_ver: u32,
}
@ -96,7 +95,6 @@ impl Cluster {
let mut c = Cluster {
id,
attributes: Vec::with_capacity(ATTRS_PER_CLUSTER),
feature_map: None,
data_ver: rand::thread_rng().gen_range(0..0xFFFFFFFF),
};
c.add_default_attributes()?;
@ -112,22 +110,20 @@ impl Cluster {
}
pub fn set_feature_map(&mut self, map: u32) -> Result<(), Error> {
if self.feature_map.is_none() {
self.add_attribute(Attribute::new(
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);
self.write_attribute_raw(GlobalElements::FeatureMap as u16, AttrValue::Uint32(map))
.map_err(|_| Error::Invalid)?;
Ok(())
}
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(
GlobalElements::AttributeList as u16,
AttrValue::Custom,
@ -233,8 +229,7 @@ impl Cluster {
return;
}
GlobalElements::FeatureMap => {
let val = if let Some(m) = self.feature_map { m } else { 0 };
encoder.encode(EncodeValue::Value(&val));
encoder.encode(EncodeValue::Value(&attr.value));
return;
}
_ => {
@ -284,7 +279,7 @@ impl Cluster {
) -> Result<(), IMStatusCode> {
let a = self.get_attribute_mut(attr_id)?;
if a.value != AttrValue::Custom {
let mut value = a.value;
let mut value = a.value.clone();
value
.update_from_tlv(data)
.map_err(|_| IMStatusCode::Failure)?;

View file

@ -115,3 +115,9 @@ pub trait Encoder {
/// Encode a status report
fn encode_status(&mut self, status: IMStatusCode, cluster_status: u16);
}
#[derive(ToTLV, Copy, Clone)]
pub struct DeviceType {
pub dtype: u16,
pub drev: u16,
}

View file

@ -19,17 +19,21 @@ use crate::{data_model::objects::ClusterType, error::*, interaction_model::core:
use std::fmt;
use super::DeviceType;
pub const CLUSTERS_PER_ENDPT: usize = 9;
pub struct Endpoint {
dev_type: DeviceType,
clusters: Vec<Box<dyn ClusterType>>,
}
pub type BoxedClusters = [Box<dyn ClusterType>];
impl Endpoint {
pub fn new() -> Result<Box<Endpoint>, Error> {
pub fn new(dev_type: DeviceType) -> Result<Box<Endpoint>, Error> {
Ok(Box::new(Endpoint {
dev_type,
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> {
self.clusters.iter().position(|c| c.base().id == cluster_id)
}

View file

@ -23,6 +23,8 @@ use crate::{
};
use std::fmt;
use super::DeviceType;
pub trait ChangeConsumer {
fn endpoint_added(&self, id: u16, endpoint: &mut Endpoint) -> Result<(), Error>;
}
@ -59,13 +61,13 @@ impl Node {
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
.endpoints
.iter()
.position(|x| x.is_none())
.ok_or(Error::NoSpace)?;
let mut endpoint = Endpoint::new()?;
let mut endpoint = Endpoint::new(dev_type)?;
if let Some(cb) = &self.changes_cb {
cb.endpoint_added(index as u16, &mut endpoint)?;
}

View file

@ -21,7 +21,7 @@ use crate::data_model::core::DataModel;
use crate::data_model::objects::*;
use crate::error::*;
use crate::interaction_model::messages::GenericPath;
use crate::tlv::{TLVWriter, TagType};
use crate::tlv::{TLVWriter, TagType, ToTLV};
use log::error;
pub const ID: u32 = 0x001D;
@ -48,11 +48,28 @@ impl DescriptorCluster {
data_model,
base: Cluster::new(ID)?,
});
c.base.add_attribute(attr_devtypelist_new()?)?;
c.base.add_attribute(attr_serverlist_new()?)?;
c.base.add_attribute(attr_partslist_new()?)?;
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) {
let path = GenericPath {
endpoint: Some(self.endpoint_id),
@ -69,8 +86,24 @@ impl DescriptorCluster {
}
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);
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();
}
}
@ -85,6 +118,9 @@ impl ClusterType for DescriptorCluster {
fn read_custom_attribute(&self, encoder: &mut dyn Encoder, attr: &AttrDetails) {
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| {
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> {
Attribute::new(
Attributes::ServerList as u16,

View file

@ -50,12 +50,13 @@
//! pid: 0xFFF1,
//! hw_ver: 2,
//! sw_ver: 1,
//! serial_no: "aabbcc".to_string(),
//! device_name: "OnOff Light".to_string(),
//! };
//!
//! /// Get the Matter Object
//! /// 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 mut node = dm.node.write().unwrap();

View file

@ -94,6 +94,7 @@ impl ImEngine {
pid: 11,
hw_ver: 12,
sw_ver: 13,
serial_no: "aabbccdd".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
default_acl.add_subject(IM_ENGINE_PEER_ID).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();

View file

@ -204,10 +204,10 @@ fn read_cluster_id_write_attr(im: &ImEngine, endpoint: u16) -> AttrValue {
let node = im.dm.node.read().unwrap();
let echo = node.get_cluster(endpoint, echo_cluster::ID).unwrap();
*echo
.base()
echo.base()
.read_attribute_raw(echo_cluster::Attributes::AttWrite as u16)
.unwrap()
.clone()
}
fn read_cluster_id_data_ver(im: &ImEngine, endpoint: u16) -> u32 {

View file

@ -238,6 +238,7 @@ fn test_read_wc_endpoint_wc_attribute() {
let attr_list_tlvs = get_tlvs(
&mut buf,
&[
GlobalElements::FeatureMap as u16,
GlobalElements::AttributeList as u16,
echo_cluster::Attributes::Att1 as u16,
echo_cluster::Attributes::Att2 as u16,
@ -247,6 +248,14 @@ fn test_read_wc_endpoint_wc_attribute() {
);
let expected = &[
attr_data!(
GenericPath::new(
Some(0),
Some(echo_cluster::ID),
Some(GlobalElements::FeatureMap as u32),
),
ElementType::U8(0)
),
attr_data!(
GenericPath::new(
Some(0),
@ -279,6 +288,14 @@ fn test_read_wc_endpoint_wc_attribute() {
),
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!(
GenericPath::new(
Some(1),