From 068da6143c28c2235c35f03e68c6c8a6a47db532 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Tue, 20 Aug 2024 16:20:45 -0400 Subject: [PATCH] Add plumbing that allows fabric-bridge endpoints to report CADMIN attr (#35076) --- .../fabric-bridge-common/BUILD.gn | 2 + .../BridgedAdministratorCommissioning.h | 58 +++++++++++++ .../include/BridgedDevice.h | 12 +++ .../src/BridgedAdministratorCommissioning.cpp | 81 +++++++++++++++++++ examples/fabric-bridge-app/linux/main.cpp | 3 + 5 files changed, 156 insertions(+) create mode 100644 examples/fabric-bridge-app/fabric-bridge-common/include/BridgedAdministratorCommissioning.h create mode 100644 examples/fabric-bridge-app/fabric-bridge-common/src/BridgedAdministratorCommissioning.cpp diff --git a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn index 7f2fbcbbfe0556..157032f8f93c19 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn +++ b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn @@ -41,10 +41,12 @@ source_set("fabric-bridge-lib") { public_configs = [ ":config" ] sources = [ + "include/BridgedAdministratorCommissioning.h", "include/BridgedDevice.h", "include/BridgedDeviceBasicInformationImpl.h", "include/BridgedDeviceManager.h", "include/CHIPProjectAppConfig.h", + "src/BridgedAdministratorCommissioning.cpp", "src/BridgedDevice.cpp", "src/BridgedDeviceBasicInformationImpl.cpp", "src/BridgedDeviceManager.cpp", diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedAdministratorCommissioning.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedAdministratorCommissioning.h new file mode 100644 index 00000000000000..06fd9026d44225 --- /dev/null +++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedAdministratorCommissioning.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +/** + * @brief CADMIN cluster implementation for handling attribute interactions of bridged device endpoints. + * + * The current Administrator Commissioning Cluster server's zap generated code will automatically + * register an Attribute Access Interface for the root node endpoint implementation. In order to + * properly respond to a read attribute for bridged devices we are representing, we override the + * currently registered Attribute Interface such that we are first to receive any read attribute + * request on Administrator Commissioning Cluster, and if it is not an endpoint for a device we + * are a bridge for we redirect to the default cluster server implementation of Administrator + * Commissioning Cluster. + */ +class BridgedAdministratorCommissioning : public chip::app::AttributeAccessInterface +{ +public: + // Register for the AdministratorCommissioning cluster on all endpoints. + BridgedAdministratorCommissioning() : + AttributeAccessInterface(chip::NullOptional, chip::app::Clusters::AdministratorCommissioning::Id) + {} + + CHIP_ERROR Init(); + + CHIP_ERROR Read(const chip::app::ConcreteReadAttributePath & aPath, chip::app::AttributeValueEncoder & aEncoder) override; + + // We do not allow writing to CADMIN attributes of a bridged device endpoint. We simply redirect + // write requests to the original attribute interface. + CHIP_ERROR Write(const chip::app::ConcreteDataAttributePath & aPath, chip::app::AttributeValueDecoder & aDecoder) override + { + VerifyOrDie(mOriginalAttributeInterface); + return mOriginalAttributeInterface->Write(aPath, aDecoder); + } + +private: + // If mOriginalAttributeInterface is removed from here, the class description needs to be updated + // to reflect this change. + chip::app::AttributeAccessInterface * mOriginalAttributeInterface = nullptr; +}; diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h index 3dab8d3b16b2d6..7081278f4dc0f3 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h +++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h @@ -18,6 +18,7 @@ #pragma once +#include #include #include @@ -40,6 +41,14 @@ class BridgedDevice std::string softwareVersionString; }; + struct AdminCommissioningAttributes + { + chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum commissioningWindowStatus = + chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum::kWindowNotOpen; + std::optional openerFabricIndex = std::nullopt; + std::optional openerVendorId = std::nullopt; + }; + BridgedDevice(chip::NodeId nodeId); virtual ~BridgedDevice() = default; @@ -59,6 +68,8 @@ class BridgedDevice [[nodiscard]] const BridgedAttributes & GetBridgedAttributes() const { return mAttributes; } void SetBridgedAttributes(const BridgedAttributes & value) { mAttributes = value; } + // TODO(#35077): Need to allow mAdminCommissioningAttributes to be set from fabric-admin. + const AdminCommissioningAttributes & GetAdminCommissioningAttributes() const { return mAdminCommissioningAttributes; } /// Convenience method to set just the unique id of a bridged device as it /// is one of the few attributes that is not always bulk-set @@ -73,4 +84,5 @@ class BridgedDevice chip::EndpointId mParentEndpointId = 0; BridgedAttributes mAttributes; + AdminCommissioningAttributes mAdminCommissioningAttributes; }; diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedAdministratorCommissioning.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedAdministratorCommissioning.cpp new file mode 100644 index 00000000000000..c7bca223d92382 --- /dev/null +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedAdministratorCommissioning.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BridgedAdministratorCommissioning.h" + +#include "BridgedDevice.h" +#include "BridgedDeviceManager.h" +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::AdministratorCommissioning; + +CHIP_ERROR BridgedAdministratorCommissioning::Init() +{ + // We expect initialization after all embr plugin clusters initialization. This allows us to unregister + // the existing AccessAttributeInterface for AdministratorCommissioning and register ourselves, ensuring + // we get the callback for reading attribute. If the read is not intended for a bridged device we will + // forward it to the original attribute interface that we are unregistering. + mOriginalAttributeInterface = AttributeAccessInterfaceRegistry::Instance().Get(kRootEndpointId, AdministratorCommissioning::Id); + VerifyOrReturnError(mOriginalAttributeInterface, CHIP_ERROR_INTERNAL); + AttributeAccessInterfaceRegistry::Instance().Unregister(mOriginalAttributeInterface); + VerifyOrDie(AttributeAccessInterfaceRegistry::Instance().Register(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR BridgedAdministratorCommissioning::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + VerifyOrDie(aPath.mClusterId == Clusters::AdministratorCommissioning::Id); + EndpointId endpointId = aPath.mEndpointId; + BridgedDevice * device = BridgeDeviceMgr().GetDevice(endpointId); + + if (!device) + { + VerifyOrDie(mOriginalAttributeInterface); + return mOriginalAttributeInterface->Read(aPath, aEncoder); + } + auto attr = device->GetAdminCommissioningAttributes(); + + switch (aPath.mAttributeId) + { + case Attributes::WindowStatus::Id: { + return aEncoder.Encode(attr.commissioningWindowStatus); + } + case Attributes::AdminFabricIndex::Id: { + DataModel::Nullable encodeableFabricIndex = DataModel::NullNullable; + if (attr.openerFabricIndex.has_value()) + { + encodeableFabricIndex.SetNonNull(attr.openerFabricIndex.value()); + } + return aEncoder.Encode(encodeableFabricIndex); + } + case Attributes::AdminVendorId::Id: { + DataModel::Nullable encodeableVendorId = DataModel::NullNullable; + if (attr.openerVendorId.has_value()) + { + encodeableVendorId.SetNonNull(attr.openerVendorId.value()); + } + return aEncoder.Encode(encodeableVendorId); + } + default: + break; + } + + return CHIP_NO_ERROR; +} diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp index 3b6502421045f8..eeb290210caa6b 100644 --- a/examples/fabric-bridge-app/linux/main.cpp +++ b/examples/fabric-bridge-app/linux/main.cpp @@ -18,6 +18,7 @@ #include +#include "BridgedAdministratorCommissioning.h" #include "BridgedDevice.h" #include "BridgedDeviceBasicInformationImpl.h" #include "BridgedDeviceManager.h" @@ -234,6 +235,7 @@ void BridgedDeviceInformationCommandHandler::InvokeCommand(HandlerContext & hand handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, status); } +BridgedAdministratorCommissioning gBridgedAdministratorCommissioning; AdministratorCommissioningCommandHandler gAdministratorCommissioningCommandHandler; BridgedDeviceInformationCommandHandler gBridgedDeviceInformationCommandHandler; @@ -258,6 +260,7 @@ void ApplicationInit() pollingThread.detach(); BridgeDeviceMgr().Init(); + VerifyOrDie(gBridgedAdministratorCommissioning.Init() == CHIP_NO_ERROR); VerifyOrDieWithMsg(CommissionerControlInit() == CHIP_NO_ERROR, NotSpecified, "Failed to initialize Commissioner Control Server");