Skip to content

Commit

Permalink
Add plumbing that allows fabric-bridge endpoints to report CADMIN attr (
Browse files Browse the repository at this point in the history
  • Loading branch information
tehampson authored and PeterC1965 committed Aug 28, 2024
1 parent 2e3bc4e commit 8c6ea99
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 0 deletions.
2 changes: 2 additions & 0 deletions examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <app-common/zap-generated/cluster-objects.h>
#include <app/AttributeAccessInterfaceRegistry.h>

/**
* @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;
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#pragma once

#include <app-common/zap-generated/cluster-objects.h>
#include <app/util/attribute-storage.h>

#include <string>
Expand All @@ -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<chip::FabricIndex> openerFabricIndex = std::nullopt;
std::optional<chip::VendorId> openerVendorId = std::nullopt;
};

BridgedDevice(chip::NodeId nodeId);
virtual ~BridgedDevice() = default;

Expand All @@ -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
Expand All @@ -73,4 +84,5 @@ class BridgedDevice
chip::EndpointId mParentEndpointId = 0;

BridgedAttributes mAttributes;
AdminCommissioningAttributes mAdminCommissioningAttributes;
};
Original file line number Diff line number Diff line change
@@ -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 <app/AttributeAccessInterfaceRegistry.h>

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<FabricIndex> encodeableFabricIndex = DataModel::NullNullable;
if (attr.openerFabricIndex.has_value())
{
encodeableFabricIndex.SetNonNull(attr.openerFabricIndex.value());
}
return aEncoder.Encode(encodeableFabricIndex);
}
case Attributes::AdminVendorId::Id: {
DataModel::Nullable<VendorId> encodeableVendorId = DataModel::NullNullable;
if (attr.openerVendorId.has_value())
{
encodeableVendorId.SetNonNull(attr.openerVendorId.value());
}
return aEncoder.Encode(encodeableVendorId);
}
default:
break;
}

return CHIP_NO_ERROR;
}
3 changes: 3 additions & 0 deletions examples/fabric-bridge-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <AppMain.h>

#include "BridgedAdministratorCommissioning.h"
#include "BridgedDevice.h"
#include "BridgedDeviceBasicInformationImpl.h"
#include "BridgedDeviceManager.h"
Expand Down Expand Up @@ -234,6 +235,7 @@ void BridgedDeviceInformationCommandHandler::InvokeCommand(HandlerContext & hand
handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, status);
}

BridgedAdministratorCommissioning gBridgedAdministratorCommissioning;
AdministratorCommissioningCommandHandler gAdministratorCommissioningCommandHandler;
BridgedDeviceInformationCommandHandler gBridgedDeviceInformationCommandHandler;

Expand All @@ -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");
Expand Down

0 comments on commit 8c6ea99

Please sign in to comment.