diff --git a/examples/common/pigweed/protos/fabric_bridge_service.proto b/examples/common/pigweed/protos/fabric_bridge_service.proto index 0de3b3fa243d77..1c699e6942b358 100644 --- a/examples/common/pigweed/protos/fabric_bridge_service.proto +++ b/examples/common/pigweed/protos/fabric_bridge_service.proto @@ -26,8 +26,16 @@ message KeepActiveChanged { uint32 promised_active_duration_ms = 2; } +message AdministratorCommissioningChanged { + uint64 node_id = 1; + uint32 window_status = 2; + optional uint32 opener_fabric_index = 3; + optional uint32 opener_vendor_id = 4; +} + service FabricBridge { rpc AddSynchronizedDevice(SynchronizedDevice) returns (pw.protobuf.Empty){} rpc RemoveSynchronizedDevice(SynchronizedDevice) returns (pw.protobuf.Empty){} rpc ActiveChanged(KeepActiveChanged) returns (pw.protobuf.Empty){} + rpc AdminCommissioningAttributeChanged(AdministratorCommissioningChanged) returns (pw.protobuf.Empty){} } diff --git a/examples/common/pigweed/rpc_services/FabricBridge.h b/examples/common/pigweed/rpc_services/FabricBridge.h index aab714223968df..9bd520278c13b4 100644 --- a/examples/common/pigweed/rpc_services/FabricBridge.h +++ b/examples/common/pigweed/rpc_services/FabricBridge.h @@ -48,6 +48,12 @@ class FabricBridge : public pw_rpc::nanopb::FabricBridge::Service { return pw::Status::Unimplemented(); } + + virtual pw::Status AdminCommissioningAttributeChanged(const chip_rpc_AdministratorCommissioningChanged & request, + pw_protobuf_Empty & response) + { + return pw::Status::Unimplemented(); + } }; } // namespace rpc diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp index f5672fc0bd8f85..29fc2b1ea9d73c 100644 --- a/examples/fabric-admin/rpc/RpcClient.cpp +++ b/examples/fabric-admin/rpc/RpcClient.cpp @@ -180,3 +180,20 @@ CHIP_ERROR ActiveChanged(chip::NodeId nodeId, uint32_t promisedActiveDurationMs) return WaitForResponse(call); } + +CHIP_ERROR AdminCommissioningAttributeChanged(const chip_rpc_AdministratorCommissioningChanged & data) +{ + ChipLogProgress(NotSpecified, "AdminCommissioningAttributeChanged"); + + // The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler + // function and the call will complete. + auto call = fabricBridgeClient.AdminCommissioningAttributeChanged(data, RpcCompletedWithEmptyResponse); + + if (!call.active()) + { + // The RPC call was not sent. This could occur due to, for example, an invalid channel ID. Handle if necessary. + return CHIP_ERROR_INTERNAL; + } + + return WaitForResponse(call); +} diff --git a/examples/fabric-admin/rpc/RpcClient.h b/examples/fabric-admin/rpc/RpcClient.h index 8edee9a3b256ed..6dd2b5b20bbd90 100644 --- a/examples/fabric-admin/rpc/RpcClient.h +++ b/examples/fabric-admin/rpc/RpcClient.h @@ -74,3 +74,14 @@ CHIP_ERROR RemoveSynchronizedDevice(chip::NodeId nodeId); * - CHIP_ERROR_INTERNAL: An internal error occurred while activating the RPC call. */ CHIP_ERROR ActiveChanged(chip::NodeId nodeId, uint32_t promisedActiveDurationMs); + +/** + * @brief CADMIN attribute has changed of one of the bridged devices that was previously added. + * + * @param data information regarding change in AdministratorCommissioning attributes + * @return CHIP_ERROR An error code indicating the success or failure of the operation. + * - CHIP_NO_ERROR: The RPC command was successfully processed. + * - CHIP_ERROR_BUSY: Another operation is currently in progress. + * - CHIP_ERROR_INTERNAL: An internal error occurred while activating the RPC call. + */ +CHIP_ERROR AdminCommissioningAttributeChanged(const chip_rpc_AdministratorCommissioningChanged & data); 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 7081278f4dc0f3..0de35ecbfa32e8 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h +++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h @@ -68,7 +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. + + void SetAdminCommissioningAttributes(const AdminCommissioningAttributes & aAdminCommissioningAttributes); const AdminCommissioningAttributes & GetAdminCommissioningAttributes() const { return mAdminCommissioningAttributes; } /// Convenience method to set just the unique id of a bridged device as it diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp index 21f19189afefe6..27364976d121f5 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp @@ -21,6 +21,7 @@ #include #include +#include #include namespace { @@ -31,6 +32,14 @@ struct ActiveChangeEventWorkData uint32_t mPromisedActiveDuration; }; +struct ReportAttributeChangedWorkData +{ + chip::EndpointId mEndpointId; + bool mWindowChanged = false; + bool mFabricIndexChanged = false; + bool mVendorChanged = false; +}; + void ActiveChangeEventWork(intptr_t arg) { ActiveChangeEventWorkData * data = reinterpret_cast(arg); @@ -47,6 +56,28 @@ void ActiveChangeEventWork(intptr_t arg) chip::Platform::Delete(data); } +void ReportAttributeChangedWork(intptr_t arg) +{ + ReportAttributeChangedWorkData * data = reinterpret_cast(arg); + + if (data->mWindowChanged) + { + MatterReportingAttributeChangeCallback(data->mEndpointId, chip::app::Clusters::AdministratorCommissioning::Id, + chip::app::Clusters::AdministratorCommissioning::Attributes::WindowStatus::Id); + } + if (data->mFabricIndexChanged) + { + MatterReportingAttributeChangeCallback(data->mEndpointId, chip::app::Clusters::AdministratorCommissioning::Id, + chip::app::Clusters::AdministratorCommissioning::Attributes::AdminFabricIndex::Id); + } + if (data->mVendorChanged) + { + MatterReportingAttributeChangeCallback(data->mEndpointId, chip::app::Clusters::AdministratorCommissioning::Id, + chip::app::Clusters::AdministratorCommissioning::Attributes::AdminVendorId::Id); + } + chip::Platform::Delete(data); +} + } // namespace using namespace chip::app::Clusters::Actions; @@ -80,3 +111,18 @@ void BridgedDevice::SetReachable(bool reachable) ChipLogProgress(NotSpecified, "BridgedDevice[%s]: OFFLINE", mAttributes.uniqueId.c_str()); } } + +void BridgedDevice::SetAdminCommissioningAttributes(const AdminCommissioningAttributes & aAdminCommissioningAttributes) +{ + ReportAttributeChangedWorkData * workdata = chip::Platform::New(); + + workdata->mEndpointId = mEndpointId; + workdata->mWindowChanged = + (aAdminCommissioningAttributes.commissioningWindowStatus != mAdminCommissioningAttributes.commissioningWindowStatus); + workdata->mFabricIndexChanged = + (aAdminCommissioningAttributes.openerFabricIndex != mAdminCommissioningAttributes.openerFabricIndex); + workdata->mVendorChanged = (aAdminCommissioningAttributes.openerVendorId != mAdminCommissioningAttributes.openerVendorId); + + mAdminCommissioningAttributes = aAdminCommissioningAttributes; + chip::DeviceLayer::PlatformMgr().ScheduleWork(ReportAttributeChangedWork, reinterpret_cast(workdata)); +} diff --git a/examples/fabric-bridge-app/linux/RpcServer.cpp b/examples/fabric-bridge-app/linux/RpcServer.cpp index bae007ed484935..bc8eed5c3dd9f0 100644 --- a/examples/fabric-bridge-app/linux/RpcServer.cpp +++ b/examples/fabric-bridge-app/linux/RpcServer.cpp @@ -46,6 +46,8 @@ class FabricBridge final : public chip::rpc::FabricBridge pw::Status AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) override; pw::Status RemoveSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) override; pw::Status ActiveChanged(const chip_rpc_KeepActiveChanged & request, pw_protobuf_Empty & response) override; + pw::Status AdminCommissioningAttributeChanged(const chip_rpc_AdministratorCommissioningChanged & request, + pw_protobuf_Empty & response) override; }; pw::Status FabricBridge::AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) @@ -160,6 +162,44 @@ pw::Status FabricBridge::ActiveChanged(const chip_rpc_KeepActiveChanged & reques return pw::OkStatus(); } +pw::Status FabricBridge::AdminCommissioningAttributeChanged(const chip_rpc_AdministratorCommissioningChanged & request, + pw_protobuf_Empty & response) +{ + NodeId nodeId = request.node_id; + ChipLogProgress(NotSpecified, "Received CADMIN attribut change: " ChipLogFormatX64, ChipLogValueX64(nodeId)); + + auto * device = BridgeDeviceMgr().GetDeviceByNodeId(nodeId); + if (device == nullptr) + { + ChipLogError(NotSpecified, "Could not find bridged device associated with nodeId=0x" ChipLogFormatX64, + ChipLogValueX64(nodeId)); + return pw::Status::NotFound(); + } + + BridgedDevice::AdminCommissioningAttributes adminCommissioningAttributes; + + uint32_t max_window_status_value = + static_cast(chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum::kUnknownEnumValue); + VerifyOrReturnValue(request.window_status < max_window_status_value, pw::Status::InvalidArgument()); + adminCommissioningAttributes.commissioningWindowStatus = + static_cast(request.window_status); + if (request.has_opener_fabric_index) + { + VerifyOrReturnValue(request.opener_fabric_index >= chip::kMinValidFabricIndex, pw::Status::InvalidArgument()); + VerifyOrReturnValue(request.opener_fabric_index <= chip::kMaxValidFabricIndex, pw::Status::InvalidArgument()); + adminCommissioningAttributes.openerFabricIndex = static_cast(request.opener_fabric_index); + } + + if (request.has_opener_vendor_id) + { + VerifyOrReturnValue(request.opener_vendor_id != chip::VendorId::NotSpecified, pw::Status::InvalidArgument()); + adminCommissioningAttributes.openerVendorId = static_cast(request.opener_vendor_id); + } + + device->SetAdminCommissioningAttributes(adminCommissioningAttributes); + return pw::OkStatus(); +} + FabricBridge fabric_bridge_service; #endif // defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE