diff --git a/examples/onoff_light/src/main.rs b/examples/onoff_light/src/main.rs index 053370a..de2e199 100644 --- a/examples/onoff_light/src/main.rs +++ b/examples/onoff_light/src/main.rs @@ -72,6 +72,8 @@ fn run() -> Result<(), Error> { sw_ver_str: "1", serial_no: "aabbccdd", device_name: "OnOff Light", + product_name: "Light123", + vendor_name: "Vendor PQR", }; let (ipv4_addr, ipv6_addr, interface) = initialize_network()?; diff --git a/rs-matter/src/data_model/cluster_basic_information.rs b/rs-matter/src/data_model/cluster_basic_information.rs index dcc7028..ee6279f 100644 --- a/rs-matter/src/data_model/cluster_basic_information.rs +++ b/rs-matter/src/data_model/cluster_basic_information.rs @@ -15,10 +15,15 @@ * limitations under the License. */ -use core::convert::TryInto; +use core::{cell::RefCell, convert::TryInto}; use super::objects::*; -use crate::{attribute_enum, error::Error, utils::rand::Rand}; +use crate::{ + attribute_enum, + error::{Error, ErrorCode}, + utils::rand::Rand, +}; +use heapless::String; use strum::FromRepr; pub const ID: u32 = 0x0028; @@ -27,8 +32,11 @@ pub const ID: u32 = 0x0028; #[repr(u16)] pub enum Attributes { DMRevision(AttrType) = 0, + VendorName(AttrUtfType) = 1, VendorId(AttrType) = 2, + ProductName(AttrUtfType) = 3, ProductId(AttrType) = 4, + NodeLabel(AttrUtfType) = 5, HwVer(AttrType) = 7, SwVer(AttrType) = 9, SwVerString(AttrUtfType) = 0xa, @@ -39,8 +47,11 @@ attribute_enum!(Attributes); pub enum AttributesDiscriminants { DMRevision = 0, + VendorName = 1, VendorId = 2, + ProductName = 3, ProductId = 4, + NodeLabel = 5, HwVer = 7, SwVer = 9, SwVerString = 0xa, @@ -57,6 +68,8 @@ pub struct BasicInfoConfig<'a> { pub serial_no: &'a str, /// Device name; up to 32 characters pub device_name: &'a str, + pub vendor_name: &'a str, + pub product_name: &'a str, } pub const CLUSTER: Cluster<'static> = Cluster { @@ -70,16 +83,31 @@ pub const CLUSTER: Cluster<'static> = Cluster { Access::RV, Quality::FIXED, ), + Attribute::new( + AttributesDiscriminants::VendorName as u16, + Access::RV, + Quality::FIXED, + ), Attribute::new( AttributesDiscriminants::VendorId as u16, Access::RV, Quality::FIXED, ), + Attribute::new( + AttributesDiscriminants::ProductName as u16, + Access::RV, + Quality::FIXED, + ), Attribute::new( AttributesDiscriminants::ProductId as u16, Access::RV, Quality::FIXED, ), + Attribute::new( + AttributesDiscriminants::NodeLabel as u16, + Access::RWVM, + Quality::N, + ), Attribute::new( AttributesDiscriminants::HwVer as u16, Access::RV, @@ -107,13 +135,16 @@ pub const CLUSTER: Cluster<'static> = Cluster { pub struct BasicInfoCluster<'a> { data_ver: Dataver, cfg: &'a BasicInfoConfig<'a>, + node_label: RefCell>, // Max node-label as per the spec } impl<'a> BasicInfoCluster<'a> { pub fn new(cfg: &'a BasicInfoConfig<'a>, rand: Rand) -> Self { + let node_label = RefCell::new(String::from("")); Self { data_ver: Dataver::new(rand), cfg, + node_label, } } @@ -124,8 +155,13 @@ impl<'a> BasicInfoCluster<'a> { } else { match attr.attr_id.try_into()? { Attributes::DMRevision(codec) => codec.encode(writer, 1), + Attributes::VendorName(codec) => codec.encode(writer, self.cfg.vendor_name), Attributes::VendorId(codec) => codec.encode(writer, self.cfg.vid), + Attributes::ProductName(codec) => codec.encode(writer, self.cfg.product_name), Attributes::ProductId(codec) => codec.encode(writer, self.cfg.pid), + Attributes::NodeLabel(codec) => { + codec.encode(writer, self.node_label.borrow().as_str()) + } Attributes::HwVer(codec) => codec.encode(writer, self.cfg.hw_ver), Attributes::SwVer(codec) => codec.encode(writer, self.cfg.sw_ver), Attributes::SwVerString(codec) => codec.encode(writer, self.cfg.sw_ver_str), @@ -136,12 +172,35 @@ impl<'a> BasicInfoCluster<'a> { Ok(()) } } + + pub fn write(&self, attr: &AttrDetails, data: AttrData) -> Result<(), Error> { + let data = data.with_dataver(self.data_ver.get())?; + + match attr.attr_id.try_into()? { + Attributes::NodeLabel(codec) => { + *self.node_label.borrow_mut() = String::from( + codec + .decode(data) + .map_err(|_| Error::new(ErrorCode::InvalidAction))?, + ); + } + _ => return Err(Error::new(ErrorCode::InvalidAction)), + } + + self.data_ver.changed(); + + Ok(()) + } } impl<'a> Handler for BasicInfoCluster<'a> { fn read(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error> { BasicInfoCluster::read(self, attr, encoder) } + + fn write(&self, attr: &AttrDetails, data: AttrData) -> Result<(), Error> { + BasicInfoCluster::write(self, attr, data) + } } impl<'a> NonBlockingHandler for BasicInfoCluster<'a> {} diff --git a/rs-matter/tests/common/im_engine.rs b/rs-matter/tests/common/im_engine.rs index 16e98dc..02e7847 100644 --- a/rs-matter/tests/common/im_engine.rs +++ b/rs-matter/tests/common/im_engine.rs @@ -70,6 +70,8 @@ const BASIC_INFO: BasicInfoConfig<'static> = BasicInfoConfig { sw_ver_str: "13", serial_no: "aabbccdd", device_name: "Test Device", + product_name: "TestProd", + vendor_name: "TestVendor", }; struct DummyDevAtt; diff --git a/rs-matter/tests/data_model/long_reads.rs b/rs-matter/tests/data_model/long_reads.rs index 1235f96..333801c 100644 --- a/rs-matter/tests/data_model/long_reads.rs +++ b/rs-matter/tests/data_model/long_reads.rs @@ -69,18 +69,36 @@ fn wildcard_read_resp(part: u8) -> Vec> { basic_info::AttributesDiscriminants::DMRevision, dont_care.clone() ), + attr_data!( + 0, + 40, + basic_info::AttributesDiscriminants::VendorName, + dont_care.clone() + ), attr_data!( 0, 40, basic_info::AttributesDiscriminants::VendorId, dont_care.clone() ), + attr_data!( + 0, + 40, + basic_info::AttributesDiscriminants::ProductName, + dont_care.clone() + ), attr_data!( 0, 40, basic_info::AttributesDiscriminants::ProductId, dont_care.clone() ), + attr_data!( + 0, + 40, + basic_info::AttributesDiscriminants::NodeLabel, + dont_care.clone() + ), attr_data!( 0, 40, @@ -195,6 +213,9 @@ fn wildcard_read_resp(part: u8) -> Vec> { adm_comm::AttributesDiscriminants::AdminVendorId, dont_care.clone() ), + ]; + + let part2 = vec![ attr_data!(0, 62, GlobalElements::FeatureMap, dont_care.clone()), attr_data!(0, 62, GlobalElements::AttributeList, dont_care.clone()), attr_data!( @@ -203,9 +224,6 @@ fn wildcard_read_resp(part: u8) -> Vec> { noc::AttributesDiscriminants::CurrentFabricIndex, dont_care.clone() ), - ]; - - let part2 = vec![ attr_data!( 0, 62,