From 2d1ebf31a95d57511cc478f32f0eabad911d5398 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Fri, 13 Sep 2024 11:34:59 +0530 Subject: [PATCH 01/15] Regenerate zap for actions cluster --- .../all-clusters-app.matter | 17 ++- .../all-clusters-common/all-clusters-app.zap | 104 +++++++++++++++++- src/app/common/templates/config-data.yaml | 1 + .../app-common/zap-generated/callback.h | 72 ------------ 4 files changed, 117 insertions(+), 77 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index be6f4c0622c94a..71596e79a4a5c5 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -8144,9 +8144,22 @@ endpoint 1 { server cluster Actions { callback attribute actionList; callback attribute endpointLists; - callback attribute setupURL; + ram attribute setupURL default = "https://example.com"; ram attribute featureMap default = 0; - callback attribute clusterRevision default = 1; + ram attribute clusterRevision default = 1; + + handle command InstantAction; + handle command InstantActionWithTransition; + handle command StartAction; + handle command StartActionWithDuration; + handle command StopAction; + handle command PauseAction; + handle command PauseActionWithDuration; + handle command ResumeAction; + handle command EnableAction; + handle command EnableActionWithDuration; + handle command DisableAction; + handle command DisableActionWithDuration; } server cluster PowerSource { diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index c3586287ea4285..5d5d5e2cbfc382 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -7061,6 +7061,104 @@ "define": "ACTIONS_CLUSTER", "side": "server", "enabled": 1, + "commands": [ + { + "name": "InstantAction", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "InstantActionWithTransition", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StartAction", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StartActionWithDuration", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StopAction", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "PauseAction", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "PauseActionWithDuration", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ResumeAction", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "EnableAction", + "code": 8, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "EnableActionWithDuration", + "code": 9, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "DisableAction", + "code": 10, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "DisableActionWithDuration", + "code": 11, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], "attributes": [ { "name": "ActionList", @@ -7101,10 +7199,10 @@ "side": "server", "type": "long_char_string", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "https://example.com", "reportable": 1, "minInterval": 0, "maxInterval": 65344, @@ -7133,7 +7231,7 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, "defaultValue": "1", diff --git a/src/app/common/templates/config-data.yaml b/src/app/common/templates/config-data.yaml index 38f826c9ee6783..eabe9206385894 100644 --- a/src/app/common/templates/config-data.yaml +++ b/src/app/common/templates/config-data.yaml @@ -53,6 +53,7 @@ CommandHandlerInterfaceOnlyClusters: - General Diagnostics - Software Diagnostics - Wi-Fi Network Diagnostics + - Actions # We need a more configurable way of deciding which clusters have which init functions.... # See https://github.com/project-chip/connectedhomeip/issues/4369 diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index 480a2c3434c028..223aa5e483ce6b 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -5850,78 +5850,6 @@ bool emberAfLevelControlClusterMoveToClosestFrequencyCallback( bool emberAfAccessControlClusterReviewFabricRestrictionsCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::AccessControl::Commands::ReviewFabricRestrictions::DecodableType & commandData); -/** - * @brief Actions Cluster InstantAction Command callback (from client) - */ -bool emberAfActionsClusterInstantActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::InstantAction::DecodableType & commandData); -/** - * @brief Actions Cluster InstantActionWithTransition Command callback (from client) - */ -bool emberAfActionsClusterInstantActionWithTransitionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::InstantActionWithTransition::DecodableType & commandData); -/** - * @brief Actions Cluster StartAction Command callback (from client) - */ -bool emberAfActionsClusterStartActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::StartAction::DecodableType & commandData); -/** - * @brief Actions Cluster StartActionWithDuration Command callback (from client) - */ -bool emberAfActionsClusterStartActionWithDurationCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::StartActionWithDuration::DecodableType & commandData); -/** - * @brief Actions Cluster StopAction Command callback (from client) - */ -bool emberAfActionsClusterStopActionCallback(chip::app::CommandHandler * commandObj, - const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::StopAction::DecodableType & commandData); -/** - * @brief Actions Cluster PauseAction Command callback (from client) - */ -bool emberAfActionsClusterPauseActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::PauseAction::DecodableType & commandData); -/** - * @brief Actions Cluster PauseActionWithDuration Command callback (from client) - */ -bool emberAfActionsClusterPauseActionWithDurationCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::PauseActionWithDuration::DecodableType & commandData); -/** - * @brief Actions Cluster ResumeAction Command callback (from client) - */ -bool emberAfActionsClusterResumeActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::ResumeAction::DecodableType & commandData); -/** - * @brief Actions Cluster EnableAction Command callback (from client) - */ -bool emberAfActionsClusterEnableActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::EnableAction::DecodableType & commandData); -/** - * @brief Actions Cluster EnableActionWithDuration Command callback (from client) - */ -bool emberAfActionsClusterEnableActionWithDurationCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::EnableActionWithDuration::DecodableType & commandData); -/** - * @brief Actions Cluster DisableAction Command callback (from client) - */ -bool emberAfActionsClusterDisableActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::DisableAction::DecodableType & commandData); -/** - * @brief Actions Cluster DisableActionWithDuration Command callback (from client) - */ -bool emberAfActionsClusterDisableActionWithDurationCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::DisableActionWithDuration::DecodableType & commandData); /** * @brief Basic Information Cluster MfgSpecificPing Command callback (from client) */ From cda9e55f368f6d9b5d4c7893ae78bf6d82fcc465 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Fri, 13 Sep 2024 11:36:02 +0530 Subject: [PATCH 02/15] Add generic implementation for action cluster --- .../include/bridged-actions-stub.h | 110 ++++++ .../src/bridged-actions-stub.cpp | 141 +++++--- .../actions-server/actions-server.cpp | 330 ++++++++++++++++++ .../clusters/actions-server/actions-server.h | 108 ++++++ 4 files changed, 635 insertions(+), 54 deletions(-) create mode 100644 examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h create mode 100644 src/app/clusters/actions-server/actions-server.cpp create mode 100644 src/app/clusters/actions-server/actions-server.h diff --git a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h new file mode 100644 index 00000000000000..2c38869f26802f --- /dev/null +++ b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h @@ -0,0 +1,110 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::Actions; +using namespace chip::app::Clusters::Actions::Attributes; + +namespace chip { +namespace app { +namespace Clusters { +namespace Actions { +const uint16_t kActionListSize = 3; +const uint16_t kEndpointListSize = 3; +class ActionsDelegateImpl : public Delegate +{ +private: + using ActionListStructType = Structs::ActionStruct::Type; + using EndpointListStructType = Structs::EndpointListStruct::Type; + + const ActionListStructType kActionList[kActionListSize] = { + ActionListStructType{ .actionID = 0, + .name = CharSpan::fromCharString("TurnOnLight"), + .type = ActionTypeEnum::kScene, + .endpointListID = 0, + .supportedCommands = 0, + .state = ActionStateEnum::kInactive }, + + ActionListStructType{ .actionID = 1, + .name = CharSpan::fromCharString("TurnOffLight"), + .type = ActionTypeEnum::kScene, + .endpointListID = 1, + .supportedCommands = 0, + .state = ActionStateEnum::kInactive }, + + ActionListStructType{ .actionID = 2, + .name = CharSpan::fromCharString("ToggleLight"), + .type = ActionTypeEnum::kScene, + .endpointListID = 2, + .supportedCommands = 0, + .state = ActionStateEnum::kInactive }, + }; + + // Dummy endpoint list. + const EndpointId firstEpList[1] = { 0 }; + const EndpointId secondEpList[1] = { 0 }; + const EndpointId thirdEpList[1] = { 0 }; + + const EndpointListStructType kEndpointList[kEndpointListSize] = { + EndpointListStructType{ .endpointListID = 0, + .name = CharSpan::fromCharString("On"), + .type = EndpointListTypeEnum::kOther, + .endpoints = DataModel::List(firstEpList) }, + + EndpointListStructType{ .endpointListID = 1, + .name = CharSpan::fromCharString("Off"), + .type = EndpointListTypeEnum::kOther, + .endpoints = DataModel::List(secondEpList) }, + + EndpointListStructType{ .endpointListID = 2, + .name = CharSpan::fromCharString("Toggle"), + .type = EndpointListTypeEnum::kOther, + .endpoints = DataModel::List(thirdEpList) }, + }; + CHIP_ERROR ReadActionAtIndex(uint16_t index, ActionListStructType & action) override; + CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, EndpointListStructType & epList) override; + CHIP_ERROR FindActionIdInActionList(uint16_t actionId) override; + + Status HandleInstantAction(uint16_t actionId, Optional invokeId) override; + Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, Optional invokeId) override; + Status HandleStartAction(uint16_t actionId, Optional invokeId) override; + Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Status HandleStopAction(uint16_t actionId, Optional invokeId) override; + Status HandlePauseAction(uint16_t actionId, Optional invokeId) override; + Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Status HandleResumeAction(uint16_t actionId, Optional invokeId) override; + Status HandleEnableAction(uint16_t actionId, Optional invokeId) override; + Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Status HandleDisableAction(uint16_t actionId, Optional invokeId) override; + Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; +}; +} // namespace Actions +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp index 90d1b9ebd115b0..ab2670f3aa2c8f 100644 --- a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2024 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,88 +15,121 @@ * limitations under the License. */ -#include -#include -#include -#include -#include -#include -#include -#include +#include using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; +using namespace chip::app::Clusters::Actions; using namespace chip::app::Clusters::Actions::Attributes; -namespace { +CHIP_ERROR ActionsDelegateImpl::ReadActionAtIndex(uint16_t index, ActionListStructType & action) +{ + if (index >= ArraySize(kActionList)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + action.actionID = kActionList[index].actionID; + action.name = kActionList[index].name; + action.type = kActionList[index].type; + action.endpointListID = kActionList[index].endpointListID; + action.supportedCommands = kActionList[index].supportedCommands; + action.state = kActionList[index].state; + return CHIP_NO_ERROR; +} -class ActionsAttrAccess : public AttributeAccessInterface +CHIP_ERROR ActionsDelegateImpl::ReadEndpointListAtIndex(uint16_t index, EndpointListStructType & epList) { -public: - // Register for the Actions cluster on all endpoints. - ActionsAttrAccess() : AttributeAccessInterface(Optional::Missing(), Actions::Id) {} + if (index >= ArraySize(kEndpointList)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + epList.endpointListID = kEndpointList[index].endpointListID; + epList.name = kEndpointList[index].name; + epList.type = kEndpointList[index].type; + epList.endpoints = kEndpointList[index].endpoints; + return CHIP_NO_ERROR; +} - CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; +CHIP_ERROR ActionsDelegateImpl::FindActionIdInActionList(uint16_t actionId) +{ + for (uint16_t i = 0; i < kActionListSize; i++) + { + if (kActionList[i].actionID == actionId) + return CHIP_NO_ERROR; + } + return CHIP_ERROR_NOT_FOUND; +} -private: - static constexpr uint16_t ClusterRevision = 1; +Status ActionsDelegateImpl::HandleInstantAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} - CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); -}; +Status ActionsDelegateImpl::HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, + Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} -constexpr uint16_t ActionsAttrAccess::ClusterRevision; +Status ActionsDelegateImpl::HandleStartAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} -CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) +Status ActionsDelegateImpl::HandleStopAction(uint16_t actionId, Optional invokeId) { - // Just return an empty list - return aEncoder.EncodeEmptyList(); + // Not implemented + return Status::NotFound; } -CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) +Status ActionsDelegateImpl::HandlePauseAction(uint16_t actionId, Optional invokeId) { - // Just return an empty list - return aEncoder.EncodeEmptyList(); + // Not implemented + return Status::NotFound; } -CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) +Status ActionsDelegateImpl::HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) { - static const char SetupUrl[] = "https://example.com"; - return aEncoder.Encode(chip::Span(SetupUrl, strlen(SetupUrl))); + // Not implemented + return Status::NotFound; } -CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) +Status ActionsDelegateImpl::HandleResumeAction(uint16_t actionId, Optional invokeId) { - return aEncoder.Encode(ClusterRevision); + // Not implemented + return Status::NotFound; } -ActionsAttrAccess gAttrAccess; +Status ActionsDelegateImpl::HandleEnableAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} -CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +Status ActionsDelegateImpl::HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) { - VerifyOrDie(aPath.mClusterId == Actions::Id); + // Not implemented + return Status::NotFound; +} - switch (aPath.mAttributeId) - { - case ActionList::Id: - return ReadActionListAttribute(aPath.mEndpointId, aEncoder); - case EndpointLists::Id: - return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder); - case SetupURL::Id: - return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder); - case ClusterRevision::Id: - return ReadClusterRevision(aPath.mEndpointId, aEncoder); - default: - break; - } - return CHIP_NO_ERROR; +Status ActionsDelegateImpl::HandleDisableAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; } -} // anonymous namespace -void MatterActionsPluginServerInitCallback() +Status ActionsDelegateImpl::HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) { - AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); + // Not implemented + return Status::NotFound; } diff --git a/src/app/clusters/actions-server/actions-server.cpp b/src/app/clusters/actions-server/actions-server.cpp new file mode 100644 index 00000000000000..3e25d19c3a099d --- /dev/null +++ b/src/app/clusters/actions-server/actions-server.cpp @@ -0,0 +1,330 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * 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 "actions-server.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::Actions; +using namespace chip::app::Clusters::Actions::Attributes; + +Instance Instance::instance; +Instance * Instance::GetInstance() +{ + return &instance; +} + +CHIP_ERROR Instance::ReadActionListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder) +{ + if (GetInstance()->mDelegate == nullptr) + { + ChipLogError(Zcl, "Actions delegate is null!!!"); + return CHIP_ERROR_INCORRECT_STATE; + } + for (uint16_t i = 0; true; i++) + { + Actions::Structs::ActionStruct::Type action; + + CHIP_ERROR err = GetInstance()->mDelegate->ReadActionAtIndex(i, action); + if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) + { + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(encoder.Encode(action)); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR Instance::ReadEndpointListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder) +{ + if (GetInstance()->mDelegate == nullptr) + { + ChipLogError(Zcl, "Actions delegate is null!!!"); + return CHIP_ERROR_INCORRECT_STATE; + } + for (uint16_t i = 0; true; i++) + { + Actions::Structs::EndpointListStruct::Type epList; + + CHIP_ERROR err = GetInstance()->mDelegate->ReadEndpointListAtIndex(i, epList); + if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) + { + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(encoder.Encode(epList)); + } + return CHIP_NO_ERROR; +} + +void Instance::SetDefaultDelegate(Delegate * aDelegate) +{ + if (aDelegate == nullptr) + { + ChipLogError(Zcl, "Cannot set empty delegate!!!"); + return; + } + mDelegate = aDelegate; +} + +CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + VerifyOrDie(aPath.mClusterId == Actions::Id); + + switch (aPath.mAttributeId) + { + case ActionList::Id: { + Instance * d = this; + CHIP_ERROR err = + aEncoder.EncodeList([d](const auto & encoder) -> CHIP_ERROR { return d->ReadActionListAttribute(encoder); }); + return err; + } + case EndpointLists::Id: { + Instance * d = this; + CHIP_ERROR err = + aEncoder.EncodeList([d](const auto & encoder) -> CHIP_ERROR { return d->ReadEndpointListAttribute(encoder); }); + return err; + } + default: + break; + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR Instance::FindActionIdInActionList(uint16_t actionId) +{ + if (GetInstance()->mDelegate == nullptr) + { + ChipLogError(Zcl, "Actions delegate is null!!!"); + return CHIP_ERROR_INCORRECT_STATE; + } + return GetInstance()->mDelegate->FindActionIdInActionList(actionId); +} + +template +void Instance::HandleCommand(HandlerContext & handlerContext, FuncT func) +{ + if (!handlerContext.mCommandHandled && (handlerContext.mRequestPath.mCommandId == RequestT::GetCommandId())) + { + RequestT requestPayload; + + // If the command matches what the caller is looking for, let's mark this as being handled + // even if errors happen after this. This ensures that we don't execute any fall-back strategies + // to handle this command since at this point, the caller is taking responsibility for handling + // the command in its entirety, warts and all. + // + handlerContext.SetCommandHandled(); + + if (DataModel::Decode(handlerContext.mPayload, requestPayload) != CHIP_NO_ERROR) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, + Protocols::InteractionModel::Status::InvalidCommand); + return; + } + + uint16_t actionId = requestPayload.actionID; + CHIP_ERROR err = GetInstance()->FindActionIdInActionList(actionId); + if (err != CHIP_NO_ERROR) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Protocols::InteractionModel::Status::NotFound); + return; + } + + func(handlerContext, requestPayload); + } +} + +void Instance::HandleInstantAction(HandlerContext & ctx, const Commands::InstantAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleInstantAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleInstantActionWithTransition(HandlerContext & ctx, + const Commands::InstantActionWithTransition::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + uint16_t transitionTime = commandData.transitionTime; + Status status = GetInstance()->mDelegate->HandleInstantActionWithTransition(actionId, transitionTime, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleStartAction(HandlerContext & ctx, const Commands::StartAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleStartAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleStartActionWithDuration(HandlerContext & ctx, + const Commands::StartActionWithDuration::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + uint32_t duration = commandData.duration; + Status status = GetInstance()->mDelegate->HandleStartActionWithDuration(actionId, duration, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleStopAction(HandlerContext & ctx, const Commands::StopAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleStopAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandlePauseAction(HandlerContext & ctx, const Commands::PauseAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandlePauseAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandlePauseActionWithDuration(HandlerContext & ctx, + const Commands::PauseActionWithDuration::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + uint32_t duration = commandData.duration; + Status status = GetInstance()->mDelegate->HandlePauseActionWithDuration(actionId, duration, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleResumeAction(HandlerContext & ctx, const Commands::ResumeAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleResumeAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleEnableAction(HandlerContext & ctx, const Commands::EnableAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleEnableAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleEnableActionWithDuration(HandlerContext & ctx, + const Commands::EnableActionWithDuration::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + uint32_t duration = commandData.duration; + Status status = GetInstance()->mDelegate->HandleEnableActionWithDuration(actionId, duration, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleDisableAction(HandlerContext & ctx, const Commands::DisableAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleDisableAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleDisableActionWithDuration(HandlerContext & ctx, + const Commands::DisableActionWithDuration::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + uint32_t duration = commandData.duration; + Status status = GetInstance()->mDelegate->HandleDisableActionWithDuration(actionId, duration, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::InvokeCommand(HandlerContext & handlerContext) +{ + switch (handlerContext.mRequestPath.mCommandId) + { + case Actions::Commands::InstantAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleInstantAction(ctx, commandData); }); + return; + case Actions::Commands::InstantActionWithTransition::Id: + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleInstantActionWithTransition(ctx, commandData); }); + return; + case Actions::Commands::StartAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleStartAction(ctx, commandData); }); + return; + case Actions::Commands::StartActionWithDuration::Id: + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleStartActionWithDuration(ctx, commandData); }); + return; + case Actions::Commands::StopAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleStopAction(ctx, commandData); }); + return; + case Actions::Commands::PauseAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandlePauseAction(ctx, commandData); }); + return; + case Actions::Commands::PauseActionWithDuration::Id: + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandlePauseActionWithDuration(ctx, commandData); }); + return; + case Actions::Commands::ResumeAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleResumeAction(ctx, commandData); }); + return; + case Actions::Commands::EnableAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleEnableAction(ctx, commandData); }); + return; + case Actions::Commands::EnableActionWithDuration::Id: + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleEnableActionWithDuration(ctx, commandData); }); + return; + case Actions::Commands::DisableAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleDisableAction(ctx, commandData); }); + return; + case Actions::Commands::DisableActionWithDuration::Id: + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleDisableActionWithDuration(ctx, commandData); }); + return; + } +} +void MatterActionsPluginServerInitCallback() +{ + AttributeAccessInterfaceRegistry::Instance().Register(Instance::GetInstance()); + CommandHandlerInterfaceRegistry::Instance().RegisterCommandHandler(Instance::GetInstance()); +} diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h new file mode 100644 index 00000000000000..7c7a4f6d80cbe9 --- /dev/null +++ b/src/app/clusters/actions-server/actions-server.h @@ -0,0 +1,108 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * 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 +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::Protocols::InteractionModel; + +namespace chip { +namespace app { +namespace Clusters { +namespace Actions { + +class Delegate; + +class Instance : public AttributeAccessInterface, public CommandHandlerInterface +{ +public: + // Register for the Actions cluster on all endpoints. + Instance() : + AttributeAccessInterface(Optional::Missing(), Actions::Id), + CommandHandlerInterface(Optional::Missing(), Actions::Id) + {} + + static Instance * GetInstance(); + void SetDefaultDelegate(Delegate * aDelegate); + +private: + Delegate * mDelegate; + static Instance instance; + + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + + CHIP_ERROR ReadActionListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder); + CHIP_ERROR ReadEndpointListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder); + CHIP_ERROR FindActionIdInActionList(uint16_t actionId); + + // CommandHandlerInterface + template + void HandleCommand(HandlerContext & handlerContext, FuncT func); + + void InvokeCommand(HandlerContext & handlerContext) override; + + void HandleInstantAction(HandlerContext & ctx, const Commands::InstantAction::DecodableType & commandData); + void HandleInstantActionWithTransition(HandlerContext & ctx, + const Commands::InstantActionWithTransition::DecodableType & commandData); + void HandleStartAction(HandlerContext & ctx, const Commands::StartAction::DecodableType & commandData); + void HandleStartActionWithDuration(HandlerContext & ctx, const Commands::StartActionWithDuration::DecodableType & commandData); + void HandleStopAction(HandlerContext & ctx, const Commands::StopAction::DecodableType & commandData); + void HandlePauseAction(HandlerContext & ctx, const Commands::PauseAction::DecodableType & commandData); + void HandlePauseActionWithDuration(HandlerContext & ctx, const Commands::PauseActionWithDuration::DecodableType & commandData); + void HandleResumeAction(HandlerContext & ctx, const Commands::ResumeAction::DecodableType & commandData); + void HandleEnableAction(HandlerContext & ctx, const Commands::EnableAction::DecodableType & commandData); + void HandleEnableActionWithDuration(HandlerContext & ctx, + const Commands::EnableActionWithDuration::DecodableType & commandData); + void HandleDisableAction(HandlerContext & ctx, const Commands::DisableAction::DecodableType & commandData); + void HandleDisableActionWithDuration(HandlerContext & ctx, + const Commands::DisableActionWithDuration::DecodableType & commandData); +}; + +class Delegate +{ +public: + virtual ~Delegate() = default; + + virtual CHIP_ERROR ReadActionAtIndex(uint16_t index, Structs::ActionStruct::Type & action); + virtual CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, Structs::EndpointListStruct::Type & epList); + virtual CHIP_ERROR FindActionIdInActionList(uint16_t actionId); + + virtual Status HandleInstantAction(uint16_t actionId, Optional invokeId); + virtual Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, Optional invokeId); + virtual Status HandleStartAction(uint16_t actionId, Optional invokeId); + virtual Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Status HandleStopAction(uint16_t actionId, Optional invokeId); + virtual Status HandlePauseAction(uint16_t actionId, Optional invokeId); + virtual Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Status HandleResumeAction(uint16_t actionId, Optional invokeId); + virtual Status HandleEnableAction(uint16_t actionId, Optional invokeId); + virtual Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Status HandleDisableAction(uint16_t actionId, Optional invokeId); + virtual Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); +}; + +} // namespace Actions +} // namespace Clusters +} // namespace app +} // namespace chip From 4cf426fd7e2d2b5e9a47b53d0b8978263ccf3291 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Fri, 13 Sep 2024 11:36:42 +0530 Subject: [PATCH 03/15] Example changes --- examples/all-clusters-app/esp32/main/main.cpp | 4 +++- examples/bridge-app/esp32/main/main.cpp | 8 -------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/examples/all-clusters-app/esp32/main/main.cpp b/examples/all-clusters-app/esp32/main/main.cpp index 7ef84346e6cf7d..494afd5b48e774 100644 --- a/examples/all-clusters-app/esp32/main/main.cpp +++ b/examples/all-clusters-app/esp32/main/main.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,7 @@ AppCallbacks sCallbacks; app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; +app::Clusters::Actions::ActionsDelegateImpl sActionsDelegateImpl; constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; @@ -126,9 +128,9 @@ static void InitServer(intptr_t context) app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); + app::Clusters::Actions::Instance::GetInstance()->SetDefaultDelegate(&sActionsDelegateImpl); } -// #include #include #include diff --git a/examples/bridge-app/esp32/main/main.cpp b/examples/bridge-app/esp32/main/main.cpp index d1075385cec8c9..9ee3c62a6ed12d 100644 --- a/examples/bridge-app/esp32/main/main.cpp +++ b/examples/bridge-app/esp32/main/main.cpp @@ -349,14 +349,6 @@ void HandleDeviceStatusChanged(Device * dev, Device::Changed_t itemChangedMask) } } -bool emberAfActionsClusterInstantActionCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, - const Actions::Commands::InstantAction::DecodableType & commandData) -{ - // No actions are implemented, just return status NotFound. - commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); - return true; -} - const EmberAfDeviceType gRootDeviceTypes[] = { { DEVICE_TYPE_ROOT_NODE, DEVICE_VERSION_DEFAULT } }; const EmberAfDeviceType gAggregateNodeDeviceTypes[] = { { DEVICE_TYPE_BRIDGE, DEVICE_VERSION_DEFAULT } }; From a0d44acbb97a504c7545364f35790bf5b0c3d2b3 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Tue, 17 Sep 2024 11:38:52 +0530 Subject: [PATCH 04/15] Add documentation and fix pipeline --- .../clusters/actions-server/actions-server.h | 136 ++++++++++++++++++ src/app/zap_cluster_list.json | 3 +- 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h index 7c7a4f6d80cbe9..657bd872f69d61 100644 --- a/src/app/clusters/actions-server/actions-server.h +++ b/src/app/clusters/actions-server/actions-server.h @@ -84,21 +84,157 @@ class Delegate public: virtual ~Delegate() = default; + /** + * Get the action at the Nth index from list of actions. + * @param index The index of the action to be returned. It is assumed that actions are indexable from 0 and with no gaps. + * @param action A reference to the action struct which copies existing and initialised buffer at index. + * @return Returns a CHIP_NO_ERROR if there was no error and the action was returned successfully. + * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index in beyond the list of available actions. + */ virtual CHIP_ERROR ReadActionAtIndex(uint16_t index, Structs::ActionStruct::Type & action); + + /** + * Get the EndpointList at the Nth index from list of endpointList. + * @param index The index of the endpointList to be returned. It is assumed that actions are indexable from 0 and with no gaps. + * @param epList A reference to the endpointList struct which copies existing and initialised buffer at index. + * @return Returns a CHIP_NO_ERROR if there was no error and the epList was returned successfully. + * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index in beyond the list of available endpointList. + */ virtual CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, Structs::EndpointListStruct::Type & epList); + + /** + * Find the action with matching actionId in the list of action. + * @param actionId The action to be find in the list of action. + * @return Returns a CHIP_NO_ERROR if matching action is found. + * CHIP_ERROR_NOT_FOUND if the matching action does not found in the list of action. + */ virtual CHIP_ERROR FindActionIdInActionList(uint16_t actionId); + /** + * On reciept of each and every command, + * if the InvokeID data field is provided by the client when invoking a command, the server SHALL generate a StateChanged event + * when the action changes to a new state or an ActionFailed event when execution of the action fails. + * + * @return If the command refers to an action which currently is not in a state where the command applies, a response SHALL be + * generated with the StatusCode INVALID_COMMAND. + */ + + /** + * When an InstantAction command is recieved, an action (state change) on the involved endpoints shall trigger, + * in a "fire and forget" manner. Afterwards, the action’s state SHALL be Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandleInstantAction(uint16_t actionId, Optional invokeId); + + /** + * When an InstantActionWithTransition command is recieved, an action (state change) on the involved endpoints shall trigger, + * with a specified time to transition from the current state to the new state. During the transition, the action’s state SHALL + * be Active. Afterwards, the action’s state SHALL be Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @param transitionTime The time for transition from the current state to the new state. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, Optional invokeId); + + /** + * When a StartAction command is recieved, the commencement of an action on the involved endpoints shall trigger. Afterwards, + * the action’s state SHALL be Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandleStartAction(uint16_t actionId, Optional invokeId); + + /** + * When a StartActionWithDuration command is recieved, the commencement of an action on the involved endpoints shall trigger, + * and SHALL change the action’s state to Active. After the specified Duration, the action will stop, and the action’s state + * SHALL change to Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @param duration The time for which an action shall be in start state. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + + /** + * When a StopAction command is recieved, the ongoing action on the involved endpoints shall stop. Afterwards, the action’s + * state SHALL be Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandleStopAction(uint16_t actionId, Optional invokeId); + + /** + * When a PauseAction command is recieved, the ongoing action on the involved endpoints shall pause and SHALL change the + * action’s state to Paused. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandlePauseAction(uint16_t actionId, Optional invokeId); + + /** + * When a PauseActionWithDuration command is recieved, pauses an ongoing action, and SHALL change the action’s state to Paused. + * After the specified Duration, the ongoing action will be automatically resumed. which SHALL change the action’s state to + * Active. + * + * @param actionId The id of an action on which an action shall takes place. + * @param duration The time for which an action shall be in pause state. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + + /** + * When a ResumeAction command is recieved, the previously paused action shall resume and SHALL change the action’s state to + * Active. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandleResumeAction(uint16_t actionId, Optional invokeId); + + /** + * When an EnableAction command is recieved, it enables a certain action or automation. Afterwards, the action’s state SHALL be + * Active. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandleEnableAction(uint16_t actionId, Optional invokeId); + + /** + * When an EnableActionWithDuration command is recieved, it enables a certain action or automation, and SHALL change the + * action’s state to be Active. After the specified Duration, the action or automation will stop, and the action’s state SHALL + * change to Disabled. + * + * @param actionId The id of an action on which an action shall takes place. + * @param duration The time for which an action shall be in active state. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + + /** + * When a DisableAction command is recieved, it disables a certain action or automation, and SHALL change the action’s state to + * Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandleDisableAction(uint16_t actionId, Optional invokeId); + + /** + * When a DisableActionWithDuration command is recieved, it disables a certain action or automation, and SHALL change the + * action’s state to Disabled. After the specified Duration, the action or automation will re-start, and the action’s state + * SHALL change to either Inactive or Active, depending on the actions. + * + * @param actionId The id of an action on which an action shall takes place. + * @param duration The time for which an action shall be in disable state. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ virtual Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); }; diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index 971d7abede1c89..684f61f4ec86ee 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -328,6 +328,7 @@ "WINDOW_COVERING_CLUSTER": ["window-covering-server"], "WATER_HEATER_MANAGEMENT_CLUSTER": ["water-heater-management-server"], "WATER_HEATER_MODE_CLUSTER": ["mode-base-server"], - "ZONE_MANAGEMENT_CLUSTER": [] + "ZONE_MANAGEMENT_CLUSTER": [], + "ACTIONS_CLUSTER": ["actions-server"] } } From abc8467bb691ea21ec72a6b568363edc0bf69721 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Tue, 17 Sep 2024 17:02:29 +0530 Subject: [PATCH 05/15] Some example changes --- .../include/bridged-actions-stub.h | 30 ++++++++----------- .../src/bridged-actions-stub.cpp | 1 + .../asr/src/bridged-actions-stub.cpp | 8 ++--- .../bridge-app/linux/bridged-actions-stub.cpp | 8 ++--- .../bridge-app/telink/src/DeviceCallbacks.cpp | 8 ++--- .../actions-server/actions-server.cpp | 1 + .../clusters/actions-server/actions-server.h | 29 ++++++++---------- 7 files changed, 38 insertions(+), 47 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h index 2c38869f26802f..1366f404b98672 100644 --- a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h +++ b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h @@ -25,12 +25,6 @@ #include #include -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; -using namespace chip::app::Clusters::Actions; -using namespace chip::app::Clusters::Actions::Attributes; - namespace chip { namespace app { namespace Clusters { @@ -91,18 +85,18 @@ class ActionsDelegateImpl : public Delegate CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, EndpointListStructType & epList) override; CHIP_ERROR FindActionIdInActionList(uint16_t actionId) override; - Status HandleInstantAction(uint16_t actionId, Optional invokeId) override; - Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, Optional invokeId) override; - Status HandleStartAction(uint16_t actionId, Optional invokeId) override; - Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; - Status HandleStopAction(uint16_t actionId, Optional invokeId) override; - Status HandlePauseAction(uint16_t actionId, Optional invokeId) override; - Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; - Status HandleResumeAction(uint16_t actionId, Optional invokeId) override; - Status HandleEnableAction(uint16_t actionId, Optional invokeId) override; - Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; - Status HandleDisableAction(uint16_t actionId, Optional invokeId) override; - Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, Optional invokeId) override; + Protocols::InteractionModel::Status HandleStartAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Protocols::InteractionModel::Status HandleStopAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandlePauseAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Protocols::InteractionModel::Status HandleResumeAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleEnableAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Protocols::InteractionModel::Status HandleDisableAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; }; } // namespace Actions } // namespace Clusters diff --git a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp index ab2670f3aa2c8f..bd9a588f6047e4 100644 --- a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp @@ -22,6 +22,7 @@ using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::app::Clusters::Actions; using namespace chip::app::Clusters::Actions::Attributes; +using namespace chip::Protocols::InteractionModel; CHIP_ERROR ActionsDelegateImpl::ReadActionAtIndex(uint16_t index, ActionListStructType & action) { diff --git a/examples/bridge-app/asr/src/bridged-actions-stub.cpp b/examples/bridge-app/asr/src/bridged-actions-stub.cpp index 73b7e8dd9877a0..d6289a733f2259 100755 --- a/examples/bridge-app/asr/src/bridged-actions-stub.cpp +++ b/examples/bridge-app/asr/src/bridged-actions-stub.cpp @@ -95,7 +95,7 @@ CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, Attr } } // anonymous namespace -void MatterActionsPluginServerInitCallback(void) -{ - AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -} +//void MatterActionsPluginServerInitCallback(void) +//{ +// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); +//} diff --git a/examples/bridge-app/linux/bridged-actions-stub.cpp b/examples/bridge-app/linux/bridged-actions-stub.cpp index 580f4f2239bd1a..cca8d38d809c94 100644 --- a/examples/bridge-app/linux/bridged-actions-stub.cpp +++ b/examples/bridge-app/linux/bridged-actions-stub.cpp @@ -131,7 +131,7 @@ CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, Attr } } // anonymous namespace -void MatterActionsPluginServerInitCallback() -{ - AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -} +//void MatterActionsPluginServerInitCallback() +//{ +// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); +//} diff --git a/examples/bridge-app/telink/src/DeviceCallbacks.cpp b/examples/bridge-app/telink/src/DeviceCallbacks.cpp index 9e3273e7107472..65218c68295bba 100644 --- a/examples/bridge-app/telink/src/DeviceCallbacks.cpp +++ b/examples/bridge-app/telink/src/DeviceCallbacks.cpp @@ -99,7 +99,7 @@ CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, Attr } } // anonymous namespace -void MatterActionsPluginServerInitCallback(void) -{ - AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -} +//void MatterActionsPluginServerInitCallback(void) +//{ +// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); +//} diff --git a/src/app/clusters/actions-server/actions-server.cpp b/src/app/clusters/actions-server/actions-server.cpp index 3e25d19c3a099d..023cbcf9c1a0cd 100644 --- a/src/app/clusters/actions-server/actions-server.cpp +++ b/src/app/clusters/actions-server/actions-server.cpp @@ -30,6 +30,7 @@ using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::app::Clusters::Actions; using namespace chip::app::Clusters::Actions::Attributes; +using namespace chip::Protocols::InteractionModel; Instance Instance::instance; Instance * Instance::GetInstance() diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h index 657bd872f69d61..e4d65a803e8a8e 100644 --- a/src/app/clusters/actions-server/actions-server.h +++ b/src/app/clusters/actions-server/actions-server.h @@ -22,11 +22,6 @@ #include #include -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; -using namespace chip::Protocols::InteractionModel; - namespace chip { namespace app { namespace Clusters { @@ -126,7 +121,7 @@ class Delegate * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandleInstantAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId); /** * When an InstantActionWithTransition command is recieved, an action (state change) on the involved endpoints shall trigger, @@ -137,7 +132,7 @@ class Delegate * @param transitionTime The time for transition from the current state to the new state. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, Optional invokeId); /** * When a StartAction command is recieved, the commencement of an action on the involved endpoints shall trigger. Afterwards, @@ -146,7 +141,7 @@ class Delegate * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandleStartAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleStartAction(uint16_t actionId, Optional invokeId); /** * When a StartActionWithDuration command is recieved, the commencement of an action on the involved endpoints shall trigger, @@ -157,7 +152,7 @@ class Delegate * @param duration The time for which an action shall be in start state. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); /** * When a StopAction command is recieved, the ongoing action on the involved endpoints shall stop. Afterwards, the action’s @@ -166,7 +161,7 @@ class Delegate * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandleStopAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleStopAction(uint16_t actionId, Optional invokeId); /** * When a PauseAction command is recieved, the ongoing action on the involved endpoints shall pause and SHALL change the @@ -175,7 +170,7 @@ class Delegate * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandlePauseAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandlePauseAction(uint16_t actionId, Optional invokeId); /** * When a PauseActionWithDuration command is recieved, pauses an ongoing action, and SHALL change the action’s state to Paused. @@ -186,7 +181,7 @@ class Delegate * @param duration The time for which an action shall be in pause state. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); /** * When a ResumeAction command is recieved, the previously paused action shall resume and SHALL change the action’s state to @@ -195,7 +190,7 @@ class Delegate * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandleResumeAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleResumeAction(uint16_t actionId, Optional invokeId); /** * When an EnableAction command is recieved, it enables a certain action or automation. Afterwards, the action’s state SHALL be @@ -204,7 +199,7 @@ class Delegate * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandleEnableAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleEnableAction(uint16_t actionId, Optional invokeId); /** * When an EnableActionWithDuration command is recieved, it enables a certain action or automation, and SHALL change the @@ -215,7 +210,7 @@ class Delegate * @param duration The time for which an action shall be in active state. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); /** * When a DisableAction command is recieved, it disables a certain action or automation, and SHALL change the action’s state to @@ -224,7 +219,7 @@ class Delegate * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandleDisableAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleDisableAction(uint16_t actionId, Optional invokeId); /** * When a DisableActionWithDuration command is recieved, it disables a certain action or automation, and SHALL change the @@ -235,7 +230,7 @@ class Delegate * @param duration The time for which an action shall be in disable state. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); }; } // namespace Actions From 5c381137540b74e4cba964d0563093ad709db5a4 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Tue, 24 Sep 2024 17:00:52 +0530 Subject: [PATCH 06/15] Add comment about scope of name --- src/app/clusters/actions-server/actions-server.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h index e4d65a803e8a8e..03bdb38754e08f 100644 --- a/src/app/clusters/actions-server/actions-server.h +++ b/src/app/clusters/actions-server/actions-server.h @@ -82,7 +82,10 @@ class Delegate /** * Get the action at the Nth index from list of actions. * @param index The index of the action to be returned. It is assumed that actions are indexable from 0 and with no gaps. - * @param action A reference to the action struct which copies existing and initialised buffer at index. + * @param action A reference to the action struct which copies existing initialised buffer at index. + * Name field (CharSpan) of ActionStruct contails the name of an action. + * The underlying data must remain allocated throughout the lifetime of the device, + * as the API does not make a copy. * @return Returns a CHIP_NO_ERROR if there was no error and the action was returned successfully. * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index in beyond the list of available actions. */ @@ -91,7 +94,10 @@ class Delegate /** * Get the EndpointList at the Nth index from list of endpointList. * @param index The index of the endpointList to be returned. It is assumed that actions are indexable from 0 and with no gaps. - * @param epList A reference to the endpointList struct which copies existing and initialised buffer at index. + * @param epList A reference to the endpointList struct which copies existing initialised buffer at index. + * Name field (CharSpan) of EndpointList contails the name of an endpointList. + * The underlying data must remain allocated throughout the lifetime of the device, + * as the API does not make a copy. * @return Returns a CHIP_NO_ERROR if there was no error and the epList was returned successfully. * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index in beyond the list of available endpointList. */ From da513f00bc720bc1da402a1d15b41278949ca897 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Tue, 24 Sep 2024 11:31:23 +0000 Subject: [PATCH 07/15] Restyled by clang-format --- .../include/bridged-actions-stub.h | 15 ++++++++++----- .../bridge-app/asr/src/bridged-actions-stub.cpp | 6 +++--- .../bridge-app/linux/bridged-actions-stub.cpp | 6 +++--- .../bridge-app/telink/src/DeviceCallbacks.cpp | 6 +++--- .../linux/src/bridged-actions-stub.cpp | 8 ++++---- src/app/clusters/actions-server/actions-server.h | 15 ++++++++++----- 6 files changed, 33 insertions(+), 23 deletions(-) mode change 100755 => 100644 examples/bridge-app/asr/src/bridged-actions-stub.cpp diff --git a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h index 1366f404b98672..6c1a5c65fd8f20 100644 --- a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h +++ b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h @@ -86,17 +86,22 @@ class ActionsDelegateImpl : public Delegate CHIP_ERROR FindActionIdInActionList(uint16_t actionId) override; Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId) override; - Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, Optional invokeId) override; + Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, + Optional invokeId) override; Protocols::InteractionModel::Status HandleStartAction(uint16_t actionId, Optional invokeId) override; - Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; Protocols::InteractionModel::Status HandleStopAction(uint16_t actionId, Optional invokeId) override; Protocols::InteractionModel::Status HandlePauseAction(uint16_t actionId, Optional invokeId) override; - Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; Protocols::InteractionModel::Status HandleResumeAction(uint16_t actionId, Optional invokeId) override; Protocols::InteractionModel::Status HandleEnableAction(uint16_t actionId, Optional invokeId) override; - Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; Protocols::InteractionModel::Status HandleDisableAction(uint16_t actionId, Optional invokeId) override; - Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) override; + Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; }; } // namespace Actions } // namespace Clusters diff --git a/examples/bridge-app/asr/src/bridged-actions-stub.cpp b/examples/bridge-app/asr/src/bridged-actions-stub.cpp old mode 100755 new mode 100644 index d6289a733f2259..84dca65f832107 --- a/examples/bridge-app/asr/src/bridged-actions-stub.cpp +++ b/examples/bridge-app/asr/src/bridged-actions-stub.cpp @@ -95,7 +95,7 @@ CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, Attr } } // anonymous namespace -//void MatterActionsPluginServerInitCallback(void) +// void MatterActionsPluginServerInitCallback(void) //{ -// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -//} +// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); +// } diff --git a/examples/bridge-app/linux/bridged-actions-stub.cpp b/examples/bridge-app/linux/bridged-actions-stub.cpp index cca8d38d809c94..0eff1e7b6d05bc 100644 --- a/examples/bridge-app/linux/bridged-actions-stub.cpp +++ b/examples/bridge-app/linux/bridged-actions-stub.cpp @@ -131,7 +131,7 @@ CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, Attr } } // anonymous namespace -//void MatterActionsPluginServerInitCallback() +// void MatterActionsPluginServerInitCallback() //{ -// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -//} +// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); +// } diff --git a/examples/bridge-app/telink/src/DeviceCallbacks.cpp b/examples/bridge-app/telink/src/DeviceCallbacks.cpp index 65218c68295bba..8511d7047dfb0a 100644 --- a/examples/bridge-app/telink/src/DeviceCallbacks.cpp +++ b/examples/bridge-app/telink/src/DeviceCallbacks.cpp @@ -99,7 +99,7 @@ CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, Attr } } // anonymous namespace -//void MatterActionsPluginServerInitCallback(void) +// void MatterActionsPluginServerInitCallback(void) //{ -// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -//} +// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); +// } diff --git a/examples/placeholder/linux/src/bridged-actions-stub.cpp b/examples/placeholder/linux/src/bridged-actions-stub.cpp index d7abf17cd9106e..ad934cc881077c 100644 --- a/examples/placeholder/linux/src/bridged-actions-stub.cpp +++ b/examples/placeholder/linux/src/bridged-actions-stub.cpp @@ -96,7 +96,7 @@ CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, Attr } } // anonymous namespace -void MatterActionsPluginServerInitCallback(void) -{ - chip::app::AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -} +// void MatterActionsPluginServerInitCallback(void) +//{ +// chip::app::AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); +// } diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h index 03bdb38754e08f..f702069cfa68b7 100644 --- a/src/app/clusters/actions-server/actions-server.h +++ b/src/app/clusters/actions-server/actions-server.h @@ -138,7 +138,8 @@ class Delegate * @param transitionTime The time for transition from the current state to the new state. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, + Optional invokeId); /** * When a StartAction command is recieved, the commencement of an action on the involved endpoints shall trigger. Afterwards, @@ -158,7 +159,8 @@ class Delegate * @param duration The time for which an action shall be in start state. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId); /** * When a StopAction command is recieved, the ongoing action on the involved endpoints shall stop. Afterwards, the action’s @@ -187,7 +189,8 @@ class Delegate * @param duration The time for which an action shall be in pause state. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId); /** * When a ResumeAction command is recieved, the previously paused action shall resume and SHALL change the action’s state to @@ -216,7 +219,8 @@ class Delegate * @param duration The time for which an action shall be in active state. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId); /** * When a DisableAction command is recieved, it disables a certain action or automation, and SHALL change the action’s state to @@ -236,7 +240,8 @@ class Delegate * @param duration The time for which an action shall be in disable state. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId); }; } // namespace Actions From 98833fdb2543d3d812b5874d60a511d14ce59ffd Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Fri, 4 Oct 2024 13:09:42 +0530 Subject: [PATCH 08/15] Add generic struct to copy the ActionStruct and EndpointListStruct along with name buffer and added events --- .../include/bridged-actions-stub.h | 55 +++------ .../src/bridged-actions-stub.cpp | 16 +-- .../actions-server/actions-server.cpp | 34 +++++- .../clusters/actions-server/actions-server.h | 115 ++++++++++++++++-- 4 files changed, 156 insertions(+), 64 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h index 6c1a5c65fd8f20..91c9999d7cf90d 100644 --- a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h +++ b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h @@ -34,30 +34,10 @@ const uint16_t kEndpointListSize = 3; class ActionsDelegateImpl : public Delegate { private: - using ActionListStructType = Structs::ActionStruct::Type; - using EndpointListStructType = Structs::EndpointListStruct::Type; - - const ActionListStructType kActionList[kActionListSize] = { - ActionListStructType{ .actionID = 0, - .name = CharSpan::fromCharString("TurnOnLight"), - .type = ActionTypeEnum::kScene, - .endpointListID = 0, - .supportedCommands = 0, - .state = ActionStateEnum::kInactive }, - - ActionListStructType{ .actionID = 1, - .name = CharSpan::fromCharString("TurnOffLight"), - .type = ActionTypeEnum::kScene, - .endpointListID = 1, - .supportedCommands = 0, - .state = ActionStateEnum::kInactive }, - - ActionListStructType{ .actionID = 2, - .name = CharSpan::fromCharString("ToggleLight"), - .type = ActionTypeEnum::kScene, - .endpointListID = 2, - .supportedCommands = 0, - .state = ActionStateEnum::kInactive }, + const GenericActionStruct kActionList[kActionListSize] = { + GenericActionStruct(0, CharSpan::fromCharString("TurnOnLight"), ActionTypeEnum::kScene, 0, 0, ActionStateEnum::kInactive), + GenericActionStruct(1, CharSpan::fromCharString("TurnOffLight"), ActionTypeEnum::kScene, 1, 0, ActionStateEnum::kInactive), + GenericActionStruct(2, CharSpan::fromCharString("ToggleLight"), ActionTypeEnum::kScene, 2, 0, ActionStateEnum::kInactive), }; // Dummy endpoint list. @@ -65,24 +45,17 @@ class ActionsDelegateImpl : public Delegate const EndpointId secondEpList[1] = { 0 }; const EndpointId thirdEpList[1] = { 0 }; - const EndpointListStructType kEndpointList[kEndpointListSize] = { - EndpointListStructType{ .endpointListID = 0, - .name = CharSpan::fromCharString("On"), - .type = EndpointListTypeEnum::kOther, - .endpoints = DataModel::List(firstEpList) }, - - EndpointListStructType{ .endpointListID = 1, - .name = CharSpan::fromCharString("Off"), - .type = EndpointListTypeEnum::kOther, - .endpoints = DataModel::List(secondEpList) }, - - EndpointListStructType{ .endpointListID = 2, - .name = CharSpan::fromCharString("Toggle"), - .type = EndpointListTypeEnum::kOther, - .endpoints = DataModel::List(thirdEpList) }, + const GenericEndpointList kEndpointList[kEndpointListSize] = { + GenericEndpointList(0, CharSpan::fromCharString("On"), EndpointListTypeEnum::kOther, + DataModel::List(firstEpList)), + GenericEndpointList(1, CharSpan::fromCharString("Off"), EndpointListTypeEnum::kOther, + DataModel::List(secondEpList)), + GenericEndpointList(2, CharSpan::fromCharString("Toggle"), EndpointListTypeEnum::kOther, + DataModel::List(thirdEpList)), }; - CHIP_ERROR ReadActionAtIndex(uint16_t index, ActionListStructType & action) override; - CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, EndpointListStructType & epList) override; + + CHIP_ERROR ReadActionAtIndex(uint16_t index, GenericActionStruct & action) override; + CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, GenericEndpointList & epList) override; CHIP_ERROR FindActionIdInActionList(uint16_t actionId) override; Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId) override; diff --git a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp index bd9a588f6047e4..e7f0dd701015b3 100644 --- a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp @@ -24,31 +24,23 @@ using namespace chip::app::Clusters::Actions; using namespace chip::app::Clusters::Actions::Attributes; using namespace chip::Protocols::InteractionModel; -CHIP_ERROR ActionsDelegateImpl::ReadActionAtIndex(uint16_t index, ActionListStructType & action) +CHIP_ERROR ActionsDelegateImpl::ReadActionAtIndex(uint16_t index, GenericActionStruct & action) { if (index >= ArraySize(kActionList)) { return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; } - action.actionID = kActionList[index].actionID; - action.name = kActionList[index].name; - action.type = kActionList[index].type; - action.endpointListID = kActionList[index].endpointListID; - action.supportedCommands = kActionList[index].supportedCommands; - action.state = kActionList[index].state; + action = kActionList[index]; return CHIP_NO_ERROR; } -CHIP_ERROR ActionsDelegateImpl::ReadEndpointListAtIndex(uint16_t index, EndpointListStructType & epList) +CHIP_ERROR ActionsDelegateImpl::ReadEndpointListAtIndex(uint16_t index, GenericEndpointList & epList) { if (index >= ArraySize(kEndpointList)) { return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; } - epList.endpointListID = kEndpointList[index].endpointListID; - epList.name = kEndpointList[index].name; - epList.type = kEndpointList[index].type; - epList.endpoints = kEndpointList[index].endpoints; + epList = kEndpointList[index]; return CHIP_NO_ERROR; } diff --git a/src/app/clusters/actions-server/actions-server.cpp b/src/app/clusters/actions-server/actions-server.cpp index 023cbcf9c1a0cd..3945903b85d410 100644 --- a/src/app/clusters/actions-server/actions-server.cpp +++ b/src/app/clusters/actions-server/actions-server.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,35 @@ Instance * Instance::GetInstance() return &instance; } +void Instance::OnStateChanged(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState) +{ + ChipLogProgress(Zcl, "ActionsServer: OnStateChanged"); + + // Record StateChanged event + EventNumber eventNumber; + Events::StateChanged::Type event{ actionId, invokeId, actionState }; + + if (CHIP_NO_ERROR != LogEvent(event, endpoint, eventNumber)) + { + ChipLogError(Zcl, "ActionsServer: Failed to record OnStateChanged event"); + } +} + +void Instance::OnActionFailed(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState, + ActionErrorEnum actionError) +{ + ChipLogProgress(Zcl, "ActionsServer: OnActionFailed"); + + // Record ActionFailed event + EventNumber eventNumber; + Events::ActionFailed::Type event{ actionId, invokeId, actionState, actionError }; + + if (CHIP_NO_ERROR != LogEvent(event, endpoint, eventNumber)) + { + ChipLogError(Zcl, "ActionsServer: Failed to record OnActionFailed event"); + } +} + CHIP_ERROR Instance::ReadActionListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder) { if (GetInstance()->mDelegate == nullptr) @@ -47,7 +77,7 @@ CHIP_ERROR Instance::ReadActionListAttribute(const AttributeValueEncoder::ListEn } for (uint16_t i = 0; true; i++) { - Actions::Structs::ActionStruct::Type action; + GenericActionStruct action; CHIP_ERROR err = GetInstance()->mDelegate->ReadActionAtIndex(i, action); if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) @@ -69,7 +99,7 @@ CHIP_ERROR Instance::ReadEndpointListAttribute(const AttributeValueEncoder::List } for (uint16_t i = 0; true; i++) { - Actions::Structs::EndpointListStruct::Type epList; + GenericEndpointList epList; CHIP_ERROR err = GetInstance()->mDelegate->ReadEndpointListAtIndex(i, epList); if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h index f702069cfa68b7..d081bdfd6c44e0 100644 --- a/src/app/clusters/actions-server/actions-server.h +++ b/src/app/clusters/actions-server/actions-server.h @@ -27,8 +27,94 @@ namespace app { namespace Clusters { namespace Actions { +inline constexpr size_t kActionNameMaxSize = 128u; +inline constexpr size_t kEndpointListNameMaxSize = 128u; + class Delegate; +struct GenericActionStruct : public Structs::ActionStruct::Type +{ + GenericActionStruct(){}; + + GenericActionStruct(uint16_t action, CharSpan label, ActionTypeEnum actionType, uint16_t epListID, + BitMask commands, ActionStateEnum actionState) + { + Set(action, label, actionType, epListID, commands, actionState); + } + + GenericActionStruct(const GenericActionStruct & action) { *this = action; } + + GenericActionStruct & operator=(const GenericActionStruct & action) + { + Set(action.actionID, action.name, action.type, action.endpointListID, action.supportedCommands, action.state); + return *this; + } + + void Set(uint16_t action, CharSpan label, ActionTypeEnum actionType, uint16_t epListID, BitMask commands, + ActionStateEnum actionState) + { + actionID = action; + type = actionType; + endpointListID = epListID; + supportedCommands = commands; + state = actionState; + memset(mActionNameBuffer, 0, sizeof(mActionNameBuffer)); + if (label.size() > sizeof(mActionNameBuffer)) + { + memcpy(mActionNameBuffer, label.data(), sizeof(mActionNameBuffer)); + name = CharSpan(mActionNameBuffer, sizeof(mActionNameBuffer)); + } + else + { + memcpy(mActionNameBuffer, label.data(), label.size()); + name = CharSpan(mActionNameBuffer, label.size()); + } + } + +private: + char mActionNameBuffer[kActionNameMaxSize]; +}; + +struct GenericEndpointList : public Structs::EndpointListStruct::Type +{ + GenericEndpointList(){}; + + GenericEndpointList(uint16_t epListId, CharSpan label, EndpointListTypeEnum epListType, + DataModel::List endpointList) + { + Set(epListId, label, epListType, endpointList); + } + + GenericEndpointList(const GenericEndpointList & epList) { *this = epList; } + + GenericEndpointList & operator=(const GenericEndpointList & epList) + { + Set(epList.endpointListID, epList.name, epList.type, epList.endpoints); + return *this; + } + + void Set(uint16_t epListId, CharSpan label, EndpointListTypeEnum epListType, DataModel::List endpointList) + { + endpointListID = epListId; + type = epListType; + endpoints = endpointList; + memset(mEndpointListNameBuffer, 0, sizeof(mEndpointListNameBuffer)); + if (label.size() > sizeof(mEndpointListNameBuffer)) + { + memcpy(mEndpointListNameBuffer, label.data(), sizeof(mEndpointListNameBuffer)); + name = CharSpan(mEndpointListNameBuffer, sizeof(mEndpointListNameBuffer)); + } + else + { + memcpy(mEndpointListNameBuffer, label.data(), label.size()); + name = CharSpan(mEndpointListNameBuffer, label.size()); + } + } + +private: + char mEndpointListNameBuffer[kEndpointListNameMaxSize]; +}; + class Instance : public AttributeAccessInterface, public CommandHandlerInterface { public: @@ -38,6 +124,19 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface CommandHandlerInterface(Optional::Missing(), Actions::Id) {} + /** + * @brief + * Called when the state of action is changed. + */ + void OnStateChanged(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState); + + /** + * @brief + * Called when the action is failed.. + */ + void OnActionFailed(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState, + ActionErrorEnum actionError); + static Instance * GetInstance(); void SetDefaultDelegate(Delegate * aDelegate); @@ -82,26 +181,24 @@ class Delegate /** * Get the action at the Nth index from list of actions. * @param index The index of the action to be returned. It is assumed that actions are indexable from 0 and with no gaps. - * @param action A reference to the action struct which copies existing initialised buffer at index. + * @param action A reference to the GenericActionStruct which copies the buffer into it's own memory. * Name field (CharSpan) of ActionStruct contails the name of an action. - * The underlying data must remain allocated throughout the lifetime of the device, - * as the API does not make a copy. + * The API makes a copy of name. * @return Returns a CHIP_NO_ERROR if there was no error and the action was returned successfully. * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index in beyond the list of available actions. */ - virtual CHIP_ERROR ReadActionAtIndex(uint16_t index, Structs::ActionStruct::Type & action); + virtual CHIP_ERROR ReadActionAtIndex(uint16_t index, GenericActionStruct & action); /** * Get the EndpointList at the Nth index from list of endpointList. * @param index The index of the endpointList to be returned. It is assumed that actions are indexable from 0 and with no gaps. - * @param epList A reference to the endpointList struct which copies existing initialised buffer at index. - * Name field (CharSpan) of EndpointList contails the name of an endpointList. - * The underlying data must remain allocated throughout the lifetime of the device, - * as the API does not make a copy. + * @param epList A reference to the GenericEndpointList which copies the buffer into it's own memory. + * Name field (CharSpan) of EndpointList contails the name of an endpoint list. + * The API makes a copy of name. * @return Returns a CHIP_NO_ERROR if there was no error and the epList was returned successfully. * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index in beyond the list of available endpointList. */ - virtual CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, Structs::EndpointListStruct::Type & epList); + virtual CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, GenericEndpointList & epList); /** * Find the action with matching actionId in the list of action. From dda966779db301f833a50fe657fd33197ba95a3d Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Mon, 7 Oct 2024 17:27:26 +0530 Subject: [PATCH 09/15] Address review comments --- .../include/bridged-actions-stub.h | 22 +-- .../src/bridged-actions-stub.cpp | 10 +- examples/bridge-app/asr/BUILD.gn | 1 - .../asr/src/bridged-actions-stub.cpp | 101 ------------ .../asr/subdevice/SubDeviceManager.cpp | 8 - examples/bridge-app/linux/BUILD.gn | 8 + .../bridge-app/linux/bridged-actions-stub.cpp | 8 +- examples/bridge-app/telink/src/AppTask.cpp | 8 - .../bridge-app/telink/src/DeviceCallbacks.cpp | 105 ------------- examples/placeholder/linux/apps/app1/BUILD.gn | 1 - examples/placeholder/linux/apps/app2/BUILD.gn | 1 - .../linux/src/bridged-actions-stub.cpp | 102 ------------ .../actions-server/actions-server.cpp | 12 +- .../clusters/actions-server/actions-server.h | 148 +++++++++--------- 14 files changed, 103 insertions(+), 432 deletions(-) delete mode 100644 examples/bridge-app/asr/src/bridged-actions-stub.cpp delete mode 100644 examples/bridge-app/telink/src/DeviceCallbacks.cpp delete mode 100644 examples/placeholder/linux/src/bridged-actions-stub.cpp diff --git a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h index 91c9999d7cf90d..ca8b0e26d2004d 100644 --- a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h +++ b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h @@ -34,10 +34,10 @@ const uint16_t kEndpointListSize = 3; class ActionsDelegateImpl : public Delegate { private: - const GenericActionStruct kActionList[kActionListSize] = { - GenericActionStruct(0, CharSpan::fromCharString("TurnOnLight"), ActionTypeEnum::kScene, 0, 0, ActionStateEnum::kInactive), - GenericActionStruct(1, CharSpan::fromCharString("TurnOffLight"), ActionTypeEnum::kScene, 1, 0, ActionStateEnum::kInactive), - GenericActionStruct(2, CharSpan::fromCharString("ToggleLight"), ActionTypeEnum::kScene, 2, 0, ActionStateEnum::kInactive), + const ActionStructStorage kActionList[kActionListSize] = { + ActionStructStorage(0, CharSpan::fromCharString("TurnOnLight"), ActionTypeEnum::kScene, 0, 0, ActionStateEnum::kInactive), + ActionStructStorage(1, CharSpan::fromCharString("TurnOffLight"), ActionTypeEnum::kScene, 1, 0, ActionStateEnum::kInactive), + ActionStructStorage(2, CharSpan::fromCharString("ToggleLight"), ActionTypeEnum::kScene, 2, 0, ActionStateEnum::kInactive), }; // Dummy endpoint list. @@ -45,18 +45,18 @@ class ActionsDelegateImpl : public Delegate const EndpointId secondEpList[1] = { 0 }; const EndpointId thirdEpList[1] = { 0 }; - const GenericEndpointList kEndpointList[kEndpointListSize] = { - GenericEndpointList(0, CharSpan::fromCharString("On"), EndpointListTypeEnum::kOther, + const EndpointListStorage kEndpointList[kEndpointListSize] = { + EndpointListStorage(0, CharSpan::fromCharString("On"), EndpointListTypeEnum::kOther, DataModel::List(firstEpList)), - GenericEndpointList(1, CharSpan::fromCharString("Off"), EndpointListTypeEnum::kOther, + EndpointListStorage(1, CharSpan::fromCharString("Off"), EndpointListTypeEnum::kOther, DataModel::List(secondEpList)), - GenericEndpointList(2, CharSpan::fromCharString("Toggle"), EndpointListTypeEnum::kOther, + EndpointListStorage(2, CharSpan::fromCharString("Toggle"), EndpointListTypeEnum::kOther, DataModel::List(thirdEpList)), }; - CHIP_ERROR ReadActionAtIndex(uint16_t index, GenericActionStruct & action) override; - CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, GenericEndpointList & epList) override; - CHIP_ERROR FindActionIdInActionList(uint16_t actionId) override; + CHIP_ERROR ReadActionAtIndex(uint16_t index, ActionStructStorage & action) override; + CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList) override; + bool FindActionIdInActionList(uint16_t actionId) override; Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId) override; Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, diff --git a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp index e7f0dd701015b3..e5e7c98ae0d0c1 100644 --- a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp @@ -24,7 +24,7 @@ using namespace chip::app::Clusters::Actions; using namespace chip::app::Clusters::Actions::Attributes; using namespace chip::Protocols::InteractionModel; -CHIP_ERROR ActionsDelegateImpl::ReadActionAtIndex(uint16_t index, GenericActionStruct & action) +CHIP_ERROR ActionsDelegateImpl::ReadActionAtIndex(uint16_t index, ActionStructStorage & action) { if (index >= ArraySize(kActionList)) { @@ -34,7 +34,7 @@ CHIP_ERROR ActionsDelegateImpl::ReadActionAtIndex(uint16_t index, GenericActionS return CHIP_NO_ERROR; } -CHIP_ERROR ActionsDelegateImpl::ReadEndpointListAtIndex(uint16_t index, GenericEndpointList & epList) +CHIP_ERROR ActionsDelegateImpl::ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList) { if (index >= ArraySize(kEndpointList)) { @@ -44,14 +44,14 @@ CHIP_ERROR ActionsDelegateImpl::ReadEndpointListAtIndex(uint16_t index, GenericE return CHIP_NO_ERROR; } -CHIP_ERROR ActionsDelegateImpl::FindActionIdInActionList(uint16_t actionId) +bool ActionsDelegateImpl::FindActionIdInActionList(uint16_t actionId) { for (uint16_t i = 0; i < kActionListSize; i++) { if (kActionList[i].actionID == actionId) - return CHIP_NO_ERROR; + return true; } - return CHIP_ERROR_NOT_FOUND; + return false; } Status ActionsDelegateImpl::HandleInstantAction(uint16_t actionId, Optional invokeId) diff --git a/examples/bridge-app/asr/BUILD.gn b/examples/bridge-app/asr/BUILD.gn index 0fb9be4dcd99c4..19f8263e12bb7c 100755 --- a/examples/bridge-app/asr/BUILD.gn +++ b/examples/bridge-app/asr/BUILD.gn @@ -78,7 +78,6 @@ asr_executable("bridge_app") { "${examples_plat_dir}/shell/matter_shell.cpp", "src/AppTask.cpp", "src/DeviceCallbacks.cpp", - "src/bridged-actions-stub.cpp", "src/main.cpp", "subdevice/SubDevice.cpp", "subdevice/SubDeviceManager.cpp", diff --git a/examples/bridge-app/asr/src/bridged-actions-stub.cpp b/examples/bridge-app/asr/src/bridged-actions-stub.cpp deleted file mode 100644 index 84dca65f832107..00000000000000 --- a/examples/bridge-app/asr/src/bridged-actions-stub.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Copyright (c) 2021 Project CHIP Authors - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; -using namespace chip::app::Clusters::Actions::Attributes; - -namespace { - -class ActionsAttrAccess : public AttributeAccessInterface -{ -public: - // Register for the Actions cluster on all endpoints. - ActionsAttrAccess() : AttributeAccessInterface(Optional::Missing(), Actions::Id) {} - - CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; - -private: - static constexpr uint16_t ClusterRevision = 1; - - CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); -}; - -constexpr uint16_t ActionsAttrAccess::ClusterRevision; - -CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - static const char SetupUrl[] = "https://example.com"; - return aEncoder.Encode(chip::Span(SetupUrl, strlen(SetupUrl))); -} - -CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - return aEncoder.Encode(ClusterRevision); -} - -ActionsAttrAccess gAttrAccess; - -CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) -{ - VerifyOrDie(aPath.mClusterId == Actions::Id); - - switch (aPath.mAttributeId) - { - case ActionList::Id: - return ReadActionListAttribute(aPath.mEndpointId, aEncoder); - case EndpointLists::Id: - return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder); - case SetupURL::Id: - return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder); - case ClusterRevision::Id: - return ReadClusterRevision(aPath.mEndpointId, aEncoder); - default: - break; - } - return CHIP_NO_ERROR; -} -} // anonymous namespace - -// void MatterActionsPluginServerInitCallback(void) -//{ -// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -// } diff --git a/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp b/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp index 776c4e43490e04..9147d170cc4644 100644 --- a/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp +++ b/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp @@ -243,14 +243,6 @@ void HandleDeviceStatusChanged(SubDevice * dev, SubDevice::Changed_t itemChanged const EmberAfDeviceType gRootDeviceTypes[] = { { DEVICE_TYPE_ROOT_NODE, DEVICE_VERSION_DEFAULT } }; const EmberAfDeviceType gAggregateNodeDeviceTypes[] = { { DEVICE_TYPE_BRIDGE, DEVICE_VERSION_DEFAULT } }; -bool emberAfActionsClusterInstantActionCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, - const Actions::Commands::InstantAction::DecodableType & commandData) -{ - // No actions are implemented, just return status NotFound. - commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); - return true; -} - void Init_Bridge_Endpoint() { // bridge will have own database named gSubDevices. diff --git a/examples/bridge-app/linux/BUILD.gn b/examples/bridge-app/linux/BUILD.gn index 212fb9dd3a9264..42bdbe83f2ed1c 100644 --- a/examples/bridge-app/linux/BUILD.gn +++ b/examples/bridge-app/linux/BUILD.gn @@ -28,6 +28,14 @@ executable("chip-bridge-app") { "main.cpp", ] + # Generic implementation of the actions cluster is not introduced in this app as this app has + # an interface to test actions. + # TODO: Generic implementation can be used here instead of having its own. + excludes = [ "${chip_root}/src/app/clusters/actions-server/**" ] + + # Apply excludes to the sources + sources -= excludes + deps = [ "${chip_root}/examples/bridge-app/bridge-common", "${chip_root}/examples/platform/linux:app-main", diff --git a/examples/bridge-app/linux/bridged-actions-stub.cpp b/examples/bridge-app/linux/bridged-actions-stub.cpp index 0eff1e7b6d05bc..580f4f2239bd1a 100644 --- a/examples/bridge-app/linux/bridged-actions-stub.cpp +++ b/examples/bridge-app/linux/bridged-actions-stub.cpp @@ -131,7 +131,7 @@ CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, Attr } } // anonymous namespace -// void MatterActionsPluginServerInitCallback() -//{ -// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -// } +void MatterActionsPluginServerInitCallback() +{ + AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); +} diff --git a/examples/bridge-app/telink/src/AppTask.cpp b/examples/bridge-app/telink/src/AppTask.cpp index 79644c2860ae21..7c731ae5cc7f29 100644 --- a/examples/bridge-app/telink/src/AppTask.cpp +++ b/examples/bridge-app/telink/src/AppTask.cpp @@ -387,14 +387,6 @@ void HandleDeviceStatusChanged(Device * dev, Device::Changed_t itemChangedMask) } } -bool emberAfActionsClusterInstantActionCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, - const Clusters::Actions::Commands::InstantAction::DecodableType & commandData) -{ - // No actions are implemented, just return status NotFound. - commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); - return true; -} - CHIP_ERROR AppTask::Init(void) { SetExampleButtonCallbacks(LightingActionEventHandler); diff --git a/examples/bridge-app/telink/src/DeviceCallbacks.cpp b/examples/bridge-app/telink/src/DeviceCallbacks.cpp deleted file mode 100644 index 8511d7047dfb0a..00000000000000 --- a/examples/bridge-app/telink/src/DeviceCallbacks.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Copyright (c) 2023 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 -#include -#include -#include -#include -#include -#include -#include - -using namespace ::chip; -using namespace ::chip::app; -using namespace ::chip::app::Clusters; -using namespace ::chip::app::Clusters::Actions::Attributes; -using namespace ::chip::Inet; -using namespace ::chip::System; - -namespace { - -class ActionsAttrAccess : public AttributeAccessInterface -{ -public: - // Register for the Actions cluster on all endpoints. - ActionsAttrAccess() : AttributeAccessInterface(Optional::Missing(), Actions::Id) {} - - CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; - -private: - static constexpr uint16_t ClusterRevision = 1; - - CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); -}; - -constexpr uint16_t ActionsAttrAccess::ClusterRevision; - -CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - static const char SetupUrl[] = "https://example.com"; - return aEncoder.Encode(chip::CharSpan::fromCharString(SetupUrl)); -} - -CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - return aEncoder.Encode(ClusterRevision); -} - -ActionsAttrAccess gAttrAccess; - -CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) -{ - VerifyOrDie(aPath.mClusterId == Actions::Id); - - switch (aPath.mAttributeId) - { - case ActionList::Id: - return ReadActionListAttribute(aPath.mEndpointId, aEncoder); - case EndpointLists::Id: - return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder); - case SetupURL::Id: - return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder); - case ClusterRevision::Id: - return ReadClusterRevision(aPath.mEndpointId, aEncoder); - default: - break; - } - return CHIP_NO_ERROR; -} -} // anonymous namespace - -// void MatterActionsPluginServerInitCallback(void) -//{ -// AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -// } diff --git a/examples/placeholder/linux/apps/app1/BUILD.gn b/examples/placeholder/linux/apps/app1/BUILD.gn index aba1e870f7a041..f8cc1b36a2b0ee 100644 --- a/examples/placeholder/linux/apps/app1/BUILD.gn +++ b/examples/placeholder/linux/apps/app1/BUILD.gn @@ -28,7 +28,6 @@ source_set("app1") { sources = [ "../../resource-monitoring-delegates.cpp", - "../../src/bridged-actions-stub.cpp", "../../static-supported-modes-manager.cpp", "../../thread-border-router-management.cpp", ] diff --git a/examples/placeholder/linux/apps/app2/BUILD.gn b/examples/placeholder/linux/apps/app2/BUILD.gn index 2bea36611ffb37..302054f5bf927b 100644 --- a/examples/placeholder/linux/apps/app2/BUILD.gn +++ b/examples/placeholder/linux/apps/app2/BUILD.gn @@ -28,7 +28,6 @@ source_set("app2") { sources = [ "../../resource-monitoring-delegates.cpp", - "../../src/bridged-actions-stub.cpp", "../../static-supported-modes-manager.cpp", ] diff --git a/examples/placeholder/linux/src/bridged-actions-stub.cpp b/examples/placeholder/linux/src/bridged-actions-stub.cpp deleted file mode 100644 index ad934cc881077c..00000000000000 --- a/examples/placeholder/linux/src/bridged-actions-stub.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Copyright (c) 2021 Project CHIP Authors - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; -using namespace chip::app::Clusters::Actions::Attributes; - -namespace { - -class ActionsAttrAccess : public AttributeAccessInterface -{ -public: - // Register for the Actions cluster on all endpoints. - ActionsAttrAccess() : AttributeAccessInterface(Optional::Missing(), Actions::Id) {} - - CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; - -private: - static constexpr uint16_t ClusterRevision = 1; - - CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); -}; - -constexpr uint16_t ActionsAttrAccess::ClusterRevision; - -CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - static const char SetupUrl[] = "https://example.com"; - return aEncoder.Encode(chip::Span(SetupUrl, strlen(SetupUrl))); -} - -CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - return aEncoder.Encode(ClusterRevision); -} - -ActionsAttrAccess gAttrAccess; - -CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) -{ - VerifyOrDie(aPath.mClusterId == Actions::Id); - - switch (aPath.mAttributeId) - { - case ActionList::Id: - return ReadActionListAttribute(aPath.mEndpointId, aEncoder); - case EndpointLists::Id: - return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder); - case SetupURL::Id: - return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder); - case ClusterRevision::Id: - return ReadClusterRevision(aPath.mEndpointId, aEncoder); - default: - break; - } - return CHIP_NO_ERROR; -} -} // anonymous namespace - -// void MatterActionsPluginServerInitCallback(void) -//{ -// chip::app::AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -// } diff --git a/src/app/clusters/actions-server/actions-server.cpp b/src/app/clusters/actions-server/actions-server.cpp index 3945903b85d410..543e4e6aa078b7 100644 --- a/src/app/clusters/actions-server/actions-server.cpp +++ b/src/app/clusters/actions-server/actions-server.cpp @@ -16,7 +16,6 @@ */ #include "actions-server.h" -#include #include #include #include @@ -77,7 +76,7 @@ CHIP_ERROR Instance::ReadActionListAttribute(const AttributeValueEncoder::ListEn } for (uint16_t i = 0; true; i++) { - GenericActionStruct action; + ActionStructStorage action; CHIP_ERROR err = GetInstance()->mDelegate->ReadActionAtIndex(i, action); if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) @@ -99,7 +98,7 @@ CHIP_ERROR Instance::ReadEndpointListAttribute(const AttributeValueEncoder::List } for (uint16_t i = 0; true; i++) { - GenericEndpointList epList; + EndpointListStorage epList; CHIP_ERROR err = GetInstance()->mDelegate->ReadEndpointListAtIndex(i, epList); if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) @@ -146,12 +145,12 @@ CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValu return CHIP_NO_ERROR; } -CHIP_ERROR Instance::FindActionIdInActionList(uint16_t actionId) +bool Instance::FindActionIdInActionList(uint16_t actionId) { if (GetInstance()->mDelegate == nullptr) { ChipLogError(Zcl, "Actions delegate is null!!!"); - return CHIP_ERROR_INCORRECT_STATE; + return false; } return GetInstance()->mDelegate->FindActionIdInActionList(actionId); } @@ -178,8 +177,7 @@ void Instance::HandleCommand(HandlerContext & handlerContext, FuncT func) } uint16_t actionId = requestPayload.actionID; - CHIP_ERROR err = GetInstance()->FindActionIdInActionList(actionId); - if (err != CHIP_NO_ERROR) + if (!GetInstance()->FindActionIdInActionList(actionId)) { handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Protocols::InteractionModel::Status::NotFound); return; diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h index d081bdfd6c44e0..ba30566a1e3101 100644 --- a/src/app/clusters/actions-server/actions-server.h +++ b/src/app/clusters/actions-server/actions-server.h @@ -21,36 +21,39 @@ #include #include #include +#include namespace chip { namespace app { namespace Clusters { namespace Actions { -inline constexpr size_t kActionNameMaxSize = 128u; -inline constexpr size_t kEndpointListNameMaxSize = 128u; +static constexpr size_t kActionNameMaxSize = 128u; +static constexpr size_t kEndpointListNameMaxSize = 128u; +static constexpr size_t kEndpointListMaxSize = 256u; class Delegate; -struct GenericActionStruct : public Structs::ActionStruct::Type +struct ActionStructStorage : public Structs::ActionStruct::Type { - GenericActionStruct(){}; + ActionStructStorage() : mActionName(mBuffer, sizeof(mBuffer)){}; - GenericActionStruct(uint16_t action, CharSpan label, ActionTypeEnum actionType, uint16_t epListID, - BitMask commands, ActionStateEnum actionState) + ActionStructStorage(uint16_t action, CharSpan actionName, ActionTypeEnum actionType, uint16_t epListID, + BitMask commands, ActionStateEnum actionState) : + mActionName(mBuffer, sizeof(mBuffer)) { - Set(action, label, actionType, epListID, commands, actionState); + Set(action, actionName, actionType, epListID, commands, actionState); } - GenericActionStruct(const GenericActionStruct & action) { *this = action; } + ActionStructStorage(const ActionStructStorage & action) : mActionName(mBuffer, sizeof(mBuffer)) { *this = action; } - GenericActionStruct & operator=(const GenericActionStruct & action) + ActionStructStorage & operator=(const ActionStructStorage & action) { Set(action.actionID, action.name, action.type, action.endpointListID, action.supportedCommands, action.state); return *this; } - void Set(uint16_t action, CharSpan label, ActionTypeEnum actionType, uint16_t epListID, BitMask commands, + void Set(uint16_t action, CharSpan actionName, ActionTypeEnum actionType, uint16_t epListID, BitMask commands, ActionStateEnum actionState) { actionID = action; @@ -58,61 +61,55 @@ struct GenericActionStruct : public Structs::ActionStruct::Type endpointListID = epListID; supportedCommands = commands; state = actionState; - memset(mActionNameBuffer, 0, sizeof(mActionNameBuffer)); - if (label.size() > sizeof(mActionNameBuffer)) - { - memcpy(mActionNameBuffer, label.data(), sizeof(mActionNameBuffer)); - name = CharSpan(mActionNameBuffer, sizeof(mActionNameBuffer)); - } - else - { - memcpy(mActionNameBuffer, label.data(), label.size()); - name = CharSpan(mActionNameBuffer, label.size()); - } + CopyCharSpanToMutableCharSpanWithTruncation(actionName, mActionName); + name = mActionName; } private: - char mActionNameBuffer[kActionNameMaxSize]; + char mBuffer[kActionNameMaxSize]; + MutableCharSpan mActionName; }; -struct GenericEndpointList : public Structs::EndpointListStruct::Type +struct EndpointListStorage : public Structs::EndpointListStruct::Type { - GenericEndpointList(){}; + EndpointListStorage() : mEpListName(mBuffer, sizeof(mBuffer)){}; - GenericEndpointList(uint16_t epListId, CharSpan label, EndpointListTypeEnum epListType, - DataModel::List endpointList) + EndpointListStorage(uint16_t epListId, CharSpan epListName, EndpointListTypeEnum epListType, + DataModel::List endpointList) : + mEpListName(mBuffer, sizeof(mBuffer)) { - Set(epListId, label, epListType, endpointList); + Set(epListId, epListName, epListType, endpointList); } - GenericEndpointList(const GenericEndpointList & epList) { *this = epList; } + EndpointListStorage(const EndpointListStorage & epList) : mEpListName(mBuffer, sizeof(mBuffer)) { *this = epList; } - GenericEndpointList & operator=(const GenericEndpointList & epList) + EndpointListStorage & operator=(const EndpointListStorage & epList) { Set(epList.endpointListID, epList.name, epList.type, epList.endpoints); return *this; } - void Set(uint16_t epListId, CharSpan label, EndpointListTypeEnum epListType, DataModel::List endpointList) + void Set(uint16_t epListId, CharSpan epListName, EndpointListTypeEnum epListType, + DataModel::List endpointList) { endpointListID = epListId; type = epListType; - endpoints = endpointList; - memset(mEndpointListNameBuffer, 0, sizeof(mEndpointListNameBuffer)); - if (label.size() > sizeof(mEndpointListNameBuffer)) - { - memcpy(mEndpointListNameBuffer, label.data(), sizeof(mEndpointListNameBuffer)); - name = CharSpan(mEndpointListNameBuffer, sizeof(mEndpointListNameBuffer)); - } - else + + for (uint8_t index = 0; index < std::min(endpointList.size(), kEndpointListMaxSize); index++) { - memcpy(mEndpointListNameBuffer, label.data(), label.size()); - name = CharSpan(mEndpointListNameBuffer, label.size()); + mEpList.push_back(endpointList[index]); } + mEpListSpan = Span(mEpList.data(), mEpList.size()); + endpoints = DataModel::List(mEpListSpan); + CopyCharSpanToMutableCharSpanWithTruncation(epListName, mEpListName); + name = mEpListName; } private: - char mEndpointListNameBuffer[kEndpointListNameMaxSize]; + char mBuffer[kEndpointListNameMaxSize]; + MutableCharSpan mEpListName; + std::vector mEpList; + Span mEpListSpan; }; class Instance : public AttributeAccessInterface, public CommandHandlerInterface @@ -148,7 +145,7 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface CHIP_ERROR ReadActionListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder); CHIP_ERROR ReadEndpointListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder); - CHIP_ERROR FindActionIdInActionList(uint16_t actionId); + bool FindActionIdInActionList(uint16_t actionId); // CommandHandlerInterface template @@ -181,35 +178,30 @@ class Delegate /** * Get the action at the Nth index from list of actions. * @param index The index of the action to be returned. It is assumed that actions are indexable from 0 and with no gaps. - * @param action A reference to the GenericActionStruct which copies the buffer into it's own memory. - * Name field (CharSpan) of ActionStruct contails the name of an action. - * The API makes a copy of name. + * @param action A reference to the ActionStructStorage which should be initialized via copy/assignments or calling Set(). * @return Returns a CHIP_NO_ERROR if there was no error and the action was returned successfully. * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index in beyond the list of available actions. */ - virtual CHIP_ERROR ReadActionAtIndex(uint16_t index, GenericActionStruct & action); + virtual CHIP_ERROR ReadActionAtIndex(uint16_t index, ActionStructStorage & action) = 0; /** * Get the EndpointList at the Nth index from list of endpointList. * @param index The index of the endpointList to be returned. It is assumed that actions are indexable from 0 and with no gaps. - * @param epList A reference to the GenericEndpointList which copies the buffer into it's own memory. - * Name field (CharSpan) of EndpointList contails the name of an endpoint list. - * The API makes a copy of name. + * @param action A reference to the EndpointListStorage which should be initialized via copy/assignments or calling Set(). * @return Returns a CHIP_NO_ERROR if there was no error and the epList was returned successfully. * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index in beyond the list of available endpointList. */ - virtual CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, GenericEndpointList & epList); + virtual CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList) = 0; /** * Find the action with matching actionId in the list of action. * @param actionId The action to be find in the list of action. - * @return Returns a CHIP_NO_ERROR if matching action is found. - * CHIP_ERROR_NOT_FOUND if the matching action does not found in the list of action. + * @return Returns a true if matching action is found otherwise false. */ - virtual CHIP_ERROR FindActionIdInActionList(uint16_t actionId); + virtual bool FindActionIdInActionList(uint16_t actionId) = 0; /** - * On reciept of each and every command, + * On receipt of each and every command, * if the InvokeID data field is provided by the client when invoking a command, the server SHALL generate a StateChanged event * when the action changes to a new state or an ActionFailed event when execution of the action fails. * @@ -218,16 +210,16 @@ class Delegate */ /** - * When an InstantAction command is recieved, an action (state change) on the involved endpoints shall trigger, + * When an InstantAction command is received, an action (state change) on the involved endpoints shall trigger, * in a "fire and forget" manner. Afterwards, the action’s state SHALL be Inactive. * * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId) = 0; /** - * When an InstantActionWithTransition command is recieved, an action (state change) on the involved endpoints shall trigger, + * When an InstantActionWithTransition command is received, an action (state change) on the involved endpoints shall trigger, * with a specified time to transition from the current state to the new state. During the transition, the action’s state SHALL * be Active. Afterwards, the action’s state SHALL be Inactive. * @@ -236,19 +228,19 @@ class Delegate * @return Returns a Success if an action took place successfully otherwise, suitable error. */ virtual Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, - Optional invokeId); + Optional invokeId) = 0; /** - * When a StartAction command is recieved, the commencement of an action on the involved endpoints shall trigger. Afterwards, + * When a StartAction command is received, the commencement of an action on the involved endpoints shall trigger. Afterwards, * the action’s state SHALL be Inactive. * * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandleStartAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleStartAction(uint16_t actionId, Optional invokeId) = 0; /** - * When a StartActionWithDuration command is recieved, the commencement of an action on the involved endpoints shall trigger, + * When a StartActionWithDuration command is received, the commencement of an action on the involved endpoints shall trigger, * and SHALL change the action’s state to Active. After the specified Duration, the action will stop, and the action’s state * SHALL change to Inactive. * @@ -257,28 +249,28 @@ class Delegate * @return Returns a Success if an action took place successfully otherwise, suitable error. */ virtual Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, - Optional invokeId); + Optional invokeId) = 0; /** - * When a StopAction command is recieved, the ongoing action on the involved endpoints shall stop. Afterwards, the action’s + * When a StopAction command is received, the ongoing action on the involved endpoints shall stop. Afterwards, the action’s * state SHALL be Inactive. * * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandleStopAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleStopAction(uint16_t actionId, Optional invokeId) = 0; /** - * When a PauseAction command is recieved, the ongoing action on the involved endpoints shall pause and SHALL change the + * When a PauseAction command is received, the ongoing action on the involved endpoints shall pause and SHALL change the * action’s state to Paused. * * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandlePauseAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandlePauseAction(uint16_t actionId, Optional invokeId) = 0; /** - * When a PauseActionWithDuration command is recieved, pauses an ongoing action, and SHALL change the action’s state to Paused. + * When a PauseActionWithDuration command is received, pauses an ongoing action, and SHALL change the action’s state to Paused. * After the specified Duration, the ongoing action will be automatically resumed. which SHALL change the action’s state to * Active. * @@ -287,28 +279,28 @@ class Delegate * @return Returns a Success if an action took place successfully otherwise, suitable error. */ virtual Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, - Optional invokeId); + Optional invokeId) = 0; /** - * When a ResumeAction command is recieved, the previously paused action shall resume and SHALL change the action’s state to + * When a ResumeAction command is received, the previously paused action shall resume and SHALL change the action’s state to * Active. * * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandleResumeAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleResumeAction(uint16_t actionId, Optional invokeId) = 0; /** - * When an EnableAction command is recieved, it enables a certain action or automation. Afterwards, the action’s state SHALL be + * When an EnableAction command is received, it enables a certain action or automation. Afterwards, the action’s state SHALL be * Active. * * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandleEnableAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleEnableAction(uint16_t actionId, Optional invokeId) = 0; /** - * When an EnableActionWithDuration command is recieved, it enables a certain action or automation, and SHALL change the + * When an EnableActionWithDuration command is received, it enables a certain action or automation, and SHALL change the * action’s state to be Active. After the specified Duration, the action or automation will stop, and the action’s state SHALL * change to Disabled. * @@ -317,19 +309,19 @@ class Delegate * @return Returns a Success if an action took place successfully otherwise, suitable error. */ virtual Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, - Optional invokeId); + Optional invokeId) = 0; /** - * When a DisableAction command is recieved, it disables a certain action or automation, and SHALL change the action’s state to + * When a DisableAction command is received, it disables a certain action or automation, and SHALL change the action’s state to * Inactive. * * @param actionId The id of an action on which an action shall takes place. * @return Returns a Success if an action took place successfully otherwise, suitable error. */ - virtual Protocols::InteractionModel::Status HandleDisableAction(uint16_t actionId, Optional invokeId); + virtual Protocols::InteractionModel::Status HandleDisableAction(uint16_t actionId, Optional invokeId) = 0; /** - * When a DisableActionWithDuration command is recieved, it disables a certain action or automation, and SHALL change the + * When a DisableActionWithDuration command is received, it disables a certain action or automation, and SHALL change the * action’s state to Disabled. After the specified Duration, the action or automation will re-start, and the action’s state * SHALL change to either Inactive or Active, depending on the actions. * @@ -338,7 +330,7 @@ class Delegate * @return Returns a Success if an action took place successfully otherwise, suitable error. */ virtual Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, - Optional invokeId); + Optional invokeId) = 0; }; } // namespace Actions From 52edac18c12fd34a25ff0f72878c6fb6318398b0 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Thu, 10 Oct 2024 13:30:22 +0530 Subject: [PATCH 10/15] Fix CI and apps should use emberAfActionsClusterInitCallback instead of MatterActionsPluginServerInitCallback in example --- .../esp32/sdkconfig_m5stack.defaults | 6 ++++++ .../esp32/sdkconfig_m5stack_rpc.defaults | 6 ++++++ examples/bridge-app/linux/BUILD.gn | 8 -------- examples/bridge-app/linux/bridged-actions-stub.cpp | 2 +- examples/bridge-app/telink/CMakeLists.txt | 1 - 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack.defaults b/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack.defaults index 287262d17e57cc..03691548ea91db 100644 --- a/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack.defaults +++ b/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack.defaults @@ -73,3 +73,9 @@ CONFIG_BUILD_CHIP_TESTS=y # Move functions from IRAM to flash CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y + +# Reduce the event logging buffer to reduce the DRAM usage +# TODO: [ESP32] Fix the DRAM overflow in esp32 apps #34717 +CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=512 +CONFIG_EVENT_LOGGING_INFO_BUFFER_SIZE=512 +CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE=512 diff --git a/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack_rpc.defaults b/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack_rpc.defaults index d2eaffb9bfd15b..6c4907410a1c22 100644 --- a/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack_rpc.defaults +++ b/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack_rpc.defaults @@ -88,3 +88,9 @@ CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=1024 CONFIG_DIAG_USE_EXTERNAL_LOG_WRAP=y + +# Reduce the event logging buffer to reduce the DRAM usage +# TODO: [ESP32] Fix the DRAM overflow in esp32 apps #34717 +CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=512 +CONFIG_EVENT_LOGGING_INFO_BUFFER_SIZE=512 +CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE=512 diff --git a/examples/bridge-app/linux/BUILD.gn b/examples/bridge-app/linux/BUILD.gn index 42bdbe83f2ed1c..212fb9dd3a9264 100644 --- a/examples/bridge-app/linux/BUILD.gn +++ b/examples/bridge-app/linux/BUILD.gn @@ -28,14 +28,6 @@ executable("chip-bridge-app") { "main.cpp", ] - # Generic implementation of the actions cluster is not introduced in this app as this app has - # an interface to test actions. - # TODO: Generic implementation can be used here instead of having its own. - excludes = [ "${chip_root}/src/app/clusters/actions-server/**" ] - - # Apply excludes to the sources - sources -= excludes - deps = [ "${chip_root}/examples/bridge-app/bridge-common", "${chip_root}/examples/platform/linux:app-main", diff --git a/examples/bridge-app/linux/bridged-actions-stub.cpp b/examples/bridge-app/linux/bridged-actions-stub.cpp index 580f4f2239bd1a..f5224199a03336 100644 --- a/examples/bridge-app/linux/bridged-actions-stub.cpp +++ b/examples/bridge-app/linux/bridged-actions-stub.cpp @@ -131,7 +131,7 @@ CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, Attr } } // anonymous namespace -void MatterActionsPluginServerInitCallback() +void emberAfActionsClusterInitCallback() { AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); } diff --git a/examples/bridge-app/telink/CMakeLists.txt b/examples/bridge-app/telink/CMakeLists.txt index f2e80864d46e01..e7984bc1332853 100644 --- a/examples/bridge-app/telink/CMakeLists.txt +++ b/examples/bridge-app/telink/CMakeLists.txt @@ -38,7 +38,6 @@ target_include_directories(app PRIVATE target_sources(app PRIVATE src/AppTask.cpp src/Device.cpp - src/DeviceCallbacks.cpp ${TELINK_COMMON}/common/src/mainCommon.cpp ${TELINK_COMMON}/common/src/AppTaskCommon.cpp ${TELINK_COMMON}/util/src/LEDManager.cpp From dc58d1d7f4a4b4af969905cd01b9f3421e7ff139 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Sun, 20 Oct 2024 18:08:41 +0530 Subject: [PATCH 11/15] Try to fix CI --- examples/all-clusters-app/esp32/main/main.cpp | 3 --- examples/all-clusters-app/linux/main-common.cpp | 7 +++++++ scripts/tools/check_includes_config.py | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/all-clusters-app/esp32/main/main.cpp b/examples/all-clusters-app/esp32/main/main.cpp index 494afd5b48e774..2753282298b382 100644 --- a/examples/all-clusters-app/esp32/main/main.cpp +++ b/examples/all-clusters-app/esp32/main/main.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -97,7 +96,6 @@ AppCallbacks sCallbacks; app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; -app::Clusters::Actions::ActionsDelegateImpl sActionsDelegateImpl; constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; @@ -128,7 +126,6 @@ static void InitServer(intptr_t context) app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); - app::Clusters::Actions::Instance::GetInstance()->SetDefaultDelegate(&sActionsDelegateImpl); } #include diff --git a/examples/all-clusters-app/linux/main-common.cpp b/examples/all-clusters-app/linux/main-common.cpp index 22170885db1cbe..8b46e612e17494 100644 --- a/examples/all-clusters-app/linux/main-common.cpp +++ b/examples/all-clusters-app/linux/main-common.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,7 @@ Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupporte Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; Clusters::ValveConfigurationAndControl::ValveControlDelegate sValveDelegate; Clusters::TimeSynchronization::ExtendedTimeSyncDelegate sTimeSyncDelegate; +Clusters::Actions::ActionsDelegateImpl sActionsDelegateImpl; // Please refer to https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/namespaces constexpr const uint8_t kNamespaceCommon = 7; @@ -341,6 +343,11 @@ void emberAfThermostatClusterInitCallback(EndpointId endpoint) SetDefaultDelegate(endpoint, &delegate); } +void emberAfActionsClusterInitCallback(EndpointId endpoint) +{ + Clusters::Actions::Instance::GetInstance()->SetDefaultDelegate(&sActionsDelegateImpl); +} + Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, uint16_t maxReadLength) diff --git a/scripts/tools/check_includes_config.py b/scripts/tools/check_includes_config.py index a7da891ea59c12..e7d165a20d384c 100644 --- a/scripts/tools/check_includes_config.py +++ b/scripts/tools/check_includes_config.py @@ -128,6 +128,7 @@ 'src/app/clusters/application-launcher-server/application-launcher-server.cpp': {'string'}, 'src/app/clusters/application-launcher-server/application-launcher-delegate.h': {'list'}, 'src/app/clusters/audio-output-server/audio-output-delegate.h': {'list'}, + 'src/app/clusters/actions-server/actions-server.h': {'vector'}, # EcosystemInformationCluster is for Fabric Sync and is intended to run on device that are capable of handling these types. 'src/app/clusters/ecosystem-information-server/ecosystem-information-server.h': {'map', 'string', 'vector'}, 'src/app/clusters/channel-server/channel-delegate.h': {'list'}, From 0960f7e2fb9a5ab2a246b838f2bd88ad43c930ea Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Thu, 19 Dec 2024 12:59:46 +0530 Subject: [PATCH 12/15] Address review changes --- src/app/clusters/actions-server/actions-server.cpp | 12 ++++-------- src/app/clusters/actions-server/actions-server.h | 2 ++ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/app/clusters/actions-server/actions-server.cpp b/src/app/clusters/actions-server/actions-server.cpp index 543e4e6aa078b7..766fcda7bd9ade 100644 --- a/src/app/clusters/actions-server/actions-server.cpp +++ b/src/app/clusters/actions-server/actions-server.cpp @@ -74,7 +74,7 @@ CHIP_ERROR Instance::ReadActionListAttribute(const AttributeValueEncoder::ListEn ChipLogError(Zcl, "Actions delegate is null!!!"); return CHIP_ERROR_INCORRECT_STATE; } - for (uint16_t i = 0; true; i++) + for (uint16_t i = 0; i <= kMaxActionList; i++) { ActionStructStorage action; @@ -96,7 +96,7 @@ CHIP_ERROR Instance::ReadEndpointListAttribute(const AttributeValueEncoder::List ChipLogError(Zcl, "Actions delegate is null!!!"); return CHIP_ERROR_INCORRECT_STATE; } - for (uint16_t i = 0; true; i++) + for (uint16_t i = 0; i <= kMaxEndpointList; i++) { EndpointListStorage epList; @@ -129,15 +129,11 @@ CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValu { case ActionList::Id: { Instance * d = this; - CHIP_ERROR err = - aEncoder.EncodeList([d](const auto & encoder) -> CHIP_ERROR { return d->ReadActionListAttribute(encoder); }); - return err; + return aEncoder.EncodeList([d](const auto & encoder) -> CHIP_ERROR { return d->ReadActionListAttribute(encoder); }); } case EndpointLists::Id: { Instance * d = this; - CHIP_ERROR err = - aEncoder.EncodeList([d](const auto & encoder) -> CHIP_ERROR { return d->ReadEndpointListAttribute(encoder); }); - return err; + return aEncoder.EncodeList([d](const auto & encoder) -> CHIP_ERROR { return d->ReadEndpointListAttribute(encoder); }); } default: break; diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h index ba30566a1e3101..0c20ef0b041e5c 100644 --- a/src/app/clusters/actions-server/actions-server.h +++ b/src/app/clusters/actions-server/actions-server.h @@ -140,6 +140,8 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface private: Delegate * mDelegate; static Instance instance; + static constexpr size_t kMaxEndpointList = 256u; + static constexpr size_t kMaxActionList = 256u; CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; From 092ab7f384ea09e2ebcfa63cbd163805d6e06d99 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Fri, 20 Dec 2024 17:46:40 +0530 Subject: [PATCH 13/15] Change implementation to accomodate actions server on multiple endpoints. --- .../src/bridged-actions-stub.cpp | 2 +- .../all-clusters-app/linux/main-common.cpp | 2 +- .../actions-server/actions-server.cpp | 173 +++++++++++------- .../clusters/actions-server/actions-server.h | 49 ++--- 4 files changed, 129 insertions(+), 97 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp index e5e7c98ae0d0c1..f59efbe24b2a59 100644 --- a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2024 Project CHIP Authors + * Copyright (c) 2021-2024 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/examples/all-clusters-app/linux/main-common.cpp b/examples/all-clusters-app/linux/main-common.cpp index 8b46e612e17494..64010d11f39a8b 100644 --- a/examples/all-clusters-app/linux/main-common.cpp +++ b/examples/all-clusters-app/linux/main-common.cpp @@ -345,7 +345,7 @@ void emberAfThermostatClusterInitCallback(EndpointId endpoint) void emberAfActionsClusterInitCallback(EndpointId endpoint) { - Clusters::Actions::Instance::GetInstance()->SetDefaultDelegate(&sActionsDelegateImpl); + Clusters::Actions::ActionsServer::SetDefaultDelegate(endpoint, &sActionsDelegateImpl); } Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, diff --git a/src/app/clusters/actions-server/actions-server.cpp b/src/app/clusters/actions-server/actions-server.cpp index 766fcda7bd9ade..ec20bdf038ab96 100644 --- a/src/app/clusters/actions-server/actions-server.cpp +++ b/src/app/clusters/actions-server/actions-server.cpp @@ -32,53 +32,80 @@ using namespace chip::app::Clusters::Actions; using namespace chip::app::Clusters::Actions::Attributes; using namespace chip::Protocols::InteractionModel; -Instance Instance::instance; -Instance * Instance::GetInstance() +static constexpr size_t kActionsDelegateTableSize = + MATTER_DM_ACTIONS_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; + +namespace { +Delegate * gDelegateTable[kActionsDelegateTableSize] = { nullptr }; + +Delegate * GetDelegate(EndpointId endpoint) +{ + uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, Actions::Id, MATTER_DM_ACTIONS_CLUSTER_SERVER_ENDPOINT_COUNT); + return (ep >= kActionsDelegateTableSize ? nullptr : gDelegateTable[ep]); +} + +} // namespace + +ActionsServer ActionsServer::sInstance; + +void ActionsServer::SetDefaultDelegate(EndpointId endpoint, Delegate * delegate) +{ + uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, Actions::Id, MATTER_DM_ACTIONS_CLUSTER_SERVER_ENDPOINT_COUNT); + // if endpoint is found + if (ep < kActionsDelegateTableSize) + { + gDelegateTable[ep] = delegate; + } +} + +ActionsServer & ActionsServer::Instance() { - return &instance; + return sInstance; } -void Instance::OnStateChanged(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState) +void ActionsServer::OnStateChanged(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState) { ChipLogProgress(Zcl, "ActionsServer: OnStateChanged"); - // Record StateChanged event + // Generate StateChanged event EventNumber eventNumber; Events::StateChanged::Type event{ actionId, invokeId, actionState }; if (CHIP_NO_ERROR != LogEvent(event, endpoint, eventNumber)) { - ChipLogError(Zcl, "ActionsServer: Failed to record OnStateChanged event"); + ChipLogError(Zcl, "ActionsServer: Failed to generate OnStateChanged event"); } } -void Instance::OnActionFailed(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState, - ActionErrorEnum actionError) +void ActionsServer::OnActionFailed(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState, + ActionErrorEnum actionError) { ChipLogProgress(Zcl, "ActionsServer: OnActionFailed"); - // Record ActionFailed event + // Generate ActionFailed event EventNumber eventNumber; Events::ActionFailed::Type event{ actionId, invokeId, actionState, actionError }; if (CHIP_NO_ERROR != LogEvent(event, endpoint, eventNumber)) { - ChipLogError(Zcl, "ActionsServer: Failed to record OnActionFailed event"); + ChipLogError(Zcl, "ActionsServer: Failed to generate OnActionFailed event"); } } -CHIP_ERROR Instance::ReadActionListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder) +CHIP_ERROR ActionsServer::ReadActionListAttribute(const ConcreteReadAttributePath & aPath, + const AttributeValueEncoder::ListEncodeHelper & encoder) { - if (GetInstance()->mDelegate == nullptr) + Delegate * delegate = GetDelegate(aPath.mEndpointId); + if (delegate == nullptr) { ChipLogError(Zcl, "Actions delegate is null!!!"); return CHIP_ERROR_INCORRECT_STATE; } - for (uint16_t i = 0; i <= kMaxActionList; i++) + for (uint16_t i = 0; i <= kMaxActionListLength; i++) { ActionStructStorage action; - CHIP_ERROR err = GetInstance()->mDelegate->ReadActionAtIndex(i, action); + CHIP_ERROR err = delegate->ReadActionAtIndex(i, action); if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) { return CHIP_NO_ERROR; @@ -89,18 +116,20 @@ CHIP_ERROR Instance::ReadActionListAttribute(const AttributeValueEncoder::ListEn return CHIP_NO_ERROR; } -CHIP_ERROR Instance::ReadEndpointListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder) +CHIP_ERROR ActionsServer::ReadEndpointListAttribute(const ConcreteReadAttributePath & aPath, + const AttributeValueEncoder::ListEncodeHelper & encoder) { - if (GetInstance()->mDelegate == nullptr) + Delegate * delegate = GetDelegate(aPath.mEndpointId); + if (delegate == nullptr) { ChipLogError(Zcl, "Actions delegate is null!!!"); return CHIP_ERROR_INCORRECT_STATE; } - for (uint16_t i = 0; i <= kMaxEndpointList; i++) + for (uint16_t i = 0; i <= kMaxEndpointListLength; i++) { EndpointListStorage epList; - CHIP_ERROR err = GetInstance()->mDelegate->ReadEndpointListAtIndex(i, epList); + CHIP_ERROR err = delegate->ReadEndpointListAtIndex(i, epList); if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) { return CHIP_NO_ERROR; @@ -111,29 +140,19 @@ CHIP_ERROR Instance::ReadEndpointListAttribute(const AttributeValueEncoder::List return CHIP_NO_ERROR; } -void Instance::SetDefaultDelegate(Delegate * aDelegate) -{ - if (aDelegate == nullptr) - { - ChipLogError(Zcl, "Cannot set empty delegate!!!"); - return; - } - mDelegate = aDelegate; -} - -CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +CHIP_ERROR ActionsServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) { VerifyOrDie(aPath.mClusterId == Actions::Id); switch (aPath.mAttributeId) { case ActionList::Id: { - Instance * d = this; - return aEncoder.EncodeList([d](const auto & encoder) -> CHIP_ERROR { return d->ReadActionListAttribute(encoder); }); + return aEncoder.EncodeList( + [this, aPath](const auto & encoder) -> CHIP_ERROR { return this->ReadActionListAttribute(aPath, encoder); }); } case EndpointLists::Id: { - Instance * d = this; - return aEncoder.EncodeList([d](const auto & encoder) -> CHIP_ERROR { return d->ReadEndpointListAttribute(encoder); }); + return aEncoder.EncodeList( + [this, aPath](const auto & encoder) -> CHIP_ERROR { return this->ReadEndpointListAttribute(aPath, encoder); }); } default: break; @@ -141,18 +160,19 @@ CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValu return CHIP_NO_ERROR; } -bool Instance::FindActionIdInActionList(uint16_t actionId) +bool ActionsServer::FindActionIdInActionList(EndpointId endpointId, uint16_t actionId) { - if (GetInstance()->mDelegate == nullptr) + Delegate * delegate = GetDelegate(endpointId); + if (delegate == nullptr) { ChipLogError(Zcl, "Actions delegate is null!!!"); return false; } - return GetInstance()->mDelegate->FindActionIdInActionList(actionId); + return delegate->FindActionIdInActionList(actionId); } template -void Instance::HandleCommand(HandlerContext & handlerContext, FuncT func) +void ActionsServer::HandleCommand(HandlerContext & handlerContext, FuncT func) { if (!handlerContext.mCommandHandled && (handlerContext.mRequestPath.mCommandId == RequestT::GetCommandId())) { @@ -172,8 +192,7 @@ void Instance::HandleCommand(HandlerContext & handlerContext, FuncT func) return; } - uint16_t actionId = requestPayload.actionID; - if (!GetInstance()->FindActionIdInActionList(actionId)) + if (FindActionIdInActionList(handlerContext.mRequestPath.mEndpointId, requestPayload.actionID)) { handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Protocols::InteractionModel::Status::NotFound); return; @@ -183,113 +202,125 @@ void Instance::HandleCommand(HandlerContext & handlerContext, FuncT func) } } -void Instance::HandleInstantAction(HandlerContext & ctx, const Commands::InstantAction::DecodableType & commandData) +void ActionsServer::HandleInstantAction(HandlerContext & ctx, const Commands::InstantAction::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; - Status status = GetInstance()->mDelegate->HandleInstantAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleInstantAction(actionId, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandleInstantActionWithTransition(HandlerContext & ctx, - const Commands::InstantActionWithTransition::DecodableType & commandData) +void ActionsServer::HandleInstantActionWithTransition(HandlerContext & ctx, + const Commands::InstantActionWithTransition::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; uint16_t transitionTime = commandData.transitionTime; - Status status = GetInstance()->mDelegate->HandleInstantActionWithTransition(actionId, transitionTime, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleInstantActionWithTransition(actionId, transitionTime, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandleStartAction(HandlerContext & ctx, const Commands::StartAction::DecodableType & commandData) +void ActionsServer::HandleStartAction(HandlerContext & ctx, const Commands::StartAction::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; - Status status = GetInstance()->mDelegate->HandleStartAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleStartAction(actionId, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandleStartActionWithDuration(HandlerContext & ctx, - const Commands::StartActionWithDuration::DecodableType & commandData) +void ActionsServer::HandleStartActionWithDuration(HandlerContext & ctx, + const Commands::StartActionWithDuration::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; uint32_t duration = commandData.duration; - Status status = GetInstance()->mDelegate->HandleStartActionWithDuration(actionId, duration, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleStartActionWithDuration(actionId, duration, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandleStopAction(HandlerContext & ctx, const Commands::StopAction::DecodableType & commandData) +void ActionsServer::HandleStopAction(HandlerContext & ctx, const Commands::StopAction::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; - Status status = GetInstance()->mDelegate->HandleStopAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleStopAction(actionId, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandlePauseAction(HandlerContext & ctx, const Commands::PauseAction::DecodableType & commandData) +void ActionsServer::HandlePauseAction(HandlerContext & ctx, const Commands::PauseAction::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; - Status status = GetInstance()->mDelegate->HandlePauseAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandlePauseAction(actionId, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandlePauseActionWithDuration(HandlerContext & ctx, - const Commands::PauseActionWithDuration::DecodableType & commandData) +void ActionsServer::HandlePauseActionWithDuration(HandlerContext & ctx, + const Commands::PauseActionWithDuration::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; uint32_t duration = commandData.duration; - Status status = GetInstance()->mDelegate->HandlePauseActionWithDuration(actionId, duration, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandlePauseActionWithDuration(actionId, duration, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandleResumeAction(HandlerContext & ctx, const Commands::ResumeAction::DecodableType & commandData) +void ActionsServer::HandleResumeAction(HandlerContext & ctx, const Commands::ResumeAction::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; - Status status = GetInstance()->mDelegate->HandleResumeAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleResumeAction(actionId, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandleEnableAction(HandlerContext & ctx, const Commands::EnableAction::DecodableType & commandData) +void ActionsServer::HandleEnableAction(HandlerContext & ctx, const Commands::EnableAction::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; - Status status = GetInstance()->mDelegate->HandleEnableAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleEnableAction(actionId, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandleEnableActionWithDuration(HandlerContext & ctx, - const Commands::EnableActionWithDuration::DecodableType & commandData) +void ActionsServer::HandleEnableActionWithDuration(HandlerContext & ctx, + const Commands::EnableActionWithDuration::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; uint32_t duration = commandData.duration; - Status status = GetInstance()->mDelegate->HandleEnableActionWithDuration(actionId, duration, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleEnableActionWithDuration(actionId, duration, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandleDisableAction(HandlerContext & ctx, const Commands::DisableAction::DecodableType & commandData) +void ActionsServer::HandleDisableAction(HandlerContext & ctx, const Commands::DisableAction::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; - Status status = GetInstance()->mDelegate->HandleDisableAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleDisableAction(actionId, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::HandleDisableActionWithDuration(HandlerContext & ctx, - const Commands::DisableActionWithDuration::DecodableType & commandData) +void ActionsServer::HandleDisableActionWithDuration(HandlerContext & ctx, + const Commands::DisableActionWithDuration::DecodableType & commandData) { uint16_t actionId = commandData.actionID; Optional invokeId = commandData.invokeID; uint32_t duration = commandData.duration; - Status status = GetInstance()->mDelegate->HandleDisableActionWithDuration(actionId, duration, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleDisableActionWithDuration(actionId, duration, invokeId); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } -void Instance::InvokeCommand(HandlerContext & handlerContext) +void ActionsServer::InvokeCommand(HandlerContext & handlerContext) { switch (handlerContext.mRequestPath.mCommandId) { @@ -350,6 +381,6 @@ void Instance::InvokeCommand(HandlerContext & handlerContext) } void MatterActionsPluginServerInitCallback() { - AttributeAccessInterfaceRegistry::Instance().Register(Instance::GetInstance()); - CommandHandlerInterfaceRegistry::Instance().RegisterCommandHandler(Instance::GetInstance()); + AttributeAccessInterfaceRegistry::Instance().Register(&ActionsServer::Instance()); + CommandHandlerInterfaceRegistry::Instance().RegisterCommandHandler(&ActionsServer::Instance()); } diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h index 0c20ef0b041e5c..3c1570252e1326 100644 --- a/src/app/clusters/actions-server/actions-server.h +++ b/src/app/clusters/actions-server/actions-server.h @@ -36,16 +36,16 @@ class Delegate; struct ActionStructStorage : public Structs::ActionStruct::Type { - ActionStructStorage() : mActionName(mBuffer, sizeof(mBuffer)){}; + ActionStructStorage() : mActionName(mBuffer){}; - ActionStructStorage(uint16_t action, CharSpan actionName, ActionTypeEnum actionType, uint16_t epListID, + ActionStructStorage(uint16_t action, const CharSpan & actionName, ActionTypeEnum actionType, uint16_t epListID, BitMask commands, ActionStateEnum actionState) : - mActionName(mBuffer, sizeof(mBuffer)) + mActionName(mBuffer) { Set(action, actionName, actionType, epListID, commands, actionState); } - ActionStructStorage(const ActionStructStorage & action) : mActionName(mBuffer, sizeof(mBuffer)) { *this = action; } + ActionStructStorage(const ActionStructStorage & action) : mActionName(mBuffer) { *this = action; } ActionStructStorage & operator=(const ActionStructStorage & action) { @@ -53,8 +53,8 @@ struct ActionStructStorage : public Structs::ActionStruct::Type return *this; } - void Set(uint16_t action, CharSpan actionName, ActionTypeEnum actionType, uint16_t epListID, BitMask commands, - ActionStateEnum actionState) + void Set(uint16_t action, const CharSpan & actionName, ActionTypeEnum actionType, uint16_t epListID, + BitMask commands, ActionStateEnum actionState) { actionID = action; type = actionType; @@ -72,16 +72,16 @@ struct ActionStructStorage : public Structs::ActionStruct::Type struct EndpointListStorage : public Structs::EndpointListStruct::Type { - EndpointListStorage() : mEpListName(mBuffer, sizeof(mBuffer)){}; + EndpointListStorage() : mEpListName(mBuffer){}; - EndpointListStorage(uint16_t epListId, CharSpan epListName, EndpointListTypeEnum epListType, - DataModel::List endpointList) : - mEpListName(mBuffer, sizeof(mBuffer)) + EndpointListStorage(uint16_t epListId, const CharSpan & epListName, EndpointListTypeEnum epListType, + const DataModel::List & endpointList) : + mEpListName(mBuffer) { Set(epListId, epListName, epListType, endpointList); } - EndpointListStorage(const EndpointListStorage & epList) : mEpListName(mBuffer, sizeof(mBuffer)) { *this = epList; } + EndpointListStorage(const EndpointListStorage & epList) : mEpListName(mBuffer) { *this = epList; } EndpointListStorage & operator=(const EndpointListStorage & epList) { @@ -89,8 +89,8 @@ struct EndpointListStorage : public Structs::EndpointListStruct::Type return *this; } - void Set(uint16_t epListId, CharSpan epListName, EndpointListTypeEnum epListType, - DataModel::List endpointList) + void Set(uint16_t epListId, const CharSpan & epListName, EndpointListTypeEnum epListType, + const DataModel::List & endpointList) { endpointListID = epListId; type = epListType; @@ -112,14 +112,15 @@ struct EndpointListStorage : public Structs::EndpointListStruct::Type Span mEpListSpan; }; -class Instance : public AttributeAccessInterface, public CommandHandlerInterface +class ActionsServer : public AttributeAccessInterface, public CommandHandlerInterface { public: // Register for the Actions cluster on all endpoints. - Instance() : + ActionsServer() : AttributeAccessInterface(Optional::Missing(), Actions::Id), CommandHandlerInterface(Optional::Missing(), Actions::Id) {} + static ActionsServer & Instance(); /** * @brief @@ -134,20 +135,20 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface void OnActionFailed(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState, ActionErrorEnum actionError); - static Instance * GetInstance(); - void SetDefaultDelegate(Delegate * aDelegate); + static void SetDefaultDelegate(EndpointId endpointId, Delegate * aDelegate); private: - Delegate * mDelegate; - static Instance instance; - static constexpr size_t kMaxEndpointList = 256u; - static constexpr size_t kMaxActionList = 256u; + static ActionsServer sInstance; + static constexpr size_t kMaxEndpointListLength = 256u; + static constexpr size_t kMaxActionListLength = 256u; CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; - CHIP_ERROR ReadActionListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder); - CHIP_ERROR ReadEndpointListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder); - bool FindActionIdInActionList(uint16_t actionId); + CHIP_ERROR ReadActionListAttribute(const ConcreteReadAttributePath & aPath, + const AttributeValueEncoder::ListEncodeHelper & encoder); + CHIP_ERROR ReadEndpointListAttribute(const ConcreteReadAttributePath & aPath, + const AttributeValueEncoder::ListEncodeHelper & encoder); + bool FindActionIdInActionList(EndpointId endpointId, uint16_t actionId); // CommandHandlerInterface template From be5fa2024fbd5675c60b6f47527e85abd222bcec Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Tue, 24 Dec 2024 15:44:09 +0530 Subject: [PATCH 14/15] Restructured the storage structs, command handler and removed vector usage. --- scripts/tools/check_includes_config.py | 1 - .../actions-server/actions-server.cpp | 78 ++++++------------- .../clusters/actions-server/actions-server.h | 39 +++++----- 3 files changed, 45 insertions(+), 73 deletions(-) diff --git a/scripts/tools/check_includes_config.py b/scripts/tools/check_includes_config.py index e7d165a20d384c..a7da891ea59c12 100644 --- a/scripts/tools/check_includes_config.py +++ b/scripts/tools/check_includes_config.py @@ -128,7 +128,6 @@ 'src/app/clusters/application-launcher-server/application-launcher-server.cpp': {'string'}, 'src/app/clusters/application-launcher-server/application-launcher-delegate.h': {'list'}, 'src/app/clusters/audio-output-server/audio-output-delegate.h': {'list'}, - 'src/app/clusters/actions-server/actions-server.h': {'vector'}, # EcosystemInformationCluster is for Fabric Sync and is intended to run on device that are capable of handling these types. 'src/app/clusters/ecosystem-information-server/ecosystem-information-server.h': {'map', 'string', 'vector'}, 'src/app/clusters/channel-server/channel-delegate.h': {'list'}, diff --git a/src/app/clusters/actions-server/actions-server.cpp b/src/app/clusters/actions-server/actions-server.cpp index ec20bdf038ab96..50d5b548de803b 100644 --- a/src/app/clusters/actions-server/actions-server.cpp +++ b/src/app/clusters/actions-server/actions-server.cpp @@ -204,119 +204,91 @@ void ActionsServer::HandleCommand(HandlerContext & handlerContext, FuncT func) void ActionsServer::HandleInstantAction(HandlerContext & ctx, const Commands::InstantAction::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandleInstantAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleInstantAction(commandData.actionID, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandleInstantActionWithTransition(HandlerContext & ctx, const Commands::InstantActionWithTransition::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - uint16_t transitionTime = commandData.transitionTime; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandleInstantActionWithTransition(actionId, transitionTime, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = + delegate->HandleInstantActionWithTransition(commandData.actionID, commandData.transitionTime, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandleStartAction(HandlerContext & ctx, const Commands::StartAction::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandleStartAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleStartAction(commandData.actionID, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandleStartActionWithDuration(HandlerContext & ctx, const Commands::StartActionWithDuration::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - uint32_t duration = commandData.duration; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandleStartActionWithDuration(actionId, duration, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleStartActionWithDuration(commandData.actionID, commandData.duration, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandleStopAction(HandlerContext & ctx, const Commands::StopAction::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandleStopAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleStopAction(commandData.actionID, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandlePauseAction(HandlerContext & ctx, const Commands::PauseAction::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandlePauseAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandlePauseAction(commandData.actionID, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandlePauseActionWithDuration(HandlerContext & ctx, const Commands::PauseActionWithDuration::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - uint32_t duration = commandData.duration; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandlePauseActionWithDuration(actionId, duration, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandlePauseActionWithDuration(commandData.actionID, commandData.duration, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandleResumeAction(HandlerContext & ctx, const Commands::ResumeAction::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandleResumeAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleResumeAction(commandData.actionID, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandleEnableAction(HandlerContext & ctx, const Commands::EnableAction::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandleEnableAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleEnableAction(commandData.actionID, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandleEnableActionWithDuration(HandlerContext & ctx, const Commands::EnableActionWithDuration::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - uint32_t duration = commandData.duration; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandleEnableActionWithDuration(actionId, duration, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleEnableActionWithDuration(commandData.actionID, commandData.duration, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandleDisableAction(HandlerContext & ctx, const Commands::DisableAction::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandleDisableAction(actionId, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleDisableAction(commandData.actionID, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } void ActionsServer::HandleDisableActionWithDuration(HandlerContext & ctx, const Commands::DisableActionWithDuration::DecodableType & commandData) { - uint16_t actionId = commandData.actionID; - Optional invokeId = commandData.invokeID; - uint32_t duration = commandData.duration; - Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); - Status status = delegate->HandleDisableActionWithDuration(actionId, duration, invokeId); + Delegate * delegate = GetDelegate(ctx.mRequestPath.mEndpointId); + Status status = delegate->HandleDisableActionWithDuration(commandData.actionID, commandData.duration, commandData.invokeID); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h index 3c1570252e1326..bdb41f69cad771 100644 --- a/src/app/clusters/actions-server/actions-server.h +++ b/src/app/clusters/actions-server/actions-server.h @@ -21,31 +21,32 @@ #include #include #include -#include namespace chip { namespace app { namespace Clusters { namespace Actions { -static constexpr size_t kActionNameMaxSize = 128u; -static constexpr size_t kEndpointListNameMaxSize = 128u; -static constexpr size_t kEndpointListMaxSize = 256u; +// Last byte is reserved of '\0' terminator. +static constexpr size_t kActionNameMaxSize = 127u; +static constexpr size_t kEndpointListNameMaxSize = 127u; + +static constexpr size_t kEndpointListMaxSize = 256u; class Delegate; struct ActionStructStorage : public Structs::ActionStruct::Type { - ActionStructStorage() : mActionName(mBuffer){}; + ActionStructStorage() : mActionName(mBuffer, sizeof(mBuffer)){}; ActionStructStorage(uint16_t action, const CharSpan & actionName, ActionTypeEnum actionType, uint16_t epListID, BitMask commands, ActionStateEnum actionState) : - mActionName(mBuffer) + mActionName(mBuffer, sizeof(mBuffer)) { Set(action, actionName, actionType, epListID, commands, actionState); } - ActionStructStorage(const ActionStructStorage & action) : mActionName(mBuffer) { *this = action; } + ActionStructStorage(const ActionStructStorage & action) : mActionName(mBuffer, sizeof(mBuffer)) { *this = action; } ActionStructStorage & operator=(const ActionStructStorage & action) { @@ -72,16 +73,16 @@ struct ActionStructStorage : public Structs::ActionStruct::Type struct EndpointListStorage : public Structs::EndpointListStruct::Type { - EndpointListStorage() : mEpListName(mBuffer){}; + EndpointListStorage() : mEpListName(mBuffer, sizeof(mBuffer)){}; EndpointListStorage(uint16_t epListId, const CharSpan & epListName, EndpointListTypeEnum epListType, const DataModel::List & endpointList) : - mEpListName(mBuffer) + mEpListName(mBuffer, sizeof(mBuffer)) { Set(epListId, epListName, epListType, endpointList); } - EndpointListStorage(const EndpointListStorage & epList) : mEpListName(mBuffer) { *this = epList; } + EndpointListStorage(const EndpointListStorage & epList) : mEpListName(mBuffer, sizeof(mBuffer)) { *this = epList; } EndpointListStorage & operator=(const EndpointListStorage & epList) { @@ -92,15 +93,15 @@ struct EndpointListStorage : public Structs::EndpointListStruct::Type void Set(uint16_t epListId, const CharSpan & epListName, EndpointListTypeEnum epListType, const DataModel::List & endpointList) { - endpointListID = epListId; - type = epListType; + endpointListID = epListId; + type = epListType; + size_t epListSize = std::min(endpointList.size(), kEndpointListMaxSize); - for (uint8_t index = 0; index < std::min(endpointList.size(), kEndpointListMaxSize); index++) + for (uint8_t index = 0; index < epListSize; index++) { - mEpList.push_back(endpointList[index]); + mEpList[index] = endpointList[index]; } - mEpListSpan = Span(mEpList.data(), mEpList.size()); - endpoints = DataModel::List(mEpListSpan); + endpoints = DataModel::List(Span(mEpList, epListSize)); CopyCharSpanToMutableCharSpanWithTruncation(epListName, mEpListName); name = mEpListName; } @@ -108,8 +109,7 @@ struct EndpointListStorage : public Structs::EndpointListStruct::Type private: char mBuffer[kEndpointListNameMaxSize]; MutableCharSpan mEpListName; - std::vector mEpList; - Span mEpListSpan; + EndpointId mEpList[kEndpointListMaxSize]; }; class ActionsServer : public AttributeAccessInterface, public CommandHandlerInterface @@ -150,7 +150,8 @@ class ActionsServer : public AttributeAccessInterface, public CommandHandlerInte const AttributeValueEncoder::ListEncodeHelper & encoder); bool FindActionIdInActionList(EndpointId endpointId, uint16_t actionId); - // CommandHandlerInterface + // Cannot use CommandHandlerInterface::HandleCommand directly because we need to do the FindActionIdInActionList() check before + // sending a command. template void HandleCommand(HandlerContext & handlerContext, FuncT func); From 0d1274e08e04177aae2caa39644bff900bc0d89d Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Mon, 27 Jan 2025 16:49:22 +0530 Subject: [PATCH 15/15] Add unit tests for the actions cluster. --- .../include/bridged-actions-stub.h | 2 +- .../actions-server/actions-server.cpp | 67 +-- .../clusters/actions-server/actions-server.h | 16 +- src/app/tests/BUILD.gn | 15 + src/app/tests/TestActionsCluster.cpp | 445 ++++++++++++++++++ 5 files changed, 509 insertions(+), 36 deletions(-) create mode 100644 src/app/tests/TestActionsCluster.cpp diff --git a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h index ca8b0e26d2004d..d58269313b648e 100644 --- a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h +++ b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h @@ -41,7 +41,7 @@ class ActionsDelegateImpl : public Delegate }; // Dummy endpoint list. - const EndpointId firstEpList[1] = { 0 }; + const EndpointId firstEpList[3] = { 0, 1, 2 }; const EndpointId secondEpList[1] = { 0 }; const EndpointId thirdEpList[1] = { 0 }; diff --git a/src/app/clusters/actions-server/actions-server.cpp b/src/app/clusters/actions-server/actions-server.cpp index 50d5b548de803b..a8fcd476eb2345 100644 --- a/src/app/clusters/actions-server/actions-server.cpp +++ b/src/app/clusters/actions-server/actions-server.cpp @@ -32,16 +32,12 @@ using namespace chip::app::Clusters::Actions; using namespace chip::app::Clusters::Actions::Attributes; using namespace chip::Protocols::InteractionModel; -static constexpr size_t kActionsDelegateTableSize = - MATTER_DM_ACTIONS_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; - namespace { Delegate * gDelegateTable[kActionsDelegateTableSize] = { nullptr }; Delegate * GetDelegate(EndpointId endpoint) { - uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, Actions::Id, MATTER_DM_ACTIONS_CLUSTER_SERVER_ENDPOINT_COUNT); - return (ep >= kActionsDelegateTableSize ? nullptr : gDelegateTable[ep]); + return (endpoint >= kActionsDelegateTableSize ? nullptr : gDelegateTable[endpoint]); } } // namespace @@ -50,11 +46,9 @@ ActionsServer ActionsServer::sInstance; void ActionsServer::SetDefaultDelegate(EndpointId endpoint, Delegate * delegate) { - uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, Actions::Id, MATTER_DM_ACTIONS_CLUSTER_SERVER_ENDPOINT_COUNT); - // if endpoint is found - if (ep < kActionsDelegateTableSize) + if (endpoint < kActionsDelegateTableSize) { - gDelegateTable[ep] = delegate; + gDelegateTable[endpoint] = delegate; } } @@ -92,6 +86,30 @@ void ActionsServer::OnActionFailed(EndpointId endpoint, uint16_t actionId, uint3 } } +CHIP_ERROR ActionsServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + VerifyOrDie(aPath.mClusterId == Actions::Id); + + switch (aPath.mAttributeId) + { + case ActionList::Id: { + // The encoder will automatically create the outer AttributeDataIB container + // We just need to encode the array of actions + ReturnErrorOnFailure(aEncoder.EncodeList( + [this, aPath](const auto & encoder) -> CHIP_ERROR { return this->ReadActionListAttribute(aPath, encoder); })); + return CHIP_NO_ERROR; + } + case EndpointLists::Id: { + ReturnErrorOnFailure(aEncoder.EncodeList( + [this, aPath](const auto & encoder) -> CHIP_ERROR { return this->ReadEndpointListAttribute(aPath, encoder); })); + return CHIP_NO_ERROR; + } + default: + break; + } + return CHIP_NO_ERROR; +} + CHIP_ERROR ActionsServer::ReadActionListAttribute(const ConcreteReadAttributePath & aPath, const AttributeValueEncoder::ListEncodeHelper & encoder) { @@ -101,15 +119,20 @@ CHIP_ERROR ActionsServer::ReadActionListAttribute(const ConcreteReadAttributePat ChipLogError(Zcl, "Actions delegate is null!!!"); return CHIP_ERROR_INCORRECT_STATE; } - for (uint16_t i = 0; i <= kMaxActionListLength; i++) + + for (uint16_t i = 0; i < kMaxActionListLength; i++) { ActionStructStorage action; - CHIP_ERROR err = delegate->ReadActionAtIndex(i, action); + if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) { return CHIP_NO_ERROR; } + else if (err != CHIP_NO_ERROR) + { + return err; + } ReturnErrorOnFailure(encoder.Encode(action)); } @@ -125,7 +148,7 @@ CHIP_ERROR ActionsServer::ReadEndpointListAttribute(const ConcreteReadAttributeP ChipLogError(Zcl, "Actions delegate is null!!!"); return CHIP_ERROR_INCORRECT_STATE; } - for (uint16_t i = 0; i <= kMaxEndpointListLength; i++) + for (uint16_t i = 0; i < kMaxEndpointListLength; i++) { EndpointListStorage epList; @@ -140,26 +163,6 @@ CHIP_ERROR ActionsServer::ReadEndpointListAttribute(const ConcreteReadAttributeP return CHIP_NO_ERROR; } -CHIP_ERROR ActionsServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) -{ - VerifyOrDie(aPath.mClusterId == Actions::Id); - - switch (aPath.mAttributeId) - { - case ActionList::Id: { - return aEncoder.EncodeList( - [this, aPath](const auto & encoder) -> CHIP_ERROR { return this->ReadActionListAttribute(aPath, encoder); }); - } - case EndpointLists::Id: { - return aEncoder.EncodeList( - [this, aPath](const auto & encoder) -> CHIP_ERROR { return this->ReadEndpointListAttribute(aPath, encoder); }); - } - default: - break; - } - return CHIP_NO_ERROR; -} - bool ActionsServer::FindActionIdInActionList(EndpointId endpointId, uint16_t actionId) { Delegate * delegate = GetDelegate(endpointId); diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h index bdb41f69cad771..162cb40fea215a 100644 --- a/src/app/clusters/actions-server/actions-server.h +++ b/src/app/clusters/actions-server/actions-server.h @@ -22,6 +22,16 @@ #include #include +namespace { +// Zero'th index will be used for unit tests only. +static constexpr size_t kActionsDelegateTableSize = +#ifdef ZCL_USING_ACTIONS_CLUSTER_SERVER + MATTER_DM_ACTIONS_CLUSTER_SERVER_ENDPOINT_COUNT + +#endif + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT + 1; + +} // namespace + namespace chip { namespace app { namespace Clusters { @@ -97,7 +107,7 @@ struct EndpointListStorage : public Structs::EndpointListStruct::Type type = epListType; size_t epListSize = std::min(endpointList.size(), kEndpointListMaxSize); - for (uint8_t index = 0; index < epListSize; index++) + for (size_t index = 0; index < epListSize; index++) { mEpList[index] = endpointList[index]; } @@ -137,13 +147,13 @@ class ActionsServer : public AttributeAccessInterface, public CommandHandlerInte static void SetDefaultDelegate(EndpointId endpointId, Delegate * aDelegate); + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + private: static ActionsServer sInstance; static constexpr size_t kMaxEndpointListLength = 256u; static constexpr size_t kMaxActionListLength = 256u; - CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; - CHIP_ERROR ReadActionListAttribute(const ConcreteReadAttributePath & aPath, const AttributeValueEncoder::ListEncodeHelper & encoder); CHIP_ERROR ReadEndpointListAttribute(const ConcreteReadAttributePath & aPath, diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 1923573765101a..b066cf20379c67 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -109,6 +109,18 @@ source_set("power-cluster-test-srcs") { ] } +source_set("actions-cluster-test-srcs") { + sources = + [ "${chip_root}/src/app/clusters/actions-server/actions-server.cpp" ] + + public_deps = [ + "${chip_root}/src/app/common:cluster-objects", + "${chip_root}/src/app/util/mock:mock_codegen_data_model", + "${chip_root}/src/app/util/mock:mock_ember", + "${chip_root}/src/lib/core", + ] +} + source_set("scenes-table-test-srcs") { sources = [ "${chip_root}/src/app/clusters/scenes-server/ExtensionFieldSets.h", @@ -195,6 +207,7 @@ chip_test_suite("tests") { test_sources = [ "TestAclAttribute.cpp", "TestAclEvent.cpp", + "TestActionsCluster.cpp", "TestAttributeAccessInterfaceCache.cpp", "TestAttributePathExpandIterator.cpp", "TestAttributePathParams.cpp", @@ -239,6 +252,7 @@ chip_test_suite("tests") { cflags = [ "-Wconversion" ] public_deps = [ + ":actions-cluster-test-srcs", ":app-test-stubs", ":binding-test-srcs", ":ecosystem-information-test-srcs", @@ -272,6 +286,7 @@ chip_test_suite("tests") { "TestSceneTable.cpp", ] public_deps += [ + ":actions-cluster-test-srcs", ":power-cluster-test-srcs", ":scenes-table-test-srcs", ] diff --git a/src/app/tests/TestActionsCluster.cpp b/src/app/tests/TestActionsCluster.cpp new file mode 100644 index 00000000000000..702527711c2707 --- /dev/null +++ b/src/app/tests/TestActionsCluster.cpp @@ -0,0 +1,445 @@ +/* + * + * Copyright (c) 2025 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 + +#include "lib/support/CHIPMem.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT +#undef CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT +#define CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT 1 +#endif + +namespace chip { +namespace app { + +using namespace Clusters::Actions; +using namespace chip::Protocols::InteractionModel; + +class TestActionsCluster : public ::testing::Test +{ +public: + static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); } + static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); } +}; + +class TestActionsDelegateImpl : public Clusters::Actions::Delegate +{ +public: + EndpointId endpointId = 0; + static constexpr size_t kMaxActionNameLength = 127u; + static constexpr size_t kMaxEndpointListNameLength = 127u; + static constexpr size_t kEndpointListMaxSize = 256u; + static constexpr size_t kMaxActions = 2; + static constexpr size_t kMaxEndpointLists = 2; + + ActionStructStorage mActions[kMaxActions]; + size_t mNumActions = 0; + + EndpointListStorage mEndpointLists[kMaxEndpointLists]; + size_t mNumEndpointLists = 0; + + CHIP_ERROR ReadActionAtIndex(uint16_t index, ActionStructStorage & action) override + { + if (index >= mNumActions) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + action = mActions[index]; + return CHIP_NO_ERROR; + } + + CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList) override + { + if (index >= mNumEndpointLists) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + epList = mEndpointLists[index]; + return CHIP_NO_ERROR; + } + + bool FindActionIdInActionList(uint16_t actionId) override + { + for (uint16_t i = 0; i < mNumActions; i++) + { + if (mActions[i].actionID == actionId) + { + return true; + } + } + return false; + } + + // Test helper methods + CHIP_ERROR AddTestAction(const ActionStructStorage & action) + { + if (mNumActions >= kMaxActions) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + mActions[mNumActions++] = action; + return CHIP_NO_ERROR; + } + + CHIP_ERROR AddTestEndpointList(const EndpointListStorage & epList) + { + if (mNumEndpointLists >= kMaxEndpointLists) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + mEndpointLists[mNumEndpointLists++] = epList; + return CHIP_NO_ERROR; + } + + Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, + Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandleStartAction(uint16_t actionId, Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandleStopAction(uint16_t actionId, Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandlePauseAction(uint16_t actionId, Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandleResumeAction(uint16_t actionId, Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandleEnableAction(uint16_t actionId, Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandleDisableAction(uint16_t actionId, Optional invokeId) override + { + return Status::NotFound; + } + Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override + { + return Status::NotFound; + } +}; + +TestActionsDelegateImpl delegate; +TEST_F(TestActionsCluster, TestActionListConstraints) +{ + // Test 1: Action name length constraint + char longName[kActionNameMaxSize + 10]; + memset(longName, 'A', sizeof(longName)); + longName[sizeof(longName) - 1] = '\0'; + + ActionStructStorage actionWithLongName(1, CharSpan::fromCharString(longName), ActionTypeEnum::kScene, 0, BitMask(), + ActionStateEnum::kInactive); + + // Add action and verify it was added successfully + EXPECT_EQ(delegate.AddTestAction(actionWithLongName), CHIP_NO_ERROR); + + // Verify the name was truncated by reading it back + ActionStructStorage readAction; + EXPECT_EQ(delegate.ReadActionAtIndex(0, readAction), CHIP_NO_ERROR); + EXPECT_EQ(readAction.name.size(), kActionNameMaxSize); + + // Test 2: Maximum action list size + delegate.mNumActions = 0; + for (uint16_t i = 0; i < delegate.kMaxActions; i++) + { + ActionStructStorage action(i, CharSpan::fromCharString("Action"), ActionTypeEnum::kScene, 0, BitMask(), + ActionStateEnum::kInactive); + EXPECT_EQ(delegate.AddTestAction(action), CHIP_NO_ERROR); + } + + // Try to add one more action beyond the limit + ActionStructStorage extraAction(99, CharSpan::fromCharString("Extra"), ActionTypeEnum::kScene, 0, BitMask(), + ActionStateEnum::kInactive); + EXPECT_EQ(delegate.AddTestAction(extraAction), CHIP_ERROR_BUFFER_TOO_SMALL); +} + +TEST_F(TestActionsCluster, TestEndpointListConstraints) +{ + // Test 1: Endpoint list name length constraint + char longName[kEndpointListNameMaxSize + 10]; + memset(longName, 'B', sizeof(longName)); + longName[sizeof(longName) - 1] = '\0'; + + const EndpointId endpoints[] = { 1, 2, 3 }; + EndpointListStorage epListWithLongName(1, CharSpan::fromCharString(longName), EndpointListTypeEnum::kOther, + DataModel::List(endpoints)); + + // Add endpoint list and verify it was added successfully + EXPECT_EQ(delegate.AddTestEndpointList(epListWithLongName), CHIP_NO_ERROR); + + // Verify the name was truncated by reading it back + EndpointListStorage readEpList; + EXPECT_EQ(delegate.ReadEndpointListAtIndex(0, readEpList), CHIP_NO_ERROR); + EXPECT_EQ(readEpList.name.size(), kEndpointListNameMaxSize); + + // Test 2: Maximum endpoint list size + delegate.mNumEndpointLists = 0; + for (uint16_t i = 0; i < delegate.kMaxEndpointLists; i++) + { + EndpointListStorage epList(i, CharSpan::fromCharString("List"), EndpointListTypeEnum::kOther, + DataModel::List(endpoints)); + EXPECT_EQ(delegate.AddTestEndpointList(epList), CHIP_NO_ERROR); + } + + // Try to add one more endpoint list beyond the limit + EndpointListStorage extraEpList(99, CharSpan::fromCharString("Extra"), EndpointListTypeEnum::kOther, + DataModel::List(endpoints)); + EXPECT_EQ(delegate.AddTestEndpointList(extraEpList), CHIP_ERROR_BUFFER_TOO_SMALL); + + // Test 3: Maximum endpoints per list + delegate.mNumEndpointLists = 0; + EndpointId tooManyEndpoints[kEndpointListMaxSize + 5]; + for (uint16_t i = 0; i < kEndpointListMaxSize + 5; i++) + { + tooManyEndpoints[i] = i; + } + + EndpointListStorage epListWithTooManyEndpoints(1, CharSpan::fromCharString("List"), EndpointListTypeEnum::kOther, + DataModel::List(tooManyEndpoints)); + + // The list should be added but truncated to kEndpointListMaxSize + EXPECT_EQ(delegate.AddTestEndpointList(epListWithTooManyEndpoints), CHIP_NO_ERROR); + + // Verify the endpoint list was truncated + EXPECT_EQ(delegate.ReadEndpointListAtIndex(0, readEpList), CHIP_NO_ERROR); + EXPECT_EQ(readEpList.endpoints.size(), kEndpointListMaxSize); +} + +TEST_F(TestActionsCluster, TestActionListAttributeAccess) +{ + ActionsServer::Instance().SetDefaultDelegate(delegate.endpointId, &delegate); + delegate.mNumActions = 0; + + // Add test actions + ActionStructStorage action1(1, CharSpan::fromCharString("FirstAction"), ActionTypeEnum::kScene, 0, BitMask(), + ActionStateEnum::kInactive); + ActionStructStorage action2(2, CharSpan::fromCharString("SecondAction"), ActionTypeEnum::kScene, 1, BitMask(), + ActionStateEnum::kActive); + + EXPECT_EQ(delegate.AddTestAction(action1), CHIP_NO_ERROR); + EXPECT_EQ(delegate.AddTestAction(action2), CHIP_NO_ERROR); + + // Test reading actions through attribute reader + uint8_t buf[1024]; + + // Create the TLV writer + TLV::TLVWriter tlvWriter; + tlvWriter.Init(buf); + + AttributeReportIBs::Builder builder; + builder.Init(&tlvWriter); + + ConcreteAttributePath path(delegate.endpointId, Clusters::Actions::Id, Clusters::Actions::Attributes::ActionList::Id); + ConcreteReadAttributePath readPath(path); + chip::DataVersion dataVersion(0); + Access::SubjectDescriptor subjectDescriptor; + AttributeValueEncoder encoder(builder, subjectDescriptor, path, dataVersion); + + // Read the action list using the Actions cluster's Read function + EXPECT_EQ(ActionsServer::Instance().Read(readPath, encoder), CHIP_NO_ERROR); + + TLV::TLVReader reader; + reader.Init(buf); + + TLV::TLVReader attrReportsReader; + TLV::TLVReader attrReportReader; + TLV::TLVReader attrDataReader; + + reader.Next(); + reader.OpenContainer(attrReportsReader); + + attrReportsReader.Next(); + attrReportsReader.OpenContainer(attrReportReader); + + attrReportReader.Next(); + attrReportReader.OpenContainer(attrDataReader); + + // We're now in the attribute data IB, skip to the desired tag, we want TagNum = 2 + attrDataReader.Next(); + for (int i = 0; i < 3 && !(IsContextTag(attrDataReader.GetTag()) && TagNumFromTag(attrDataReader.GetTag()) == 2); ++i) + { + attrDataReader.Next(); + } + EXPECT_TRUE(IsContextTag(attrDataReader.GetTag())); + EXPECT_EQ(TagNumFromTag(attrDataReader.GetTag()), 2u); + + Clusters::Actions::Attributes::ActionList::TypeInfo::DecodableType list; + CHIP_ERROR err = list.Decode(attrDataReader); + EXPECT_EQ(err, CHIP_NO_ERROR); + + auto iter = list.begin(); + EXPECT_TRUE(iter.Next()); + Clusters::Actions::Structs::ActionStruct::Type action = iter.GetValue(); + EXPECT_EQ(action.actionID, 1); + EXPECT_TRUE(strncmp(action.name.data(), "FirstAction", action.name.size()) == 0); + EXPECT_EQ(action.type, ActionTypeEnum::kScene); + EXPECT_EQ(action.endpointListID, 0); + EXPECT_EQ(action.supportedCommands.Raw(), 0); + EXPECT_EQ(action.state, ActionStateEnum::kInactive); + + EXPECT_TRUE(iter.Next()); + action = iter.GetValue(); + EXPECT_EQ(action.actionID, 2); + EXPECT_TRUE(strncmp(action.name.data(), "SecondAction", action.name.size()) == 0); + EXPECT_EQ(action.type, ActionTypeEnum::kScene); + EXPECT_EQ(action.endpointListID, 1); + EXPECT_EQ(action.supportedCommands.Raw(), 0); + EXPECT_EQ(action.state, ActionStateEnum::kActive); + + // Cleanup + ActionsServer::Instance().SetDefaultDelegate(delegate.endpointId, nullptr); +} + +TEST_F(TestActionsCluster, TestEndpointListAttributeAccess) +{ + ActionsServer::Instance().SetDefaultDelegate(delegate.endpointId, &delegate); + delegate.mNumEndpointLists = 0; + + // Add test endpoint lists + const EndpointId endpoints1[] = { 1, 2 }; + const EndpointId endpoints2[] = { 3, 4, 5 }; + + EndpointListStorage epList1(1, CharSpan::fromCharString("FirstList"), EndpointListTypeEnum::kOther, + DataModel::List(endpoints1, 2)); + EndpointListStorage epList2(2, CharSpan::fromCharString("SecondList"), EndpointListTypeEnum::kOther, + DataModel::List(endpoints2, 3)); + + EXPECT_EQ(delegate.AddTestEndpointList(epList1), CHIP_NO_ERROR); + EXPECT_EQ(delegate.AddTestEndpointList(epList2), CHIP_NO_ERROR); + + // Test reading endpoint lists through attribute reader + TLV::TLVWriter writer; + uint8_t buf[1024]; + writer.Init(buf); + + // Create the builders + TLV::TLVWriter tlvWriter; + tlvWriter.Init(buf); + + AttributeReportIBs::Builder builder; + builder.Init(&tlvWriter); + + ConcreteAttributePath path(delegate.endpointId, Clusters::Actions::Id, Clusters::Actions::Attributes::EndpointLists::Id); + ConcreteReadAttributePath readPath(path); + chip::DataVersion dataVersion(0); + Access::SubjectDescriptor subjectDescriptor; + AttributeValueEncoder encoder(builder, subjectDescriptor, path, dataVersion); + + EXPECT_EQ(ActionsServer::Instance().Read(path, encoder), CHIP_NO_ERROR); + + TLV::TLVReader reader; + reader.Init(buf); + + TLV::TLVReader attrReportsReader; + TLV::TLVReader attrReportReader; + TLV::TLVReader attrDataReader; + + reader.Next(); + reader.OpenContainer(attrReportsReader); + + attrReportsReader.Next(); + attrReportsReader.OpenContainer(attrReportReader); + + attrReportReader.Next(); + attrReportReader.OpenContainer(attrDataReader); + + // We're now in the attribute data IB, skip to the desired tag, we want TagNum = 2 + attrDataReader.Next(); + for (int i = 0; i < 3 && !(IsContextTag(attrDataReader.GetTag()) && TagNumFromTag(attrDataReader.GetTag()) == 2); ++i) + { + attrDataReader.Next(); + } + EXPECT_TRUE(IsContextTag(attrDataReader.GetTag())); + EXPECT_EQ(TagNumFromTag(attrDataReader.GetTag()), 2u); + + Clusters::Actions::Attributes::EndpointLists::TypeInfo::DecodableType list; + CHIP_ERROR err = list.Decode(attrDataReader); + EXPECT_EQ(err, CHIP_NO_ERROR); + + auto iter = list.begin(); + EXPECT_TRUE(iter.Next()); + Clusters::Actions::Structs::EndpointListStruct::DecodableType endpointList = iter.GetValue(); + EXPECT_EQ(endpointList.endpointListID, 1); + EXPECT_TRUE(strncmp(endpointList.name.data(), "FirstList", endpointList.name.size()) == 0); + EXPECT_EQ(endpointList.type, EndpointListTypeEnum::kOther); + auto it = endpointList.endpoints.begin(); + uint8_t i = 0; + while (it.Next()) + { + EXPECT_EQ(endpoints1[i++], it.GetValue()); + } + + EXPECT_TRUE(iter.Next()); + endpointList = iter.GetValue(); + EXPECT_EQ(endpointList.endpointListID, 2); + EXPECT_TRUE(strncmp(endpointList.name.data(), "SecondList", endpointList.name.size()) == 0); + EXPECT_EQ(endpointList.type, EndpointListTypeEnum::kOther); + it = endpointList.endpoints.begin(); + i = 0; + while (it.Next()) + { + EXPECT_EQ(endpoints2[i++], it.GetValue()); + } + + // Cleanup + ActionsServer::Instance().SetDefaultDelegate(delegate.endpointId, nullptr); +} + +} // namespace app +} // namespace chip