diff --git a/rs-matter/src/data_model/objects/attribute.rs b/rs-matter/src/data_model/objects/attribute.rs index b31c1be..25e08e2 100644 --- a/rs-matter/src/data_model/objects/attribute.rs +++ b/rs-matter/src/data_model/objects/attribute.rs @@ -40,9 +40,12 @@ bitflags! { const READ_PRIVILEGE_MASK = Self::NEED_VIEW.bits | Self::NEED_MANAGE.bits | Self::NEED_OPERATE.bits | Self::NEED_ADMIN.bits; const WRITE_PRIVILEGE_MASK = Self::NEED_MANAGE.bits | Self::NEED_OPERATE.bits | Self::NEED_ADMIN.bits; const RV = Self::READ.bits | Self::NEED_VIEW.bits; + const RF = Self::READ.bits | Self::FAB_SCOPED.bits; + const RA = Self::READ.bits | Self::NEED_ADMIN.bits; const RWVA = Self::READ.bits | Self::WRITE.bits | Self::NEED_VIEW.bits | Self::NEED_ADMIN.bits; const RWFA = Self::READ.bits | Self::WRITE.bits | Self::FAB_SCOPED.bits | Self::NEED_ADMIN.bits; const RWVM = Self::READ.bits | Self::WRITE.bits | Self::NEED_VIEW.bits | Self::NEED_MANAGE.bits; + const RWFVM = Self::READ.bits | Self::WRITE.bits | Self::FAB_SCOPED.bits |Self::NEED_VIEW.bits | Self::NEED_MANAGE.bits; } } @@ -79,6 +82,10 @@ bitflags! { const NULLABLE = 0x08; // Short: X const SN = Self::SCENE.bits | Self::PERSISTENT.bits; + const S = Self::SCENE.bits; + const N = Self::PERSISTENT.bits; + const F = Self::FIXED.bits; + const X = Self::NULLABLE.bits; } } diff --git a/rs-matter/src/data_model/sdm/nw_commissioning.rs b/rs-matter/src/data_model/sdm/nw_commissioning.rs index 5abf809..1ee0a45 100644 --- a/rs-matter/src/data_model/sdm/nw_commissioning.rs +++ b/rs-matter/src/data_model/sdm/nw_commissioning.rs @@ -15,17 +15,35 @@ * limitations under the License. */ +use strum::FromRepr; + use crate::{ + attribute_enum, data_model::objects::{ - AttrDataEncoder, AttrDetails, ChangeNotifier, Cluster, Dataver, Handler, - NonBlockingHandler, ATTRIBUTE_LIST, FEATURE_MAP, + Access, AttrDataEncoder, AttrDataWriter, AttrDetails, AttrType, Attribute, ChangeNotifier, + Cluster, Dataver, Handler, NonBlockingHandler, Quality, ATTRIBUTE_LIST, FEATURE_MAP, }, - error::{Error, ErrorCode}, + error::Error, + tlv::{OctetStr, TLVWriter, TagType, ToTLV}, utils::rand::Rand, }; pub const ID: u32 = 0x0031; +#[derive(FromRepr)] +#[repr(u16)] +pub enum Attributes { + MaxNetworks = 0x00, + Networks = 0x01, + ConnectMaxTimeSecs = 0x03, + InterfaceEnabled = 0x04, + LastNetworkingStatus = 0x05, + LastNetworkID = 0x06, + LastConnectErrorValue = 0x07, +} + +attribute_enum!(Attributes); + enum FeatureMap { _Wifi = 0x01, _Thread = 0x02, @@ -35,7 +53,33 @@ enum FeatureMap { pub const CLUSTER: Cluster<'static> = Cluster { id: ID as _, feature_map: FeatureMap::Ethernet as _, - attributes: &[FEATURE_MAP, ATTRIBUTE_LIST], + attributes: &[ + FEATURE_MAP, + ATTRIBUTE_LIST, + Attribute::new(Attributes::MaxNetworks as u16, Access::RA, Quality::F), + Attribute::new(Attributes::Networks as u16, Access::RA, Quality::NONE), + Attribute::new( + Attributes::ConnectMaxTimeSecs as u16, + Access::RV, + Quality::F, + ), + Attribute::new( + Attributes::InterfaceEnabled as u16, + Access::RWVA, + Quality::N, + ), + Attribute::new( + Attributes::LastNetworkingStatus as u16, + Access::RA, + Quality::X, + ), + Attribute::new(Attributes::LastNetworkID as u16, Access::RA, Quality::X), + Attribute::new( + Attributes::LastConnectErrorValue as u16, + Access::RA, + Quality::X, + ), + ], commands: &[], }; @@ -49,15 +93,90 @@ impl NwCommCluster { data_ver: Dataver::new(rand), } } + + fn get_network_info(&self) -> NwMetaInfo<'static> { + // Only single, Ethernet, supported for now + let nw_info = NwInfo { + network_id: OctetStr::new(b"en0"), + connected: true, + }; + NwMetaInfo { + nw_info, + connect_max_time_secs: 60, + interface_enabled: true, + last_nw_status: NetworkCommissioningStatus::Success, + } + } +} + +#[derive(ToTLV)] +struct NwInfo<'a> { + network_id: OctetStr<'a>, + connected: bool, +} + +struct NwMetaInfo<'a> { + nw_info: NwInfo<'a>, + connect_max_time_secs: u8, + interface_enabled: bool, + last_nw_status: NetworkCommissioningStatus, +} + +#[allow(dead_code)] +enum NetworkCommissioningStatus { + Success = 0, + OutOfRange = 1, + BoundsExceeded = 2, + NetworkIDNotFound = 3, + DuplicateNetworkID = 4, + NetworkNotFound = 5, + RegulatoryError = 6, + AuthFailure = 7, + UnsupportedSecurity = 8, + OtherConnectionFailure = 9, + IPV6Failed = 10, + IPBindFailed = 11, + UnknownError = 12, } impl Handler for NwCommCluster { fn read(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error> { - if let Some(writer) = encoder.with_dataver(self.data_ver.get())? { + let info = self.get_network_info(); + if let Some(mut writer) = encoder.with_dataver(self.data_ver.get())? { if attr.is_system() { CLUSTER.read(attr.attr_id, writer) } else { - Err(ErrorCode::AttributeNotFound.into()) + match attr.attr_id.try_into()? { + Attributes::MaxNetworks => AttrType::::new().encode(writer, 1), + Attributes::Networks => { + writer.start_array(AttrDataWriter::TAG)?; + info.nw_info.to_tlv(&mut writer, TagType::Anonymous)?; + writer.end_container()?; + writer.complete() + } + Attributes::ConnectMaxTimeSecs => { + AttrType::::new().encode(writer, info.connect_max_time_secs) + } + + Attributes::InterfaceEnabled => { + AttrType::::new().encode(writer, info.interface_enabled) + } + + Attributes::LastNetworkingStatus => { + AttrType::::new().encode(writer, info.last_nw_status as u8) + } + + Attributes::LastNetworkID => { + info.nw_info + .network_id + .to_tlv(&mut writer, AttrDataWriter::TAG)?; + writer.complete() + } + Attributes::LastConnectErrorValue => { + writer.null(AttrDataWriter::TAG)?; + writer.complete() + } + } } } else { Ok(())