Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[chip-tool] Add multiple writes in a single transaction support #19566

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/chip-tool/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ config("config") {
]

defines = [
"CONFIG_USE_LOCAL_STORAGE=${config_use_local_storage}",
"CONFIG_USE_SEPARATE_EVENTLOOP=${config_use_separate_eventloop}",
"CONFIG_USE_INTERACTIVE_MODE=${config_use_interactive_mode}",
"CONFIG_ENABLE_YAML_TESTS=${config_enable_yaml_tests}",
Expand All @@ -49,10 +50,13 @@ static_library("chip-tool-utils") {
"${chip_root}/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp",
"${chip_root}/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp",
"commands/clusters/ModelCommand.cpp",
"commands/clusters/ModelCommand.h",
"commands/common/CHIPCommand.cpp",
"commands/common/CHIPCommand.h",
"commands/common/Command.cpp",
"commands/common/Command.h",
"commands/common/Commands.cpp",
"commands/common/Commands.h",
"commands/common/CredentialIssuerCommands.h",
"commands/discover/DiscoverCommand.cpp",
"commands/discover/DiscoverCommissionablesCommand.cpp",
Expand Down
1 change: 1 addition & 0 deletions examples/chip-tool/chip-tool.gni
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ declare_args() {
config_use_separate_eventloop = true
config_use_interactive_mode = true
config_enable_yaml_tests = true
config_use_local_storage = true
}
11 changes: 10 additions & 1 deletion examples/chip-tool/commands/clusters/ComplexArgument.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,17 @@ template <typename T>
class TypedComplexArgument : public ComplexArgument
{
public:
TypedComplexArgument() {}
TypedComplexArgument(T * request) : mRequest(request) {}
~TypedComplexArgument() { ComplexArgumentParser::Finalize(*mRequest); }
~TypedComplexArgument()
{
if (mRequest != nullptr)
{
ComplexArgumentParser::Finalize(*mRequest);
}
}

void SetArgument(T * request) { mRequest = request; };

CHIP_ERROR Parse(const char * label, const char * json)
{
Expand Down
3 changes: 3 additions & 0 deletions examples/chip-tool/commands/clusters/ModelCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

#pragma once

#ifdef CONFIG_USE_LOCAL_STORAGE
#include "../../config/PersistentStorage.h"
#endif // CONFIG_USE_LOCAL_STORAGE

#include "../common/CHIPCommand.h"
#include <lib/core/CHIPEncoding.h>

Expand Down
5 changes: 5 additions & 0 deletions examples/chip-tool/commands/clusters/SubscriptionsCommands.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@

#pragma once

#include <lib/core/CHIPError.h>

#include <commands/common/CHIPCommand.h>
#include <commands/common/Commands.h>

class ShutdownSubscription : public CHIPCommand
{
public:
Expand Down
158 changes: 133 additions & 25 deletions examples/chip-tool/commands/clusters/WriteAttributeCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,83 @@
#include "DataModelLogger.h"
#include "ModelCommand.h"

template <class T = std::vector<CustomArgument *>>
class WriteAttribute : public InteractionModelWriter, public ModelCommand, public chip::app::WriteClient::Callback
{
public:
WriteAttribute(CredentialIssuerCommands * credsIssuerConfig) :
InteractionModelWriter(this), ModelCommand("write-by-id", credsIssuerConfig)
{
AddArgument("cluster-id", 0, UINT32_MAX, &mClusterId);
AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId);
AddArgument("attribute-value", &mAttributeValue);
AddArgumentClusterIds();
AddArgumentAttributeIds();
AddArgumentAttributeValues();
AddArguments();
}

WriteAttribute(chip::ClusterId clusterId, CredentialIssuerCommands * credsIssuerConfig) :
InteractionModelWriter(this), ModelCommand("write-by-id", credsIssuerConfig), mClusterId(clusterId)
InteractionModelWriter(this), ModelCommand("write-by-id", credsIssuerConfig), mClusterIds(1, clusterId)
{
AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId);
AddArgument("attribute-value", &mAttributeValue);
AddArgumentAttributeIds();
AddArgumentAttributeValues();
AddArguments();
}

template <typename minType, typename maxType>
WriteAttribute(chip::ClusterId clusterId, const char * attributeName, minType minValue, maxType maxValue,
chip::AttributeId attributeId, CredentialIssuerCommands * credsIssuerConfig) :
WriteAttribute(clusterId, attributeId, credsIssuerConfig)
{
AddArgumentAttributeName(attributeName);
AddArgumentAttributeValues(static_cast<int64_t>(minValue), static_cast<uint64_t>(maxValue));
AddArguments();
}

WriteAttribute(chip::ClusterId clusterId, const char * attributeName, float minValue, float maxValue,
chip::AttributeId attributeId, CredentialIssuerCommands * credsIssuerConfig) :
WriteAttribute(clusterId, attributeId, credsIssuerConfig)
{
AddArgumentAttributeName(attributeName);
AddArgumentAttributeValues(minValue, maxValue);
AddArguments();
}

WriteAttribute(chip::ClusterId clusterId, const char * attributeName, double minValue, double maxValue,
chip::AttributeId attributeId, CredentialIssuerCommands * credsIssuerConfig) :
WriteAttribute(clusterId, attributeId, credsIssuerConfig)
{
AddArgumentAttributeName(attributeName);
AddArgumentAttributeValues(minValue, maxValue);
AddArguments();
}

WriteAttribute(chip::ClusterId clusterId, const char * attributeName, chip::AttributeId attributeId,
CredentialIssuerCommands * credsIssuerConfig) :
WriteAttribute(clusterId, attributeId, credsIssuerConfig)
{
AddArgumentAttributeName(attributeName);
AddArgumentAttributeValues();
AddArguments();
}

WriteAttribute(chip::ClusterId clusterId, const char * attributeName, chip::AttributeId attributeId,
TypedComplexArgument<T> & attributeParser, CredentialIssuerCommands * credsIssuerConfig) :
WriteAttribute(clusterId, attributeId, credsIssuerConfig)
{
AddArgumentAttributeName(attributeName);
AddArgumentAttributeValues(attributeParser);
AddArguments();
}

~WriteAttribute() {}

CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds) override
{
return WriteAttribute::SendCommand(device, endpointIds.at(0), mClusterId, mAttributeId, mAttributeValue);
return WriteAttribute::SendCommand(device, endpointIds, mClusterIds, mAttributeIds, mAttributeValues);
}

CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override
{
return WriteAttribute::SendGroupCommand(groupId, fabricIndex, mClusterId, mAttributeId, mAttributeValue);
return WriteAttribute::SendGroupCommand(groupId, fabricIndex, mClusterIds, mAttributeIds, mAttributeValues);
}

/////////// WriteClient Callback Interface /////////
Expand All @@ -79,23 +126,27 @@ class WriteAttribute : public InteractionModelWriter, public ModelCommand, publi
SetCommandExitStatus(mError);
}

template <class T>
CHIP_ERROR SendCommand(chip::DeviceProxy * device, chip::EndpointId endpointId, chip::ClusterId clusterId,
chip::AttributeId attributeId, const T & value)
CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds,
std::vector<chip::ClusterId> clusterIds, std::vector<chip::AttributeId> attributeIds, const T & values)
{
ChipLogProgress(chipTool, "Sending WriteAttribute to cluster " ChipLogFormatMEI " on endpoint %u",
ChipLogValueMEI(clusterId), endpointId);
return InteractionModelWriter::WriteAttribute(device, endpointId, clusterId, attributeId, value, mTimedInteractionTimeoutMs,
mSuppressResponse, mDataVersion, mRepeatCount, mRepeatDelayInMs);
return InteractionModelWriter::WriteAttribute(device, endpointIds, clusterIds, attributeIds, values,
mTimedInteractionTimeoutMs, mSuppressResponse, mDataVersions, mRepeatCount,
mRepeatDelayInMs);
}

template <class T>
CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex, chip::ClusterId clusterId,
chip::AttributeId attributeId, const T & value)
CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex, std::vector<chip::ClusterId> clusterIds,
std::vector<chip::AttributeId> attributeIds, const T & value)
{
ChipLogDetail(chipTool, "Sending Write Attribute to Group %u, on Fabric %x, for cluster %u with attributeId %u", groupId,
fabricIndex, clusterId, attributeId);
return InteractionModelWriter::WriteGroupAttribute(groupId, fabricIndex, clusterId, attributeId, value, mDataVersion);
fabricIndex, clusterIds.at(0), attributeIds.at(0));
chip::Optional<chip::DataVersion> dataVersion = chip::NullOptional;
if (mDataVersions.HasValue())
{
dataVersion.SetValue(mDataVersions.Value().at(0));
}

return InteractionModelWriter::WriteGroupAttribute(groupId, fabricIndex, clusterIds.at(0), attributeIds.at(0), value,
dataVersion);
}

protected:
Expand All @@ -105,25 +156,82 @@ class WriteAttribute : public InteractionModelWriter, public ModelCommand, publi
// Subclasses are responsible for calling AddArguments.
}

void AddArgumentClusterIds()
{
AddArgument("cluster-ids", 0, UINT32_MAX, &mClusterIds,
"Comma-separated list of cluster ids to write to (e.g. \"6\" or \"6,0x201\").");
}

void AddArgumentAttributeIds()
{
AddArgument("attribute-ids", 0, UINT32_MAX, &mAttributeIds,
"Comma-separated list of attribute ids to write (e.g. \"16385\" or \"16385,0x4002\").");
}

void AddArgumentAttributeName(const char * attributeName)
{
AddArgument("attribute-name", attributeName, "The attribute name to write.");
}

template <typename minType, typename maxType>
void AddArgumentAttributeValues(minType minValue, maxType maxValue)
{
AddArgument("attribute-values", minValue, maxValue, &mAttributeValues,
"Comma-separated list of attribute values to write.");
}

void AddArgumentAttributeValues()
{
AddArgument("attribute-values", &mAttributeValues, "Comma-separated list of attribute values to write.");
}

void AddArgumentAttributeValues(TypedComplexArgument<T> & attributeParser)
{
attributeParser.SetArgument(&mAttributeValues);
AddArgument("attribute-values", &attributeParser, "Comma-separated list of attribute values to write.");
}

void AddArguments()
{
AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs,
"If provided, do a timed write with the given timed interaction timeout.");
AddArgument("data-version", 0, UINT32_MAX, &mDataVersion);
AddArgument("data-version", 0, UINT32_MAX, &mDataVersions,
"Comma-separated list of data versions for the clusters being written.");
AddArgument("suppressResponse", 0, 1, &mSuppressResponse);
AddArgument("repeat-count", 1, UINT16_MAX, &mRepeatCount);
AddArgument("repeat-delay-ms", 0, UINT16_MAX, &mRepeatDelayInMs);
ModelCommand::AddArguments();
}

private:
chip::ClusterId mClusterId;
chip::AttributeId mAttributeId;
// This constructor is private as it is not intended to be used from outside the class.
WriteAttribute(chip::ClusterId clusterId, chip::AttributeId attributeId, CredentialIssuerCommands * credsIssuerConfig) :
InteractionModelWriter(this), ModelCommand("write", credsIssuerConfig), mClusterIds(1, clusterId),
mAttributeIds(1, attributeId)
{}

std::vector<chip::ClusterId> mClusterIds;
std::vector<chip::AttributeId> mAttributeIds;

CHIP_ERROR mError = CHIP_NO_ERROR;
chip::Optional<uint16_t> mTimedInteractionTimeoutMs;
chip::Optional<chip::DataVersion> mDataVersion = chip::NullOptional;
chip::Optional<std::vector<chip::DataVersion>> mDataVersions;
chip::Optional<bool> mSuppressResponse;
CustomArgument mAttributeValue;
chip::Optional<uint16_t> mRepeatCount;
chip::Optional<uint16_t> mRepeatDelayInMs;

T mAttributeValues;
};

template <class T>
class WriteAttributeAsComplex : public WriteAttribute<T>
{
public:
WriteAttributeAsComplex(chip::ClusterId clusterId, const char * attributeName, chip::AttributeId attributeId,
CredentialIssuerCommands * credsIssuerConfig) :
WriteAttribute<T>(clusterId, attributeName, attributeId, mAttributeParser, credsIssuerConfig)
{}

private:
TypedComplexArgument<T> mAttributeParser;
};
8 changes: 6 additions & 2 deletions examples/chip-tool/commands/common/CHIPCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@

#pragma once

#ifdef CONFIG_USE_LOCAL_STORAGE
#include "../../config/PersistentStorage.h"
#endif // CONFIG_USE_LOCAL_STORAGE

#include "Command.h"

#include <commands/common/CredentialIssuerCommands.h>
#include <commands/example/ExampleCredentialIssuerCommands.h>
#include <credentials/GroupDataProviderImpl.h>
#include <crypto/PersistentStorageOperationalKeystore.h>

#pragma once

class PersistentStorage;

constexpr const char kIdentityAlpha[] = "alpha";
constexpr const char kIdentityBeta[] = "beta";
constexpr const char kIdentityGamma[] = "gamma";
Expand Down Expand Up @@ -114,8 +116,10 @@ class CHIPCommand : public Command
// Execute any deferred cleanups. Used when exiting interactive mode.
void ExecuteDeferredCleanups();

#ifdef CONFIG_USE_LOCAL_STORAGE
PersistentStorage mDefaultStorage;
PersistentStorage mCommissionerStorage;
#endif // CONFIG_USE_LOCAL_STORAGE
chip::PersistentStorageOperationalKeystore mOperationalKeystore;

chip::Credentials::GroupDataProviderImpl mGroupDataProvider{ kMaxGroupsPerFabric, kMaxGroupKeysPerFabric };
Expand Down
38 changes: 38 additions & 0 deletions examples/chip-tool/commands/common/Command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,23 @@ bool Command::InitArgument(size_t argIndex, char * argValue)
return true;
}

case ArgumentType::VectorCustom: {
auto vectorArgument = static_cast<std::vector<CustomArgument *> *>(arg.value);

std::stringstream ss(argValue);
while (ss.good())
{
std::string valueAsString;
getline(ss, valueAsString, ',');

CustomArgument * customArgument = new CustomArgument();
vivien-apple marked this conversation as resolved.
Show resolved Hide resolved
vectorArgument->push_back(customArgument);
VerifyOrReturnError(CHIP_NO_ERROR == vectorArgument->back()->Parse(arg.name, valueAsString.c_str()), false);
}

return true;
}

case ArgumentType::Attribute: {
if (arg.isOptional() || arg.isNullable())
{
Expand Down Expand Up @@ -695,6 +712,18 @@ size_t Command::AddArgument(const char * name, CustomArgument * value, const cha
return AddArgumentToList(std::move(arg));
}

size_t Command::AddArgument(const char * name, std::vector<CustomArgument *> * value, const char * desc)
{
Argument arg;
arg.type = ArgumentType::VectorCustom;
arg.name = name;
arg.value = static_cast<void *>(value);
arg.flags = 0;
arg.desc = desc;

return AddArgumentToList(std::move(arg));
}

size_t Command::AddArgument(const char * name, float min, float max, float * out, const char * desc, uint8_t flags)
{
Argument arg;
Expand Down Expand Up @@ -855,5 +884,14 @@ void Command::ResetArguments()
optionalArgument->Value().clear();
}
}
else if (type == ArgumentType::VectorCustom && flags != Argument::kOptional)
{
auto vectorArgument = static_cast<std::vector<CustomArgument *> *>(arg.value);
for (auto & customArgument : *vectorArgument)
{
delete customArgument;
}
vectorArgument->clear();
}
}
}
2 changes: 2 additions & 0 deletions examples/chip-tool/commands/common/Command.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ enum ArgumentType
VectorBool,
Vector16,
Vector32,
VectorCustom,
};

struct Argument
Expand Down Expand Up @@ -179,6 +180,7 @@ class Command

size_t AddArgument(const char * name, int64_t min, uint64_t max, std::vector<uint16_t> * value, const char * desc = "");
size_t AddArgument(const char * name, int64_t min, uint64_t max, std::vector<uint32_t> * value, const char * desc = "");
size_t AddArgument(const char * name, std::vector<CustomArgument *> * value, const char * desc = "");
size_t AddArgument(const char * name, int64_t min, uint64_t max, chip::Optional<std::vector<bool>> * value,
const char * desc = "");
size_t AddArgument(const char * name, int64_t min, uint64_t max, chip::Optional<std::vector<uint32_t>> * value,
Expand Down
Loading