Skip to content

Commit

Permalink
[chip-tool] Add subscribe-all command (#20868)
Browse files Browse the repository at this point in the history
* [chip-tool] Update read-all command such that an arbitrary number of attributes/events can be used

* [chip-tool] Add subscribe-all command to chip-tool

* Update generated code
  • Loading branch information
vivien-apple authored and pull[bot] committed Dec 20, 2023
1 parent e723694 commit 1097191
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 14 deletions.
70 changes: 68 additions & 2 deletions examples/chip-tool/commands/clusters/ReportCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,20 @@ class ReadAll : public ReadCommand
public:
ReadAll(CredentialIssuerCommands * credsIssuerConfig) : ReadCommand("read-all", credsIssuerConfig)
{
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered);
AddArgument("cluster-ids", 0, UINT32_MAX, &mClusterIds,
"Comma-separated list of cluster ids to read from (e.g. \"6\" or \"8,0x201\").\n Allowed to be 0xFFFFFFFF to "
"indicate a wildcard cluster.");
AddArgument("attribute-ids", 0, UINT32_MAX, &mAttributeIds,
"Comma-separated list of attribute ids to read (e.g. \"0\" or \"1,0xFFFC,0xFFFD\").\n Allowed to be "
"0xFFFFFFFF to indicate a wildcard attribute.");
AddArgument("event-ids", 0, UINT32_MAX, &mEventIds,
"Comma-separated list of event ids to read (e.g. \"0\" or \"1,2,3\").\n Allowed to be "
"0xFFFFFFFF to indicate a wildcard event.");
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered,
"Boolean indicating whether to do a fabric-filtered read. Defaults to true.");
AddArgument("data-versions", 0, UINT32_MAX, &mDataVersions,
"Comma-separated list of data versions for the clusters being read.");
AddArgument("event-min", 0, UINT64_MAX, &mEventNumber);
ReadCommand::AddArguments();
}

Expand All @@ -432,9 +445,62 @@ class ReadAll : public ReadCommand

CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds) override
{
return ReadCommand::ReadAll(device, endpointIds, mFabricFiltered);
return ReadCommand::ReadAll(device, endpointIds, mClusterIds, mAttributeIds, mEventIds, mFabricFiltered, mDataVersions,
mEventNumber);
}

private:
std::vector<chip::ClusterId> mClusterIds;
std::vector<chip::AttributeId> mAttributeIds;
std::vector<chip::EventId> mEventIds;

chip::Optional<bool> mFabricFiltered;
chip::Optional<std::vector<chip::DataVersion>> mDataVersions;
chip::Optional<chip::EventNumber> mEventNumber;
};

class SubscribeAll : public SubscribeCommand
{
public:
SubscribeAll(CredentialIssuerCommands * credsIssuerConfig) : SubscribeCommand("subscribe-all", credsIssuerConfig)
{
AddArgument("cluster-ids", 0, UINT32_MAX, &mClusterIds,
"Comma-separated list of cluster ids to read from (e.g. \"6\" or \"8,0x201\").\n Allowed to be 0xFFFFFFFF to "
"indicate a wildcard cluster.");
AddArgument("attribute-ids", 0, UINT32_MAX, &mAttributeIds,
"Comma-separated list of attribute ids to read (e.g. \"0\" or \"1,0xFFFC,0xFFFD\").\n Allowed to be "
"0xFFFFFFFF to indicate a wildcard attribute.");
AddArgument("event-ids", 0, UINT32_MAX, &mEventIds,
"Comma-separated list of event ids to read (e.g. \"0\" or \"1,2,3\").\n Allowed to be "
"0xFFFFFFFF to indicate a wildcard event.");
AddArgument("min-interval", 0, UINT16_MAX, &mMinInterval,
"The requested minimum interval between reports. Sets MinIntervalFloor in the Subscribe Request.");
AddArgument("max-interval", 0, UINT16_MAX, &mMaxInterval,
"The requested maximum interval between reports. Sets MaxIntervalCeiling in the Subscribe Request.");
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered,
"Boolean indicating whether to do a fabric-filtered read. Defaults to true.");
AddArgument("event-min", 0, UINT64_MAX, &mEventNumber);
AddArgument("keepSubscriptions", 0, 1, &mKeepSubscriptions,
"false - Terminate existing subscriptions from initiator.\n true - Leave existing subscriptions in place.");
SubscribeCommand::AddArguments();
}

~SubscribeAll() {}

CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds) override
{
return SubscribeCommand::SubscribeAll(device, endpointIds, mClusterIds, mAttributeIds, mEventIds, mMinInterval,
mMaxInterval, mFabricFiltered, mEventNumber, mKeepSubscriptions);
}

private:
std::vector<chip::ClusterId> mClusterIds;
std::vector<chip::AttributeId> mAttributeIds;
std::vector<chip::EventId> mEventIds;

uint16_t mMinInterval;
uint16_t mMaxInterval;
chip::Optional<bool> mFabricFiltered;
chip::Optional<chip::EventNumber> mEventNumber;
chip::Optional<bool> mKeepSubscriptions;
};
1 change: 1 addition & 0 deletions examples/chip-tool/templates/commands.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ void registerClusterAny(Commands & commands, CredentialIssuerCommands * credsIss
make_unique<ReadEvent>(credsIssuerConfig), //
make_unique<SubscribeEvent>(credsIssuerConfig), //
make_unique<ReadAll>(credsIssuerConfig), //
make_unique<SubscribeAll>(credsIssuerConfig), //
};

commands.Register(clusterName, clusterCommands);
Expand Down
116 changes: 105 additions & 11 deletions src/app/tests/suites/commands/interaction_model/InteractionModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,35 +449,129 @@ void InteractionModelReports::CleanupReadClient(ReadClient * aReadClient)
mReadClients.end());
}

CHIP_ERROR InteractionModelReports::ReadAll(DeviceProxy * device, std::vector<EndpointId> endpointIds,
const Optional<bool> & fabricFiltered)
CHIP_ERROR InteractionModelReports::ReportAll(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds,
std::vector<chip::ClusterId> clusterIds, std::vector<chip::AttributeId> attributeIds,
std::vector<chip::EventId> eventIds,
chip::app::ReadClient::InteractionType interactionType, uint16_t minInterval,
uint16_t maxInterval, const chip::Optional<bool> & fabricFiltered,
const chip::Optional<std::vector<chip::DataVersion>> & dataVersions,
const chip::Optional<chip::EventNumber> & eventNumber,
const chip::Optional<bool> & keepSubscriptions)
{
const size_t endpointCount = endpointIds.size();
const size_t clusterCount = clusterIds.size();
const size_t attributeCount = attributeIds.size();
const size_t eventCount = eventIds.size();

// TODO Add data version supports
// TODO Add isUrgents supports

VerifyOrReturnError(endpointCount > 0 && endpointCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(clusterCount > 0 && clusterCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(attributeCount > 0 && attributeCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(eventCount > 0 && eventCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT);

const bool hasSameIdsCount = (clusterCount == (attributeCount + eventCount)) && (clusterCount == endpointCount);
if (!hasSameIdsCount)
{
ChipLogError(chipTool,
"\nCommand targetting a combination of attribute and event paths needs to have has many clusters and "
"endpoints than the number of attribute and events combined.\n"
"For example if there are 2 attributes and 1 event, the command expects 3 clusters and 3 endpoints.\n"
"Clusters and endpoints ids will be consumed first to populate the attribute paths of the request, and then "
"to populate the event paths of the request.\n\n"
"For example the following arguments:\n"
"\tcluster-ids: 6,6,0X28\n"
"\tendpoint-ids: 1,1,0\n"
"\tattribute-ids: 0,0x4001\n"
"\tevent-ids: 0\n"
"\n"
"will create the following paths:\n"
"\t{cluster: 6, endpoint: 1, attribute: 0}\n"
"\t{cluster: 6, endpoint: 1, attribute: 0x4001}\n"
"\t{cluster: 0x28, endpoint: 0, event: 0}\n");
return CHIP_ERROR_INVALID_ARGUMENT;
}

AttributePathParams attributePathParams[kMaxAllowedPaths];
EventPathParams eventPathParams[kMaxAllowedPaths];

auto pathsCount = endpointIds.size();
VerifyOrReturnError(pathsCount > 0 && pathsCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT);

size_t attributeIndex = 0;
size_t eventIndex = 0;
size_t pathsCount = clusterCount;
for (size_t i = 0; i < pathsCount; i++)
{
auto endpointId = endpointIds.at(i);
attributePathParams[i].mEndpointId = endpointId;
eventPathParams[i].mEndpointId = endpointId;
auto clusterId = clusterIds.at(i);
auto endpointId = endpointIds.at(i);

if (attributeIndex < attributeIds.size())
{
auto attributeId = attributeIds.at(attributeIndex);

if (endpointId != kInvalidEndpointId)
{
attributePathParams[attributeIndex].mEndpointId = endpointId;
}

if (clusterId != kInvalidClusterId)
{
attributePathParams[attributeIndex].mClusterId = clusterId;
}

if (attributeId != kInvalidAttributeId)
{
attributePathParams[attributeIndex].mAttributeId = attributeId;
}

attributeIndex++;
}
else if (eventIndex < eventIds.size())
{
auto eventId = eventIds.at(eventIndex);

if (endpointId != kInvalidEndpointId)
{
eventPathParams[eventIndex].mEndpointId = endpointId;
}

if (clusterId != kInvalidClusterId)
{
eventPathParams[eventIndex].mClusterId = clusterId;
}

if (eventId != kInvalidEventId)
{
eventPathParams[eventIndex].mEventId = eventId;
}

eventIndex++;
}
}

ReadPrepareParams params(device->GetSecureSession().Value());
params.mpEventPathParamsList = eventPathParams;
params.mEventPathParamsListSize = pathsCount;
params.mEventPathParamsListSize = eventCount;
params.mEventNumber = eventNumber;
params.mpAttributePathParamsList = attributePathParams;
params.mAttributePathParamsListSize = pathsCount;
params.mAttributePathParamsListSize = attributeCount;

if (fabricFiltered.HasValue())
{
params.mIsFabricFiltered = fabricFiltered.Value();
}

if (interactionType == ReadClient::InteractionType::Subscribe)
{
params.mMinIntervalFloorSeconds = minInterval;
params.mMaxIntervalCeilingSeconds = maxInterval;
if (keepSubscriptions.HasValue())
{
params.mKeepSubscriptions = keepSubscriptions.Value();
}
}

auto client = std::make_unique<ReadClient>(InteractionModelEngine::GetInstance(), device->GetExchangeManager(),
mBufferedReadAdapter, ReadClient::InteractionType::Read);
mBufferedReadAdapter, interactionType);
ReturnErrorOnFailure(client->SendRequest(params));
mReadClients.push_back(std::move(client));
return CHIP_NO_ERROR;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,35 @@ class InteractionModelReports
const chip::Optional<std::vector<bool>> & isUrgents = chip::NullOptional);

CHIP_ERROR ReadAll(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds,
const chip::Optional<bool> & fabricFiltered = chip::Optional<bool>(true));
std::vector<chip::ClusterId> clusterIds, std::vector<chip::AttributeId> attributeIds,
std::vector<chip::EventId> eventIds,
const chip::Optional<bool> & fabricFiltered = chip::Optional<bool>(true),
const chip::Optional<std::vector<chip::DataVersion>> & dataVersions = chip::NullOptional,
const chip::Optional<chip::EventNumber> & eventNumber = chip::NullOptional)
{
return ReportAll(device, endpointIds, clusterIds, attributeIds, eventIds, chip::app::ReadClient::InteractionType::Read, 0,
0, fabricFiltered, dataVersions, eventNumber);
}

CHIP_ERROR SubscribeAll(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds,
std::vector<chip::ClusterId> clusterIds, std::vector<chip::AttributeId> attributeIds,
std::vector<chip::EventId> eventIds, uint16_t minInterval = 0, uint16_t maxInterval = 0,
const chip::Optional<bool> & fabricFiltered = chip::Optional<bool>(true),
const chip::Optional<chip::EventNumber> & eventNumber = chip::NullOptional,
const chip::Optional<bool> & keepSubscriptions = chip::NullOptional)
{
return ReportAll(device, endpointIds, clusterIds, attributeIds, eventIds, chip::app::ReadClient::InteractionType::Subscribe,
minInterval, maxInterval, fabricFiltered, chip::NullOptional, eventNumber, keepSubscriptions);
}

CHIP_ERROR ReportAll(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds,
std::vector<chip::ClusterId> clusterIds, std::vector<chip::AttributeId> attributeIds,
std::vector<chip::EventId> eventIds, chip::app::ReadClient::InteractionType interactionType,
uint16_t minInterval = 0, uint16_t maxInterval = 0,
const chip::Optional<bool> & fabricFiltered = chip::Optional<bool>(true),
const chip::Optional<std::vector<chip::DataVersion>> & dataVersions = chip::NullOptional,
const chip::Optional<chip::EventNumber> & eventNumber = chip::NullOptional,
const chip::Optional<bool> & keepSubscriptions = chip::NullOptional);

void Shutdown() { mReadClients.clear(); }

Expand Down
1 change: 1 addition & 0 deletions zzz_generated/chip-tool/zap-generated/cluster/Commands.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1097191

Please sign in to comment.