Skip to content

Commit

Permalink
[chip-tool] Add multiple writes in a single transaction support (#19566)
Browse files Browse the repository at this point in the history
* [chip-tv-casting-app] Update the TV casting app in order to share more code with chip-tool when it comes to commands parsing

* [chip-tool] Add std::vector<CustomArgument *> arguments support

* [chip-tool] Add vector arguments supports for write interactions

* Update generated code
  • Loading branch information
vivien-apple authored and pull[bot] committed Oct 30, 2023
1 parent 77cafa5 commit 8bef72e
Show file tree
Hide file tree
Showing 8 changed files with 6,911 additions and 14,419 deletions.
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
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;
};
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();
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
51 changes: 9 additions & 42 deletions examples/chip-tool/templates/commands.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -64,45 +64,6 @@ private:

{{/zcl_commands_source_client}}

{{#zcl_attributes_server}}
{{#if isWritable}}
class Write{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}: public WriteAttribute
{
public:
Write{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}(CredentialIssuerCommands * credsIssuerConfig): WriteAttribute("{{asUpperCamelCase name}}", credsIssuerConfig){{#if_chip_complex}}, mComplex(&mValue){{/if_chip_complex}}
{
AddArgument("attr-name", "{{asDelimitedCommand (asUpperCamelCase name)}}");
{{#if_chip_complex}}
AddArgument("attr-value", &mComplex);
{{else if (isString type)}}
AddArgument("attr-value", &mValue);
{{else}}
AddArgument("attr-value", {{asTypeMinValue type}}, {{asTypeMaxValue type}}, &mValue);
{{/if_chip_complex}}
WriteAttribute::AddArguments();
}

~Write{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}() {}

CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds) override
{
return WriteAttribute::SendCommand(device, endpointIds.at(0), {{asHex parent.code 8}}, {{asHex code 8}}, mValue);
}

CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override
{
return WriteAttribute::SendGroupCommand(groupId, fabricIndex, {{asHex parent.code 8}}, {{asHex code 8}}, mValue);
}

private:
{{zapTypeToEncodableClusterObjectType type ns=parent.name forceNotOptional=true}} mValue;
{{#if_chip_complex}}
TypedComplexArgument<{{zapTypeToEncodableClusterObjectType type ns=parent.name forceNotOptional=true}}> mComplex;
{{/if_chip_complex}}
};

{{/if}}
{{/zcl_attributes_server}}
{{/zcl_clusters}}

/*----------------------------------------------------------------------------*\
Expand Down Expand Up @@ -130,10 +91,16 @@ void registerCluster{{asUpperCamelCase name}}(Commands & commands, CredentialIss
{{#zcl_attributes_server}}
make_unique<ReadAttribute>(Id, "{{asDelimitedCommand (asUpperCamelCase name)}}", Attributes::{{asUpperCamelCase name}}::Id, credsIssuerConfig), //
{{/zcl_attributes_server}}
make_unique<WriteAttribute>(Id, credsIssuerConfig), //
make_unique<WriteAttribute<>>(Id, credsIssuerConfig), //
{{#zcl_attributes_server}}
{{#if isWritable}}
make_unique<Write{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}>(credsIssuerConfig), //
{{#if_chip_complex}}
make_unique<WriteAttributeAsComplex<{{zapTypeToEncodableClusterObjectType type ns=parent.name forceNotOptional=true}}>>(Id, "{{asDelimitedCommand (asUpperCamelCase name)}}", Attributes::{{asUpperCamelCase name}}::Id, credsIssuerConfig), //
{{else if (isString type)}}
make_unique<WriteAttribute<{{zapTypeToEncodableClusterObjectType type ns=parent.name forceNotOptional=true}}>>(Id, "{{asDelimitedCommand (asUpperCamelCase name)}}", Attributes::{{asUpperCamelCase name}}::Id, credsIssuerConfig), //
{{else}}
make_unique<WriteAttribute<{{zapTypeToEncodableClusterObjectType type ns=parent.name forceNotOptional=true}}>>(Id, "{{asDelimitedCommand (asUpperCamelCase name)}}", {{asTypeMinValue type}}, {{asTypeMaxValue type}}, Attributes::{{asUpperCamelCase name}}::Id, credsIssuerConfig), //
{{/if_chip_complex}}
{{/if}}
{{/zcl_attributes_server}}
make_unique<SubscribeAttribute>(Id, credsIssuerConfig), //
Expand Down Expand Up @@ -166,7 +133,7 @@ void registerClusterAny(Commands & commands, CredentialIssuerCommands * credsIss
commands_list clusterCommands = {
make_unique<ClusterCommand>(credsIssuerConfig), //
make_unique<ReadAttribute>(credsIssuerConfig), //
make_unique<WriteAttribute>(credsIssuerConfig), //
make_unique<WriteAttribute<>>(credsIssuerConfig), //
make_unique<SubscribeAttribute>(credsIssuerConfig), //
make_unique<ReadEvent>(credsIssuerConfig), //
make_unique<SubscribeEvent>(credsIssuerConfig), //
Expand Down
Loading

0 comments on commit 8bef72e

Please sign in to comment.