diff --git a/examples/chip-tool/commands/clusters/ClusterCommand.h b/examples/chip-tool/commands/clusters/ClusterCommand.h index ecba5aefb01f02..f9092d141fa7ac 100644 --- a/examples/chip-tool/commands/clusters/ClusterCommand.h +++ b/examples/chip-tool/commands/clusters/ClusterCommand.h @@ -18,16 +18,16 @@ #pragma once -#include -#include +#include #include "DataModelLogger.h" #include "ModelCommand.h" -class ClusterCommand : public ModelCommand, public chip::app::CommandSender::Callback +class ClusterCommand : public InteractionModelCommands, public ModelCommand, public chip::app::CommandSender::Callback { public: - ClusterCommand(CredentialIssuerCommands * credsIssuerConfig) : ModelCommand("command-by-id", credsIssuerConfig) + ClusterCommand(CredentialIssuerCommands * credsIssuerConfig) : + InteractionModelCommands(this), ModelCommand("command-by-id", credsIssuerConfig) { AddArgument("cluster-id", 0, UINT32_MAX, &mClusterId); AddArgument("command-id", 0, UINT32_MAX, &mCommandId); @@ -40,7 +40,7 @@ class ClusterCommand : public ModelCommand, public chip::app::CommandSender::Cal } ClusterCommand(chip::ClusterId clusterId, CredentialIssuerCommands * credsIssuerConfig) : - ModelCommand("command-by-id", credsIssuerConfig), mClusterId(clusterId) + InteractionModelCommands(this), ModelCommand("command-by-id", credsIssuerConfig), mClusterId(clusterId) { AddArgument("command-id", 0, UINT32_MAX, &mCommandId); AddArgument("payload", &mPayload); @@ -52,7 +52,7 @@ class ClusterCommand : public ModelCommand, public chip::app::CommandSender::Cal } ClusterCommand(const char * commandName, CredentialIssuerCommands * credsIssuerConfig) : - ModelCommand(commandName, credsIssuerConfig) + InteractionModelCommands(this), ModelCommand(commandName, credsIssuerConfig) { AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs); AddArgument("suppressResponse", 0, 1, &mSuppressResponse); @@ -64,12 +64,28 @@ class ClusterCommand : public ModelCommand, public chip::app::CommandSender::Cal CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override { - return ClusterCommand::SendCommand(device, endpointIds.at(0), mClusterId, mCommandId, mPayload); + return InteractionModelCommands::SendCommand(device, endpointIds.at(0), mClusterId, mCommandId, mPayload, + mTimedInteractionTimeoutMs, mRepeatCount, mRepeatDelayInMs, mSuppressResponse); + } + + template + CHIP_ERROR SendCommand(chip::DeviceProxy * device, chip::EndpointId endpointId, chip::ClusterId clusterId, + chip::CommandId commandId, const T & value) + { + return InteractionModelCommands::SendCommand(device, endpointId, clusterId, commandId, value, mTimedInteractionTimeoutMs, + mRepeatCount, mRepeatDelayInMs, mSuppressResponse); } CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override { - return ClusterCommand::SendGroupCommand(groupId, fabricIndex, mClusterId, mCommandId, mPayload); + return InteractionModelCommands::SendGroupCommand(groupId, fabricIndex, mClusterId, mCommandId, mPayload); + } + + template + CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex, chip::ClusterId clusterId, + chip::CommandId commandId, const T & value) + { + return InteractionModelCommands::SendGroupCommand(groupId, fabricIndex, clusterId, commandId, value); } /////////// CommandSender Callback Interface ///////// @@ -125,54 +141,6 @@ class ClusterCommand : public ModelCommand, public chip::app::CommandSender::Cal } } - template - CHIP_ERROR SendCommand(chip::DeviceProxy * device, chip::EndpointId endpointId, chip::ClusterId clusterId, - chip::CommandId commandId, const T & value) - { - uint16_t repeatCount = mRepeatCount.ValueOr(1); - while (repeatCount--) - { - chip::app::CommandPathParams commandPath = { endpointId, 0 /* groupId */, clusterId, commandId, - (chip::app::CommandPathFlags::kEndpointIdValid) }; - - auto commandSender = std::make_unique(this, device->GetExchangeManager(), - mTimedInteractionTimeoutMs.HasValue()); - VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY); - ReturnErrorOnFailure(commandSender->AddRequestDataNoTimedCheck(commandPath, value, mTimedInteractionTimeoutMs, - mSuppressResponse.ValueOr(false))); - - ReturnErrorOnFailure(commandSender->SendCommandRequest(device->GetSecureSession().Value())); - mCommandSender.push_back(std::move(commandSender)); - - if (mRepeatDelayInMs.HasValue()) - { - chip::test_utils::SleepMillis(mRepeatDelayInMs.Value()); - } - } - return CHIP_NO_ERROR; - } - - template - CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex, chip::ClusterId clusterId, - chip::CommandId commandId, const T & value) - { - chip::app::CommandPathParams commandPath = { 0 /* endpoint */, groupId, clusterId, commandId, - (chip::app::CommandPathFlags::kGroupIdValid) }; - - chip::Messaging::ExchangeManager * exchangeManager = chip::app::InteractionModelEngine::GetInstance()->GetExchangeManager(); - - auto commandSender = - chip::Platform::MakeUnique(this, exchangeManager, mTimedInteractionTimeoutMs.HasValue()); - VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY); - ReturnErrorOnFailure(commandSender->AddRequestDataNoTimedCheck(commandPath, value, mTimedInteractionTimeoutMs)); - - chip::Transport::OutgoingGroupSession session(groupId, fabricIndex); - ReturnErrorOnFailure(commandSender->SendGroupCommandRequest(chip::SessionHandle(session))); - commandSender.release(); - - return CHIP_NO_ERROR; - } - private: chip::ClusterId mClusterId; chip::CommandId mCommandId; @@ -183,5 +151,4 @@ class ClusterCommand : public ModelCommand, public chip::app::CommandSender::Cal CHIP_ERROR mError = CHIP_NO_ERROR; CustomArgument mPayload; - std::vector> mCommandSender; }; diff --git a/examples/chip-tool/commands/clusters/ReportCommand.h b/examples/chip-tool/commands/clusters/ReportCommand.h index 216551f7321ed3..58d997cc4f61ee 100644 --- a/examples/chip-tool/commands/clusters/ReportCommand.h +++ b/examples/chip-tool/commands/clusters/ReportCommand.h @@ -18,18 +18,16 @@ #pragma once -#include +#include #include "DataModelLogger.h" #include "ModelCommand.h" -constexpr uint8_t kMaxAllowedPaths = 10; - -class ReportCommand : public ModelCommand, public chip::app::ReadClient::Callback +class ReportCommand : public InteractionModelReports, public ModelCommand, public chip::app::ReadClient::Callback { public: ReportCommand(const char * commandName, CredentialIssuerCommands * credsIssuerConfig) : - ModelCommand(commandName, credsIssuerConfig), mBufferedReadAdapter(*this) + InteractionModelReports(this), ModelCommand(commandName, credsIssuerConfig) {} virtual void OnSubscription(){}; @@ -100,219 +98,13 @@ class ReportCommand : public ModelCommand, public chip::app::ReadClient::Callbac void OnDone() override { - mReadClient.reset(); + InteractionModelReports::Shutdown(); SetCommandExitStatus(mError); } void OnSubscriptionEstablished(uint64_t subscriptionId) override { OnSubscription(); } protected: - CHIP_ERROR ReportAttribute(chip::DeviceProxy * device, std::vector endpointIds, - std::vector clusterIds, std::vector attributeIds, - chip::app::ReadClient::InteractionType interactionType, uint16_t minInterval = 0, - uint16_t maxInterval = 0, - const chip::Optional> & dataVersions = chip::NullOptional) - { - const size_t clusterCount = clusterIds.size(); - const size_t attributeCount = attributeIds.size(); - const size_t endpointCount = endpointIds.size(); - const size_t dataVersionsCount = dataVersions.HasValue() ? dataVersions.Value().size() : 0; - - VerifyOrReturnError(clusterCount > 0 && clusterCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(attributeCount > 0 && attributeCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(endpointCount > 0 && endpointCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(dataVersionsCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); - - const bool hasSameIdsCount = (clusterCount == attributeCount) && (clusterCount == endpointCount) && - (dataVersionsCount == 0 || clusterCount == dataVersionsCount); - const bool multipleClusters = - clusterCount > 1 && attributeCount == 1 && endpointCount == 1 && (dataVersionsCount == 0 || dataVersionsCount == 1); - const bool multipleAttributes = - attributeCount > 1 && clusterCount == 1 && endpointCount == 1 && (dataVersionsCount == 0 || dataVersionsCount == 1); - const bool multipleEndpoints = - endpointCount > 1 && clusterCount == 1 && attributeCount == 1 && (dataVersionsCount == 0 || dataVersionsCount == 1); - const bool multipleDataVersions = dataVersionsCount > 1 && clusterCount == 1 && attributeCount == 1 && endpointCount == 1; - - size_t pathsCount = 0; - if (hasSameIdsCount) - { - pathsCount = clusterCount; - } - else if (multipleClusters) - { - pathsCount = clusterCount; - } - else if (multipleAttributes) - { - pathsCount = attributeCount; - } - else if (multipleEndpoints) - { - pathsCount = endpointCount; - } - else if (multipleDataVersions) - { - pathsCount = dataVersionsCount; - } - else - { - ChipLogError( - chipTool, - "\n%sAttribute commands targetting multiple paths needs to have: \n \t * One element with multiple ids (for " - "example 1 cluster id, 1 attribute id, 2 endpoint ids)\n\t * Or the same " - "number of ids (for examples 2 cluster ids, 2 attribute ids and 2 endpoint ids).\n The current command has %u " - "cluster ids, %u attribute ids, %u endpoint ids.", - interactionType == chip::app::ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read", - static_cast(clusterCount), static_cast(attributeCount), - static_cast(endpointCount)); - return CHIP_ERROR_INVALID_ARGUMENT; - } - - ChipLogProgress(chipTool, "Sending %sAttribute to:", - interactionType == chip::app::ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read"); - - chip::app::AttributePathParams attributePathParams[kMaxAllowedPaths]; - chip::app::DataVersionFilter dataVersionFilter[kMaxAllowedPaths]; - for (size_t i = 0; i < pathsCount; i++) - { - chip::ClusterId clusterId = clusterIds.at((hasSameIdsCount || multipleClusters) ? i : 0); - chip::AttributeId attributeId = attributeIds.at((hasSameIdsCount || multipleAttributes) ? i : 0); - chip::EndpointId endpointId = endpointIds.at((hasSameIdsCount || multipleEndpoints) ? i : 0); - - ChipLogProgress(chipTool, "\tcluster " ChipLogFormatMEI ", attribute: " ChipLogFormatMEI ", endpoint %u", - ChipLogValueMEI(clusterId), ChipLogValueMEI(attributeId), endpointId); - attributePathParams[i].mClusterId = clusterId; - attributePathParams[i].mAttributeId = attributeId; - attributePathParams[i].mEndpointId = endpointId; - - if (dataVersions.HasValue()) - { - chip::DataVersion dataVersion = dataVersions.Value().at((hasSameIdsCount || multipleDataVersions) ? i : 0); - dataVersionFilter[i].mEndpointId = endpointId; - dataVersionFilter[i].mClusterId = clusterId; - dataVersionFilter[i].mDataVersion.SetValue(dataVersion); - } - } - - chip::app::ReadPrepareParams params(device->GetSecureSession().Value()); - params.mpEventPathParamsList = nullptr; - params.mEventPathParamsListSize = 0; - params.mpAttributePathParamsList = attributePathParams; - params.mAttributePathParamsListSize = pathsCount; - - if (mFabricFiltered.HasValue()) - { - params.mIsFabricFiltered = mFabricFiltered.Value(); - } - - if (dataVersions.HasValue()) - { - params.mpDataVersionFilterList = dataVersionFilter; - params.mDataVersionFilterListSize = pathsCount; - } - - if (interactionType == chip::app::ReadClient::InteractionType::Subscribe) - { - params.mMinIntervalFloorSeconds = minInterval; - params.mMaxIntervalCeilingSeconds = maxInterval; - if (mKeepSubscriptions.HasValue()) - { - params.mKeepSubscriptions = mKeepSubscriptions.Value(); - } - } - - mReadClient = std::make_unique(chip::app::InteractionModelEngine::GetInstance(), - device->GetExchangeManager(), mBufferedReadAdapter, interactionType); - return mReadClient->SendRequest(params); - } - - CHIP_ERROR ReportEvent(chip::DeviceProxy * device, std::vector endpointIds, - std::vector clusterIds, std::vector eventIds, - chip::app::ReadClient::InteractionType interactionType, uint16_t minInterval = 0, - uint16_t maxInterval = 0) - { - const size_t clusterCount = clusterIds.size(); - const size_t eventCount = eventIds.size(); - const size_t endpointCount = endpointIds.size(); - - VerifyOrReturnError(clusterCount > 0 && clusterCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(eventCount > 0 && eventCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(endpointCount > 0 && endpointCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); - - const bool hasSameIdsCount = (clusterCount == eventCount) && (clusterCount == endpointCount); - const bool multipleClusters = clusterCount > 1 && eventCount == 1 && endpointCount == 1; - const bool multipleEvents = eventCount > 1 && clusterCount == 1 && endpointCount == 1; - const bool multipleEndpoints = endpointCount > 1 && clusterCount == 1 && eventCount == 1; - - size_t pathsCount = 0; - if (hasSameIdsCount) - { - pathsCount = clusterCount; - } - else if (multipleClusters) - { - pathsCount = clusterCount; - } - else if (multipleEvents) - { - pathsCount = eventCount; - } - else if (multipleEndpoints) - { - pathsCount = endpointCount; - } - else - { - ChipLogError(chipTool, - "\n%sEvent command targetting multiple paths needs to have: \n \t * One element with multiple ids (for " - "example 1 cluster id, 1 event id, 2 endpoint ids)\n\t * Or the same " - "number of ids (for examples 2 cluster ids, 2 event ids and 2 endpoint ids).\n The current command has %u " - "cluster ids, %u event ids, %u endpoint ids.", - interactionType == chip::app::ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read", - static_cast(clusterCount), static_cast(eventCount), - static_cast(endpointCount)); - return CHIP_ERROR_INVALID_ARGUMENT; - } - - chip::app::EventPathParams eventPathParams[kMaxAllowedPaths]; - - ChipLogProgress(chipTool, "Sending %sEvent to:", - interactionType == chip::app::ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read"); - for (size_t i = 0; i < pathsCount; i++) - { - chip::ClusterId clusterId = clusterIds.at((hasSameIdsCount || multipleClusters) ? i : 0); - chip::EventId eventId = eventIds.at((hasSameIdsCount || multipleEvents) ? i : 0); - chip::EndpointId endpointId = endpointIds.at((hasSameIdsCount || multipleEndpoints) ? i : 0); - - ChipLogProgress(chipTool, "\tcluster " ChipLogFormatMEI ", event: " ChipLogFormatMEI ", endpoint %u", - ChipLogValueMEI(clusterId), ChipLogValueMEI(eventId), endpointId); - eventPathParams[i].mClusterId = clusterId; - eventPathParams[i].mEventId = eventId; - eventPathParams[i].mEndpointId = endpointId; - } - - chip::app::ReadPrepareParams params(device->GetSecureSession().Value()); - params.mpEventPathParamsList = eventPathParams; - params.mEventPathParamsListSize = pathsCount; - params.mEventNumber = mEventNumber; - params.mpAttributePathParamsList = nullptr; - params.mAttributePathParamsListSize = 0; - - if (interactionType == chip::app::ReadClient::InteractionType::Subscribe) - { - params.mMinIntervalFloorSeconds = minInterval; - params.mMaxIntervalCeilingSeconds = maxInterval; - if (mKeepSubscriptions.HasValue()) - { - params.mKeepSubscriptions = mKeepSubscriptions.Value(); - } - } - - mReadClient = std::make_unique(chip::app::InteractionModelEngine::GetInstance(), - device->GetExchangeManager(), mBufferedReadAdapter, interactionType); - return mReadClient->SendRequest(params); - } - // Use a 3x-longer-than-default timeout because wildcard reads can take a // while. chip::System::Clock::Timeout GetWaitDuration() const override @@ -320,18 +112,6 @@ class ReportCommand : public ModelCommand, public chip::app::ReadClient::Callbac return mTimeout.HasValue() ? chip::System::Clock::Seconds16(mTimeout.Value()) : (ModelCommand::GetWaitDuration() * 3); } - std::unique_ptr mReadClient; - chip::app::BufferedReadCallback mBufferedReadAdapter; - - // mFabricFiltered is really only used by the attribute commands, but we end - // up needing it in our class's shared code. - chip::Optional mFabricFiltered; - - // mKeepSubscriptions is really only used by the subscribe commands, but we end - // up needing it in our class's shared code. - chip::Optional mKeepSubscriptions; - chip::Optional mEventNumber; - CHIP_ERROR mError = CHIP_NO_ERROR; }; @@ -371,13 +151,13 @@ class ReadAttribute : public ReportCommand CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override { - return ReportCommand::ReportAttribute(device, endpointIds, mClusterIds, mAttributeIds, - chip::app::ReadClient::InteractionType::Read, 0, 0, mDataVersion); + return ReportCommand::ReadAttribute(device, endpointIds, mClusterIds, mAttributeIds, mFabricFiltered, mDataVersion); } private: std::vector mClusterIds; std::vector mAttributeIds; + chip::Optional mFabricFiltered; chip::Optional> mDataVersion; }; @@ -426,9 +206,8 @@ class SubscribeAttribute : public ReportCommand CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override { - return ReportCommand::ReportAttribute(device, endpointIds, mClusterIds, mAttributeIds, - chip::app::ReadClient::InteractionType::Subscribe, mMinInterval, mMaxInterval, - mDataVersion); + return ReportCommand::SubscribeAttribute(device, endpointIds, mClusterIds, mAttributeIds, mMinInterval, mMaxInterval, + mFabricFiltered, mDataVersion, mKeepSubscriptions); } void OnSubscription() override @@ -441,7 +220,7 @@ class SubscribeAttribute : public ReportCommand auto * command = reinterpret_cast(arg); if (!command->IsInteractive()) { - command->mReadClient.reset(); + command->InteractionModelReports::Shutdown(); } command->SetCommandExitStatus(CHIP_NO_ERROR); }, @@ -454,7 +233,9 @@ class SubscribeAttribute : public ReportCommand uint16_t mMinInterval; uint16_t mMaxInterval; + chip::Optional mFabricFiltered; chip::Optional> mDataVersion; + chip::Optional mKeepSubscriptions; }; class ReadEvent : public ReportCommand @@ -490,13 +271,13 @@ class ReadEvent : public ReportCommand CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override { - return ReportCommand::ReportEvent(device, endpointIds, mClusterIds, mEventIds, - chip::app::ReadClient::InteractionType::Read); + return ReportCommand::ReadEvent(device, endpointIds, mClusterIds, mEventIds, mEventNumber); } private: std::vector mClusterIds; std::vector mEventIds; + chip::Optional mEventNumber; }; class SubscribeEvent : public ReportCommand @@ -544,8 +325,8 @@ class SubscribeEvent : public ReportCommand CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override { - return ReportCommand::ReportEvent(device, endpointIds, mClusterIds, mEventIds, - chip::app::ReadClient::InteractionType::Subscribe, mMinInterval, mMaxInterval); + return ReportCommand::SubscribeEvent(device, endpointIds, mClusterIds, mEventIds, mMinInterval, mMaxInterval, mEventNumber, + mKeepSubscriptions); } void OnSubscription() override @@ -558,7 +339,7 @@ class SubscribeEvent : public ReportCommand auto * command = reinterpret_cast(arg); if (!command->IsInteractive()) { - command->mReadClient.reset(); + command->InteractionModelReports::Shutdown(); } command->SetCommandExitStatus(CHIP_NO_ERROR); }, @@ -571,4 +352,6 @@ class SubscribeEvent : public ReportCommand uint16_t mMinInterval; uint16_t mMaxInterval; + chip::Optional mKeepSubscriptions; + chip::Optional mEventNumber; }; diff --git a/examples/chip-tool/commands/clusters/WriteAttributeCommand.h b/examples/chip-tool/commands/clusters/WriteAttributeCommand.h index dea6b9c5e159ee..8d2e8797c8b40a 100644 --- a/examples/chip-tool/commands/clusters/WriteAttributeCommand.h +++ b/examples/chip-tool/commands/clusters/WriteAttributeCommand.h @@ -18,15 +18,16 @@ #pragma once -#include +#include #include "DataModelLogger.h" #include "ModelCommand.h" -class WriteAttribute : public ModelCommand, public chip::app::WriteClient::Callback +class WriteAttribute : public InteractionModelWriter, public ModelCommand, public chip::app::WriteClient::Callback { public: - WriteAttribute(CredentialIssuerCommands * credsIssuerConfig) : ModelCommand("write-by-id", credsIssuerConfig) + WriteAttribute(CredentialIssuerCommands * credsIssuerConfig) : + InteractionModelWriter(this), ModelCommand("write-by-id", credsIssuerConfig) { AddArgument("cluster-id", 0, UINT32_MAX, &mClusterId); AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId); @@ -38,7 +39,7 @@ class WriteAttribute : public ModelCommand, public chip::app::WriteClient::Callb } WriteAttribute(chip::ClusterId clusterId, CredentialIssuerCommands * credsIssuerConfig) : - ModelCommand("write-by-id", credsIssuerConfig), mClusterId(clusterId) + InteractionModelWriter(this), ModelCommand("write-by-id", credsIssuerConfig), mClusterId(clusterId) { AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId); AddArgument("attribute-value", &mAttributeValue); @@ -49,7 +50,7 @@ class WriteAttribute : public ModelCommand, public chip::app::WriteClient::Callb } WriteAttribute(const char * attributeName, CredentialIssuerCommands * credsIssuerConfig) : - ModelCommand("write", credsIssuerConfig) + InteractionModelWriter(this), ModelCommand("write", credsIssuerConfig) { AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs); AddArgument("data-version", 0, UINT32_MAX, &mDataVersion); @@ -88,7 +89,7 @@ class WriteAttribute : public ModelCommand, public chip::app::WriteClient::Callb void OnDone(chip::app::WriteClient * client) override { - mWriteClient.reset(); + InteractionModelWriter::Shutdown(); SetCommandExitStatus(mError); } @@ -98,45 +99,17 @@ class WriteAttribute : public ModelCommand, public chip::app::WriteClient::Callb { ChipLogProgress(chipTool, "Sending WriteAttribute to cluster " ChipLogFormatMEI " on endpoint %u", ChipLogValueMEI(clusterId), endpointId); - chip::app::AttributePathParams attributePathParams; - if (!device->GetSecureSession().Value()->IsGroupSession()) - { - attributePathParams.mEndpointId = endpointId; - } - attributePathParams.mClusterId = clusterId; - attributePathParams.mAttributeId = attributeId; - - mWriteClient = std::make_unique(device->GetExchangeManager(), this, mTimedInteractionTimeoutMs, - mSuppressResponse.ValueOr(false)); - - ReturnErrorOnFailure(mWriteClient->EncodeAttribute(attributePathParams, value, mDataVersion)); - - return mWriteClient->SendWriteRequest(device->GetSecureSession().Value()); + return InteractionModelWriter::WriteAttribute(device, endpointId, clusterId, attributeId, value, mTimedInteractionTimeoutMs, + mSuppressResponse, mDataVersion); } template CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex, chip::ClusterId clusterId, chip::AttributeId attributeId, const T & value) { - - chip::app::AttributePathParams attributePathParams; - attributePathParams.mClusterId = clusterId; - attributePathParams.mAttributeId = attributeId; - - chip::Messaging::ExchangeManager * exchangeManager = chip::app::InteractionModelEngine::GetInstance()->GetExchangeManager(); - ChipLogDetail(chipTool, "Sending Write Attribute to Group %u, on Fabric %x, for cluster %u with attributeId %u", groupId, fabricIndex, clusterId, attributeId); - - auto writeClient = chip::Platform::MakeUnique(exchangeManager, this, mTimedInteractionTimeoutMs); - VerifyOrReturnError(writeClient != nullptr, CHIP_ERROR_NO_MEMORY); - ReturnErrorOnFailure(writeClient->EncodeAttribute(attributePathParams, value, mDataVersion)); - - chip::Transport::OutgoingGroupSession session(groupId, fabricIndex); - ReturnErrorOnFailure(writeClient->SendWriteRequest(chip::SessionHandle(session))); - writeClient.release(); - - return CHIP_NO_ERROR; + return InteractionModelWriter::WriteGroupAttribute(groupId, fabricIndex, clusterId, attributeId, value, mDataVersion); } private: @@ -147,5 +120,4 @@ class WriteAttribute : public ModelCommand, public chip::app::WriteClient::Callb chip::Optional mDataVersion = chip::NullOptional; chip::Optional mSuppressResponse; CustomArgument mAttributeValue; - std::unique_ptr mWriteClient; }; diff --git a/examples/chip-tool/templates/tests/partials/test_step.zapt b/examples/chip-tool/templates/tests/partials/test_step.zapt index 9558b8a6c9d203..00ba070d86276b 100644 --- a/examples/chip-tool/templates/tests/partials/test_step.zapt +++ b/examples/chip-tool/templates/tests/partials/test_step.zapt @@ -77,8 +77,8 @@ {{else if isSubscribeAttribute}} {{>attributeArguments}}, {{minInterval}}, {{maxInterval}}{{>maybeFabricFiltered~}} {{else if isWriteGroupAttribute}} {{>groupAttributeArguments}}, value{{>maybeTimedInteractionTimeout~}} {{else if isWriteAttribute}} {{>attributeArguments}}, value{{>maybeTimedInteractionTimeout~}} -{{else if isReadEvent}} {{>eventArguments}}{{>maybeFabricFiltered}} -{{else if isSubscribeEvent}} {{>eventArguments}}, {{minInterval}}, {{maxInterval}}{{>maybeFabricFiltered~}} +{{else if isReadEvent}} {{>eventArguments~}} +{{else if isSubscribeEvent}} {{>eventArguments}}, {{minInterval}}, {{maxInterval~}} {{else if isGroupCommand}} {{>groupCommandArguments}}, value{{>maybeTimedInteractionTimeout~}} {{else if isCommand}} {{>commandArguments}}, value{{>maybeTimedInteractionTimeout~}} {{/if}} diff --git a/src/app/tests/suites/commands/interaction_model/InteractionModel.cpp b/src/app/tests/suites/commands/interaction_model/InteractionModel.cpp index 583a15db9b1c46..0b845c980b42b4 100644 --- a/src/app/tests/suites/commands/interaction_model/InteractionModel.cpp +++ b/src/app/tests/suites/commands/interaction_model/InteractionModel.cpp @@ -27,69 +27,22 @@ CHIP_ERROR InteractionModel::ReadAttribute(const char * identity, EndpointId end DeviceProxy * device = GetDevice(identity); VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); - AttributePathParams attributePathParams[1]; - if (endpointId != kInvalidEndpointId) - { - attributePathParams[0].mEndpointId = endpointId; - } - - if (clusterId != kInvalidClusterId) - { - attributePathParams[0].mClusterId = clusterId; - } - - if (attributeId != kInvalidAttributeId) - { - attributePathParams[0].mAttributeId = attributeId; - } - - ReadPrepareParams params(device->GetSecureSession().Value()); - params.mpEventPathParamsList = nullptr; - params.mEventPathParamsListSize = 0; - params.mpAttributePathParamsList = attributePathParams; - params.mAttributePathParamsListSize = 1; - params.mIsFabricFiltered = fabricFiltered; - - mReadClient = std::make_unique(InteractionModelEngine::GetInstance(), device->GetExchangeManager(), - mBufferedReadAdapter, ReadClient::InteractionType::Read); - return mReadClient->SendRequest(params); + std::vector endpointIds = { endpointId }; + std::vector clusterIds = { clusterId }; + std::vector attributeIds = { attributeId }; + return InteractionModelReports::ReadAttribute(device, endpointIds, clusterIds, attributeIds, Optional(fabricFiltered)); } CHIP_ERROR InteractionModel::ReadEvent(const char * identity, EndpointId endpointId, ClusterId clusterId, EventId eventId, - bool fabricFiltered) + const Optional & eventNumber) { DeviceProxy * device = GetDevice(identity); VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); - EventPathParams eventPathParams[1]; - if (endpointId != kInvalidEndpointId) - { - eventPathParams[0].mEndpointId = endpointId; - } - - if (clusterId != kInvalidClusterId) - { - eventPathParams[0].mClusterId = clusterId; - } - - if (eventId != kInvalidEventId) - { - eventPathParams[0].mEventId = eventId; - } - - ReadPrepareParams params(device->GetSecureSession().Value()); - params.mpEventPathParamsList = eventPathParams; - params.mEventPathParamsListSize = 1; - params.mpAttributePathParamsList = nullptr; - params.mAttributePathParamsListSize = 0; - params.mIsFabricFiltered = fabricFiltered; - - // TODO: Add data version supports - mReadClient = std::make_unique(InteractionModelEngine::GetInstance(), device->GetExchangeManager(), - mBufferedReadAdapter, ReadClient::InteractionType::Read); - VerifyOrReturnError(mReadClient != nullptr, CHIP_ERROR_NO_MEMORY); - - return mReadClient->SendRequest(params); + std::vector endpointIds = { endpointId }; + std::vector clusterIds = { clusterId }; + std::vector eventIds = { eventId }; + return InteractionModelReports::ReadEvent(device, endpointIds, clusterIds, eventIds, eventNumber); } CHIP_ERROR InteractionModel::SubscribeAttribute(const char * identity, EndpointId endpointId, ClusterId clusterId, @@ -99,83 +52,31 @@ CHIP_ERROR InteractionModel::SubscribeAttribute(const char * identity, EndpointI DeviceProxy * device = GetDevice(identity); VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); - AttributePathParams attributePathParams[1]; - if (endpointId != kInvalidEndpointId) - { - attributePathParams[0].mEndpointId = endpointId; - } - - if (clusterId != kInvalidClusterId) - { - attributePathParams[0].mClusterId = clusterId; - } - - if (attributeId != kInvalidAttributeId) - { - attributePathParams[0].mAttributeId = attributeId; - } - - ReadPrepareParams params(device->GetSecureSession().Value()); - params.mpEventPathParamsList = nullptr; - params.mEventPathParamsListSize = 0; - params.mpAttributePathParamsList = attributePathParams; - params.mAttributePathParamsListSize = 1; - params.mMinIntervalFloorSeconds = minInterval; - params.mMaxIntervalCeilingSeconds = maxInterval; - params.mIsFabricFiltered = fabricFiltered; - - mSubscribeClient = std::make_unique(InteractionModelEngine::GetInstance(), device->GetExchangeManager(), - mBufferedReadAdapter, ReadClient::InteractionType::Subscribe); - VerifyOrReturnError(mSubscribeClient != nullptr, CHIP_ERROR_NO_MEMORY); - - return mSubscribeClient->SendRequest(params); + std::vector endpointIds = { endpointId }; + std::vector clusterIds = { clusterId }; + std::vector attributeIds = { attributeId }; + return InteractionModelReports::SubscribeAttribute(device, endpointIds, clusterIds, attributeIds, minInterval, maxInterval, + Optional(fabricFiltered)); } CHIP_ERROR InteractionModel::SubscribeEvent(const char * identity, EndpointId endpointId, ClusterId clusterId, EventId eventId, - uint16_t minInterval, uint16_t maxInterval, bool fabricFiltered) + uint16_t minInterval, uint16_t maxInterval, const Optional & eventNumber) { DeviceProxy * device = GetDevice(identity); VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); - EventPathParams eventPathParams[1]; - - if (endpointId != kInvalidEndpointId) - { - eventPathParams[0].mEndpointId = endpointId; - } - - if (clusterId != kInvalidClusterId) - { - eventPathParams[0].mClusterId = clusterId; - } - - if (eventId != kInvalidEventId) - { - eventPathParams[0].mEventId = eventId; - } - - ReadPrepareParams params(device->GetSecureSession().Value()); - params.mpEventPathParamsList = eventPathParams; - params.mEventPathParamsListSize = 1; - params.mpAttributePathParamsList = nullptr; - params.mAttributePathParamsListSize = 0; - params.mMinIntervalFloorSeconds = minInterval; - params.mMaxIntervalCeilingSeconds = maxInterval; - params.mIsFabricFiltered = fabricFiltered; - - mSubscribeClient = std::make_unique(InteractionModelEngine::GetInstance(), device->GetExchangeManager(), - mBufferedReadAdapter, ReadClient::InteractionType::Subscribe); - VerifyOrReturnError(mSubscribeClient != nullptr, CHIP_ERROR_NO_MEMORY); - - return mSubscribeClient->SendRequest(params); + std::vector endpointIds = { endpointId }; + std::vector clusterIds = { clusterId }; + std::vector eventIds = { eventId }; + return InteractionModelReports::SubscribeEvent(device, endpointIds, clusterIds, eventIds, minInterval, maxInterval, + eventNumber); } void InteractionModel::Shutdown() { - mReadClient.reset(); - mSubscribeClient.reset(); - mWriteClient.reset(); - mCommandSender.reset(); + InteractionModelReports::Shutdown(); + InteractionModelWriter::Shutdown(); + InteractionModelCommands::Shutdown(); } /////////// ReadClient Callback Interface ///////// @@ -198,7 +99,6 @@ void InteractionModel::OnError(CHIP_ERROR error) void InteractionModel::OnDone() { mReadClient.reset(); - // TODO: Close the subscribe client ContinueOnChipMainThread(CHIP_NO_ERROR); } @@ -240,6 +140,249 @@ void InteractionModel::OnError(const CommandSender * client, CHIP_ERROR error) void InteractionModel::OnDone(CommandSender * client) { - mCommandSender.reset(); - ContinueOnChipMainThread(CHIP_NO_ERROR); + if (mCommandSender.size()) + { + mCommandSender.front().reset(); + mCommandSender.erase(mCommandSender.begin()); + } + + // If the command is repeated N times, wait for all the responses to comes in + // before exiting. + if (!mCommandSender.size()) + { + ContinueOnChipMainThread(CHIP_NO_ERROR); + } +} + +CHIP_ERROR InteractionModelReports::ReportAttribute(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, + std::vector attributeIds, + chip::app::ReadClient::InteractionType interactionType, uint16_t minInterval, + uint16_t maxInterval, const chip::Optional & fabricFiltered, + const chip::Optional> & dataVersions, + const chip::Optional & keepSubscriptions) +{ + const size_t clusterCount = clusterIds.size(); + const size_t attributeCount = attributeIds.size(); + const size_t endpointCount = endpointIds.size(); + const size_t dataVersionsCount = dataVersions.HasValue() ? dataVersions.Value().size() : 0; + + VerifyOrReturnError(clusterCount > 0 && clusterCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(attributeCount > 0 && attributeCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(endpointCount > 0 && endpointCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(dataVersionsCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); + + const bool hasSameIdsCount = (clusterCount == attributeCount) && (clusterCount == endpointCount) && + (dataVersionsCount == 0 || clusterCount == dataVersionsCount); + const bool multipleClusters = + clusterCount > 1 && attributeCount == 1 && endpointCount == 1 && (dataVersionsCount == 0 || dataVersionsCount == 1); + const bool multipleAttributes = + attributeCount > 1 && clusterCount == 1 && endpointCount == 1 && (dataVersionsCount == 0 || dataVersionsCount == 1); + const bool multipleEndpoints = + endpointCount > 1 && clusterCount == 1 && attributeCount == 1 && (dataVersionsCount == 0 || dataVersionsCount == 1); + const bool multipleDataVersions = dataVersionsCount > 1 && clusterCount == 1 && attributeCount == 1 && endpointCount == 1; + + size_t pathsCount = 0; + if (hasSameIdsCount) + { + pathsCount = clusterCount; + } + else if (multipleClusters) + { + pathsCount = clusterCount; + } + else if (multipleAttributes) + { + pathsCount = attributeCount; + } + else if (multipleEndpoints) + { + pathsCount = endpointCount; + } + else if (multipleDataVersions) + { + pathsCount = dataVersionsCount; + } + else + { + ChipLogError(chipTool, + "\n%sAttribute commands targetting multiple paths needs to have: \n \t * One element with multiple ids (for " + "example 1 cluster id, 1 attribute id, 2 endpoint ids)\n\t * Or the same " + "number of ids (for examples 2 cluster ids, 2 attribute ids and 2 endpoint ids).\n The current command has %u " + "cluster ids, %u attribute ids, %u endpoint ids.", + interactionType == chip::app::ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read", + static_cast(clusterCount), static_cast(attributeCount), + static_cast(endpointCount)); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + ChipLogProgress(chipTool, "Sending %sAttribute to:", + interactionType == chip::app::ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read"); + + chip::app::AttributePathParams attributePathParams[kMaxAllowedPaths]; + chip::app::DataVersionFilter dataVersionFilter[kMaxAllowedPaths]; + for (size_t i = 0; i < pathsCount; i++) + { + chip::ClusterId clusterId = clusterIds.at((hasSameIdsCount || multipleClusters) ? i : 0); + chip::AttributeId attributeId = attributeIds.at((hasSameIdsCount || multipleAttributes) ? i : 0); + chip::EndpointId endpointId = endpointIds.at((hasSameIdsCount || multipleEndpoints) ? i : 0); + + ChipLogProgress(chipTool, "\tcluster " ChipLogFormatMEI ", attribute: " ChipLogFormatMEI ", endpoint %u", + ChipLogValueMEI(clusterId), ChipLogValueMEI(attributeId), endpointId); + + if (clusterId != kInvalidClusterId) + { + attributePathParams[i].mClusterId = clusterId; + } + + if (attributeId != kInvalidAttributeId) + { + attributePathParams[i].mAttributeId = attributeId; + } + + if (endpointId != kInvalidEndpointId) + { + attributePathParams[i].mEndpointId = endpointId; + } + + if (dataVersions.HasValue()) + { + chip::DataVersion dataVersion = dataVersions.Value().at((hasSameIdsCount || multipleDataVersions) ? i : 0); + dataVersionFilter[i].mEndpointId = endpointId; + dataVersionFilter[i].mClusterId = clusterId; + dataVersionFilter[i].mDataVersion.SetValue(dataVersion); + } + } + + chip::app::ReadPrepareParams params(device->GetSecureSession().Value()); + params.mpEventPathParamsList = nullptr; + params.mEventPathParamsListSize = 0; + params.mpAttributePathParamsList = attributePathParams; + params.mAttributePathParamsListSize = pathsCount; + + if (fabricFiltered.HasValue()) + { + params.mIsFabricFiltered = fabricFiltered.Value(); + } + + if (dataVersions.HasValue()) + { + params.mpDataVersionFilterList = dataVersionFilter; + params.mDataVersionFilterListSize = pathsCount; + } + + if (interactionType == chip::app::ReadClient::InteractionType::Subscribe) + { + params.mMinIntervalFloorSeconds = minInterval; + params.mMaxIntervalCeilingSeconds = maxInterval; + if (keepSubscriptions.HasValue()) + { + params.mKeepSubscriptions = keepSubscriptions.Value(); + } + } + + auto & client = interactionType == chip::app::ReadClient::InteractionType::Subscribe ? mSubscribeClient : mReadClient; + client = std::make_unique(chip::app::InteractionModelEngine::GetInstance(), device->GetExchangeManager(), + mBufferedReadAdapter, interactionType); + return client->SendRequest(params); +} + +CHIP_ERROR InteractionModelReports::ReportEvent(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector eventIds, + chip::app::ReadClient::InteractionType interactionType, uint16_t minInterval, + uint16_t maxInterval, const chip::Optional & eventNumber, + const chip::Optional & keepSubscriptions) +{ + const size_t clusterCount = clusterIds.size(); + const size_t eventCount = eventIds.size(); + const size_t endpointCount = endpointIds.size(); + + VerifyOrReturnError(clusterCount > 0 && clusterCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(eventCount > 0 && eventCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(endpointCount > 0 && endpointCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); + + const bool hasSameIdsCount = (clusterCount == eventCount) && (clusterCount == endpointCount); + const bool multipleClusters = clusterCount > 1 && eventCount == 1 && endpointCount == 1; + const bool multipleEvents = eventCount > 1 && clusterCount == 1 && endpointCount == 1; + const bool multipleEndpoints = endpointCount > 1 && clusterCount == 1 && eventCount == 1; + + size_t pathsCount = 0; + if (hasSameIdsCount) + { + pathsCount = clusterCount; + } + else if (multipleClusters) + { + pathsCount = clusterCount; + } + else if (multipleEvents) + { + pathsCount = eventCount; + } + else if (multipleEndpoints) + { + pathsCount = endpointCount; + } + else + { + ChipLogError(chipTool, + "\n%sEvent command targetting multiple paths needs to have: \n \t * One element with multiple ids (for " + "example 1 cluster id, 1 event id, 2 endpoint ids)\n\t * Or the same " + "number of ids (for examples 2 cluster ids, 2 event ids and 2 endpoint ids).\n The current command has %u " + "cluster ids, %u event ids, %u endpoint ids.", + interactionType == chip::app::ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read", + static_cast(clusterCount), static_cast(eventCount), + static_cast(endpointCount)); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + chip::app::EventPathParams eventPathParams[kMaxAllowedPaths]; + + ChipLogProgress(chipTool, "Sending %sEvent to:", + interactionType == chip::app::ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read"); + for (size_t i = 0; i < pathsCount; i++) + { + chip::ClusterId clusterId = clusterIds.at((hasSameIdsCount || multipleClusters) ? i : 0); + chip::EventId eventId = eventIds.at((hasSameIdsCount || multipleEvents) ? i : 0); + chip::EndpointId endpointId = endpointIds.at((hasSameIdsCount || multipleEndpoints) ? i : 0); + + ChipLogProgress(chipTool, "\tcluster " ChipLogFormatMEI ", event: " ChipLogFormatMEI ", endpoint %u", + ChipLogValueMEI(clusterId), ChipLogValueMEI(eventId), endpointId); + if (clusterId != chip::kInvalidClusterId) + { + eventPathParams[i].mClusterId = clusterId; + } + + if (eventId != chip::kInvalidEventId) + { + eventPathParams[i].mEventId = eventId; + } + + if (endpointId != chip::kInvalidEndpointId) + { + eventPathParams[i].mEndpointId = endpointId; + } + } + + chip::app::ReadPrepareParams params(device->GetSecureSession().Value()); + params.mpEventPathParamsList = eventPathParams; + params.mEventPathParamsListSize = pathsCount; + params.mEventNumber = eventNumber; + params.mpAttributePathParamsList = nullptr; + params.mAttributePathParamsListSize = 0; + + if (interactionType == chip::app::ReadClient::InteractionType::Subscribe) + { + params.mMinIntervalFloorSeconds = minInterval; + params.mMaxIntervalCeilingSeconds = maxInterval; + if (keepSubscriptions.HasValue()) + { + params.mKeepSubscriptions = keepSubscriptions.Value(); + } + } + + auto & client = interactionType == chip::app::ReadClient::InteractionType::Subscribe ? mSubscribeClient : mReadClient; + client = std::make_unique(chip::app::InteractionModelEngine::GetInstance(), device->GetExchangeManager(), + mBufferedReadAdapter, interactionType); + return client->SendRequest(params); } diff --git a/src/app/tests/suites/commands/interaction_model/InteractionModel.h b/src/app/tests/suites/commands/interaction_model/InteractionModel.h index ea571b03d39d09..dcf4789d35cab5 100644 --- a/src/app/tests/suites/commands/interaction_model/InteractionModel.h +++ b/src/app/tests/suites/commands/interaction_model/InteractionModel.h @@ -25,42 +25,162 @@ #include #include #include +#include -class InteractionModel : public chip::app::ReadClient::Callback, - public chip::app::WriteClient::Callback, - public chip::app::CommandSender::Callback +constexpr uint8_t kMaxAllowedPaths = 10; + +class InteractionModelReports { public: - InteractionModel() : mBufferedReadAdapter(*this), mChunkedWriteCallback(this){}; - virtual ~InteractionModel(){}; + InteractionModelReports(chip::app::ReadClient::Callback * callback) : mBufferedReadAdapter(*callback) {} - virtual void OnResponse(const chip::app::StatusIB & status, chip::TLV::TLVReader * data) = 0; - virtual CHIP_ERROR ContinueOnChipMainThread(CHIP_ERROR err) = 0; - virtual chip::DeviceProxy * GetDevice(const char * identity) = 0; +protected: + CHIP_ERROR ReadAttribute(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector attributeIds, + const chip::Optional & fabricFiltered = chip::Optional(true), + const chip::Optional> & dataVersions = chip::NullOptional) + { + return ReportAttribute(device, endpointIds, clusterIds, attributeIds, chip::app::ReadClient::InteractionType::Read, 0, 0, + fabricFiltered, dataVersions); + } - CHIP_ERROR ReadAttribute(const char * identity, chip::EndpointId endpointId, chip::ClusterId clusterId, - chip::AttributeId attributeId, bool fabricFiltered = true); + CHIP_ERROR SubscribeAttribute(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector attributeIds, + uint16_t minInterval = 0, uint16_t maxInterval = 0, + const chip::Optional & fabricFiltered = chip::Optional(true), + const chip::Optional> & dataVersions = chip::NullOptional, + const chip::Optional & keepSubscriptions = chip::NullOptional) + { + return ReportAttribute(device, endpointIds, clusterIds, attributeIds, chip::app::ReadClient::InteractionType::Subscribe, + minInterval, maxInterval, fabricFiltered, dataVersions, keepSubscriptions); + } - CHIP_ERROR SubscribeAttribute(const char * identity, chip::EndpointId endpointId, chip::ClusterId clusterId, - chip::AttributeId attributeId, uint16_t minInterval, uint16_t maxInterval, - bool fabricFiltered = true); + CHIP_ERROR ReportAttribute(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector attributeIds, + chip::app::ReadClient::InteractionType interactionType, uint16_t minInterval = 0, + uint16_t maxInterval = 0, const chip::Optional & fabricFiltered = chip::Optional(true), + const chip::Optional> & dataVersions = chip::NullOptional, + const chip::Optional & keepSubscriptions = chip::NullOptional); - CHIP_ERROR ReadEvent(const char * identity, chip::EndpointId endpointId, chip::ClusterId clusterId, chip::EventId eventId, - bool fabricFiltered = true); + CHIP_ERROR ReadEvent(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector eventIds, + const chip::Optional & eventNumber = chip::NullOptional) + { + return ReportEvent(device, endpointIds, clusterIds, eventIds, chip::app::ReadClient::InteractionType::Read, 0, 0, + eventNumber); + } - CHIP_ERROR SubscribeEvent(const char * identity, chip::EndpointId endpointId, chip::ClusterId clusterId, chip::EventId eventId, - uint16_t minInterval, uint16_t maxInterval, bool fabricFiltered = true); + CHIP_ERROR SubscribeEvent(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector eventIds, + uint16_t minInterval = 0, uint16_t maxInterval = 0, + const chip::Optional & eventNumber = chip::NullOptional, + const chip::Optional & keepSubscriptions = chip::NullOptional) + { + return ReportEvent(device, endpointIds, clusterIds, eventIds, chip::app::ReadClient::InteractionType::Subscribe, + minInterval, maxInterval, eventNumber, keepSubscriptions); + } - CHIP_ERROR WaitForReport() { return CHIP_NO_ERROR; } + CHIP_ERROR ReportEvent(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector eventIds, + chip::app::ReadClient::InteractionType interactionType, uint16_t minInterval = 0, + uint16_t maxInterval = 0, const chip::Optional & eventNumber = chip::NullOptional, + const chip::Optional & keepSubscriptions = chip::NullOptional); + + void Shutdown() + { + mSubscribeClient.reset(); + mReadClient.reset(); + } + + std::unique_ptr mReadClient; + std::unique_ptr mSubscribeClient; + chip::app::BufferedReadCallback mBufferedReadAdapter; +}; + +class InteractionModelCommands +{ +public: + InteractionModelCommands(chip::app::CommandSender::Callback * callback) : mCallback(callback) {} +protected: template - CHIP_ERROR WriteAttribute(const char * identity, chip::EndpointId endpointId, chip::ClusterId clusterId, - chip::AttributeId attributeId, const T & value, - chip::Optional timedInteractionTimeoutMs = chip::NullOptional) + CHIP_ERROR SendCommand(chip::DeviceProxy * device, chip::EndpointId endpointId, chip::ClusterId clusterId, + chip::CommandId commandId, const T & value, + chip::Optional timedInteractionTimeoutMs = chip::NullOptional, + chip::Optional repeatCount = chip::NullOptional, + chip::Optional repeatDelayInMs = chip::NullOptional, + chip::Optional suppressResponse = chip::NullOptional) { - chip::DeviceProxy * device = GetDevice(identity); - VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); + uint16_t repeat = repeatCount.ValueOr(1); + while (repeat--) + { + + chip::app::CommandPathParams commandPath = { endpointId, clusterId, commandId, + (chip::app::CommandPathFlags::kEndpointIdValid) }; + auto commandSender = std::make_unique(mCallback, device->GetExchangeManager(), + timedInteractionTimeoutMs.HasValue()); + VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY); + + ReturnErrorOnFailure(commandSender->AddRequestDataNoTimedCheck(commandPath, value, timedInteractionTimeoutMs, + suppressResponse.ValueOr(false))); + ReturnErrorOnFailure(commandSender->SendCommandRequest(device->GetSecureSession().Value())); + mCommandSender.push_back(std::move(commandSender)); + + if (repeatDelayInMs.HasValue()) + { + chip::test_utils::SleepMillis(repeatDelayInMs.Value()); + } + } + return CHIP_NO_ERROR; + } + + template + CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex, chip::ClusterId clusterId, + chip::CommandId commandId, const T & value) + { + chip::app::CommandPathParams commandPath = { groupId, clusterId, commandId, (chip::app::CommandPathFlags::kGroupIdValid) }; + + chip::Messaging::ExchangeManager * exchangeManager = chip::app::InteractionModelEngine::GetInstance()->GetExchangeManager(); + VerifyOrReturnError(exchangeManager != nullptr, CHIP_ERROR_INCORRECT_STATE); + + auto commandSender = chip::Platform::MakeUnique(mCallback, exchangeManager, false); + VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY); + + ReturnErrorOnFailure(commandSender->AddRequestDataNoTimedCheck(commandPath, value, chip::NullOptional)); + + chip::Transport::OutgoingGroupSession session(groupId, fabricIndex); + ReturnErrorOnFailure(commandSender->SendGroupCommandRequest(chip::SessionHandle(session))); + commandSender.release(); + + return CHIP_NO_ERROR; + } + void Shutdown() + { + for (auto & commandSender : mCommandSender) + { + commandSender.reset(); + } + mCommandSender.clear(); + } + + std::vector> mCommandSender; + chip::app::CommandSender::Callback * mCallback; +}; + +class InteractionModelWriter +{ +public: + InteractionModelWriter(chip::app::WriteClient::Callback * callback) : mChunkedWriteCallback(callback) {} + +protected: + template + CHIP_ERROR WriteAttribute(chip::DeviceProxy * device, chip::EndpointId endpointId, chip::ClusterId clusterId, + chip::AttributeId attributeId, const T & value, + const chip::Optional & timedInteractionTimeoutMs = chip::NullOptional, + const chip::Optional & suppressResponse = chip::NullOptional, + const chip::Optional & dataVersion = chip::NullOptional) + { chip::app::AttributePathParams attributePathParams; if (endpointId != chip::kInvalidEndpointId) { @@ -78,23 +198,18 @@ class InteractionModel : public chip::app::ReadClient::Callback, } mWriteClient = std::make_unique(device->GetExchangeManager(), &mChunkedWriteCallback, - timedInteractionTimeoutMs); + timedInteractionTimeoutMs, suppressResponse.ValueOr(false)); VerifyOrReturnError(mWriteClient != nullptr, CHIP_ERROR_NO_MEMORY); - // TODO: Add data version supports - chip::Optional dataVersion = chip::NullOptional; ReturnErrorOnFailure(mWriteClient->EncodeAttribute(attributePathParams, value, dataVersion)); return mWriteClient->SendWriteRequest(device->GetSecureSession().Value()); } template - CHIP_ERROR WriteGroupAttribute(const char * identity, chip::GroupId groupId, chip::ClusterId clusterId, + CHIP_ERROR WriteGroupAttribute(chip::GroupId groupId, chip::FabricIndex fabricIndex, chip::ClusterId clusterId, chip::AttributeId attributeId, const T & value, - chip::Optional timedInteractionTimeoutMs = chip::NullOptional) + const chip::Optional & dataVersion = chip::NullOptional) { - chip::DeviceProxy * device = GetDevice(identity); - VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); - chip::app::AttributePathParams attributePathParams; if (clusterId != chip::kInvalidClusterId) @@ -107,17 +222,78 @@ class InteractionModel : public chip::app::ReadClient::Callback, attributePathParams.mAttributeId = attributeId; } - mWriteClient = std::make_unique(device->GetExchangeManager(), &mChunkedWriteCallback, - timedInteractionTimeoutMs); - VerifyOrReturnError(mWriteClient != nullptr, CHIP_ERROR_NO_MEMORY); + chip::Messaging::ExchangeManager * exchangeManager = chip::app::InteractionModelEngine::GetInstance()->GetExchangeManager(); + VerifyOrReturnError(exchangeManager != nullptr, CHIP_ERROR_INCORRECT_STATE); - // TODO: Add data version supports - chip::Optional dataVersion = chip::NullOptional; - ReturnErrorOnFailure(mWriteClient->EncodeAttribute(attributePathParams, value, dataVersion)); + auto writeClient = + chip::Platform::MakeUnique(exchangeManager, &mChunkedWriteCallback, chip::NullOptional); + VerifyOrReturnError(writeClient != nullptr, CHIP_ERROR_NO_MEMORY); + ReturnErrorOnFailure(writeClient->EncodeAttribute(attributePathParams, value, dataVersion)); - chip::FabricIndex fabricIndex = device->GetSecureSession().Value()->GetFabricIndex(); chip::Transport::OutgoingGroupSession session(groupId, fabricIndex); - return mWriteClient->SendWriteRequest(chip::SessionHandle(session)); + ReturnErrorOnFailure(writeClient->SendWriteRequest(chip::SessionHandle(session))); + writeClient.release(); + + return CHIP_NO_ERROR; + } + + void Shutdown() { mWriteClient.reset(); } + + std::unique_ptr mWriteClient; + chip::app::ChunkedWriteCallback mChunkedWriteCallback; +}; + +class InteractionModel : public InteractionModelReports, + public InteractionModelCommands, + public InteractionModelWriter, + public chip::app::ReadClient::Callback, + public chip::app::WriteClient::Callback, + public chip::app::CommandSender::Callback +{ +public: + InteractionModel() : InteractionModelReports(this), InteractionModelCommands(this), InteractionModelWriter(this){}; + virtual ~InteractionModel(){}; + + virtual void OnResponse(const chip::app::StatusIB & status, chip::TLV::TLVReader * data) = 0; + virtual CHIP_ERROR ContinueOnChipMainThread(CHIP_ERROR err) = 0; + virtual chip::DeviceProxy * GetDevice(const char * identity) = 0; + + CHIP_ERROR ReadAttribute(const char * identity, chip::EndpointId endpointId, chip::ClusterId clusterId, + chip::AttributeId attributeId, bool fabricFiltered = true); + + CHIP_ERROR SubscribeAttribute(const char * identity, chip::EndpointId endpointId, chip::ClusterId clusterId, + chip::AttributeId attributeId, uint16_t minInterval, uint16_t maxInterval, + bool fabricFiltered = true); + + CHIP_ERROR ReadEvent(const char * identity, chip::EndpointId endpointId, chip::ClusterId clusterId, chip::EventId eventId, + const chip::Optional & eventNumber = chip::NullOptional); + + CHIP_ERROR SubscribeEvent(const char * identity, chip::EndpointId endpointId, chip::ClusterId clusterId, chip::EventId eventId, + uint16_t minInterval, uint16_t maxInterval, + const chip::Optional & eventNumber = chip::NullOptional); + + CHIP_ERROR WaitForReport() { return CHIP_NO_ERROR; } + + template + CHIP_ERROR WriteAttribute(const char * identity, chip::EndpointId endpointId, chip::ClusterId clusterId, + chip::AttributeId attributeId, const T & value, + chip::Optional timedInteractionTimeoutMs = chip::NullOptional) + { + chip::DeviceProxy * device = GetDevice(identity); + VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); + + return InteractionModelWriter::WriteAttribute(device, endpointId, clusterId, attributeId, value, timedInteractionTimeoutMs); + } + + template + CHIP_ERROR WriteGroupAttribute(const char * identity, chip::GroupId groupId, chip::ClusterId clusterId, + chip::AttributeId attributeId, const T & value) + { + chip::DeviceProxy * device = GetDevice(identity); + VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); + + chip::FabricIndex fabricIndex = device->GetSecureSession().Value()->GetFabricIndex(); + return InteractionModelWriter::WriteGroupAttribute(groupId, fabricIndex, clusterId, attributeId, value); } template @@ -127,34 +303,18 @@ class InteractionModel : public chip::app::ReadClient::Callback, chip::DeviceProxy * device = GetDevice(identity); VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); - chip::app::CommandPathParams commandPath = { endpointId, 0 /* groupId */, clusterId, commandId, - (chip::app::CommandPathFlags::kEndpointIdValid) }; - mCommandSender = - std::make_unique(this, device->GetExchangeManager(), timedInteractionTimeoutMs.HasValue()); - VerifyOrReturnError(mCommandSender != nullptr, CHIP_ERROR_NO_MEMORY); - - ReturnErrorOnFailure(mCommandSender->AddRequestDataNoTimedCheck(commandPath, value, timedInteractionTimeoutMs)); - return mCommandSender->SendCommandRequest(device->GetSecureSession().Value()); + return InteractionModelCommands::SendCommand(device, endpointId, clusterId, commandId, value, timedInteractionTimeoutMs); } template CHIP_ERROR SendGroupCommand(const char * identity, chip::GroupId groupId, chip::ClusterId clusterId, chip::CommandId commandId, - const T & value, chip::Optional timedInteractionTimeoutMs = chip::NullOptional) + const T & value) { chip::DeviceProxy * device = GetDevice(identity); VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); - chip::app::CommandPathParams commandPath = { 0 /* endpoint */, groupId, clusterId, commandId, - (chip::app::CommandPathFlags::kGroupIdValid) }; - - mCommandSender = - std::make_unique(this, device->GetExchangeManager(), timedInteractionTimeoutMs.HasValue()); - VerifyOrReturnError(mCommandSender != nullptr, CHIP_ERROR_NO_MEMORY); - chip::FabricIndex fabricIndex = device->GetSecureSession().Value()->GetFabricIndex(); - chip::Transport::OutgoingGroupSession session(groupId, fabricIndex); - ReturnErrorOnFailure(mCommandSender->AddRequestDataNoTimedCheck(commandPath, value, timedInteractionTimeoutMs)); - return mCommandSender->SendGroupCommandRequest(chip::SessionHandle(session)); + return InteractionModelCommands::SendGroupCommand(groupId, fabricIndex, clusterId, commandId, value); } void Shutdown(); @@ -179,14 +339,4 @@ class InteractionModel : public chip::app::ReadClient::Callback, const chip::app::StatusIB & status, chip::TLV::TLVReader * data) override; void OnError(const chip::app::CommandSender * client, CHIP_ERROR error) override; void OnDone(chip::app::CommandSender * client) override; - -protected: - std::unique_ptr mReadClient; - // TODO: Add multiple subscriptions at the same time supports - std::unique_ptr mSubscribeClient; - std::unique_ptr mWriteClient; - std::unique_ptr mCommandSender; - - chip::app::BufferedReadCallback mBufferedReadAdapter; - chip::app::ChunkedWriteCallback mChunkedWriteCallback; }; diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index f19509774ca73a..d4c0788239feb8 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -45181,15 +45181,11 @@ class TestEventsSuite : public TestCommand } case 1: { LogStep(1, "Check there is no event on the target endpoint"); - return ReadEvent(kIdentityAlpha, GetEndpoint(1), TestCluster::Id, TestCluster::Events::TestEvent::Id, false - - ); + return ReadEvent(kIdentityAlpha, GetEndpoint(1), TestCluster::Id, TestCluster::Events::TestEvent::Id); } case 2: { LogStep(2, "Check reading events from an invalid endpoint"); - return ReadEvent(kIdentityAlpha, GetEndpoint(0), TestCluster::Id, TestCluster::Events::TestEvent::Id, false - - ); + return ReadEvent(kIdentityAlpha, GetEndpoint(0), TestCluster::Id, TestCluster::Events::TestEvent::Id); } case 3: { LogStep(3, "Generate an event on the accessory"); @@ -45202,9 +45198,7 @@ class TestEventsSuite : public TestCommand } case 4: { LogStep(4, "Read the event back"); - return ReadEvent(kIdentityAlpha, GetEndpoint(1), TestCluster::Id, TestCluster::Events::TestEvent::Id, false - - ); + return ReadEvent(kIdentityAlpha, GetEndpoint(1), TestCluster::Id, TestCluster::Events::TestEvent::Id); } case 5: { LogStep(5, "Generate a second event on the accessory"); @@ -45218,14 +45212,12 @@ class TestEventsSuite : public TestCommand case 6: { LogStep(6, "Read the event back"); mTestSubStepCount = 2; - return ReadEvent(kIdentityAlpha, GetEndpoint(1), TestCluster::Id, TestCluster::Events::TestEvent::Id, false - - ); + return ReadEvent(kIdentityAlpha, GetEndpoint(1), TestCluster::Id, TestCluster::Events::TestEvent::Id); } case 7: { LogStep(7, "Subscribe to the event"); mTestSubStepCount = 2; - return SubscribeEvent(kIdentityAlpha, GetEndpoint(1), TestCluster::Id, TestCluster::Events::TestEvent::Id, 3, 5, false); + return SubscribeEvent(kIdentityAlpha, GetEndpoint(1), TestCluster::Id, TestCluster::Events::TestEvent::Id, 3, 5); } case 8: { LogStep(8, "Generate a third event on the accessory");