blob: 04e658f18cc1887d99aec313bb522c10a7f787ef [file] [log] [blame]
/*
* Copyright (c) 2022 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "InteractionModel.h"
using namespace chip;
using namespace chip::app;
namespace chip {
namespace test_utils {
void BusyWaitMillis(uint16_t busyWaitForMs)
{
auto & clock = chip::System::SystemClock();
auto start = clock.GetMonotonicTimestamp();
chip::System::Clock::Milliseconds32 durationInMs(busyWaitForMs);
while (clock.GetMonotonicTimestamp() - start < durationInMs)
{
// nothing to do.
};
}
} // namespace test_utils
} // namespace chip
CHIP_ERROR InteractionModel::ReadAttribute(const char * identity, EndpointId endpointId, ClusterId clusterId,
AttributeId attributeId, bool fabricFiltered, const Optional<DataVersion> & dataVersion)
{
DeviceProxy * device = GetDevice(identity);
VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE);
std::vector<EndpointId> endpointIds = { endpointId };
std::vector<ClusterId> clusterIds = { clusterId };
std::vector<AttributeId> attributeIds = { attributeId };
Optional<std::vector<DataVersion>> dataVersions = Optional<std::vector<DataVersion>>();
if (dataVersion.HasValue())
{
dataVersions.Value().push_back(dataVersion.Value());
}
InteractionModelReports::ResetOptions();
InteractionModelReports::SetFabricFiltered(fabricFiltered);
InteractionModelReports::SetDataVersions(dataVersions);
return InteractionModelReports::ReadAttribute(device, endpointIds, clusterIds, attributeIds);
}
CHIP_ERROR InteractionModel::ReadEvent(const char * identity, EndpointId endpointId, ClusterId clusterId, EventId eventId,
bool fabricFiltered, const Optional<EventNumber> & eventNumber)
{
DeviceProxy * device = GetDevice(identity);
VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE);
std::vector<EndpointId> endpointIds = { endpointId };
std::vector<ClusterId> clusterIds = { clusterId };
std::vector<EventId> eventIds = { eventId };
InteractionModelReports::ResetOptions();
InteractionModelReports::SetFabricFiltered(fabricFiltered);
InteractionModelReports::SetEventNumber(eventNumber);
return InteractionModelReports::ReadEvent(device, endpointIds, clusterIds, eventIds);
}
CHIP_ERROR InteractionModel::SubscribeAttribute(const char * identity, EndpointId endpointId, ClusterId clusterId,
AttributeId attributeId, uint16_t minInterval, uint16_t maxInterval,
bool fabricFiltered, const Optional<DataVersion> & dataVersion,
const Optional<bool> & keepSubscriptions, const Optional<bool> & autoResubscribe)
{
DeviceProxy * device = GetDevice(identity);
VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE);
std::vector<EndpointId> endpointIds = { endpointId };
std::vector<ClusterId> clusterIds = { clusterId };
std::vector<AttributeId> attributeIds = { attributeId };
Optional<std::vector<DataVersion>> dataVersions = Optional<std::vector<DataVersion>>();
if (dataVersion.HasValue())
{
dataVersions.Value().push_back(dataVersion.Value());
}
InteractionModelReports::ResetOptions();
InteractionModelReports::SetMinInterval(minInterval);
InteractionModelReports::SetMaxInterval(maxInterval);
InteractionModelReports::SetFabricFiltered(fabricFiltered);
InteractionModelReports::SetDataVersions(dataVersions);
InteractionModelReports::SetKeepSubscriptions(keepSubscriptions);
InteractionModelReports::SetAutoResubscribe(autoResubscribe);
return InteractionModelReports::SubscribeAttribute(device, endpointIds, clusterIds, attributeIds);
}
CHIP_ERROR InteractionModel::SubscribeEvent(const char * identity, EndpointId endpointId, ClusterId clusterId, EventId eventId,
uint16_t minInterval, uint16_t maxInterval, bool fabricFiltered,
const Optional<EventNumber> & eventNumber, const Optional<bool> & keepSubscriptions,
const Optional<bool> & autoResubscribe)
{
DeviceProxy * device = GetDevice(identity);
VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE);
std::vector<EndpointId> endpointIds = { endpointId };
std::vector<ClusterId> clusterIds = { clusterId };
std::vector<EventId> eventIds = { eventId };
InteractionModelReports::ResetOptions();
SetMinInterval(minInterval);
SetMaxInterval(maxInterval);
SetFabricFiltered(fabricFiltered);
SetEventNumber(eventNumber);
SetKeepSubscriptions(keepSubscriptions);
SetAutoResubscribe(autoResubscribe);
return InteractionModelReports::SubscribeEvent(device, endpointIds, clusterIds, eventIds);
}
void InteractionModel::Shutdown()
{
InteractionModelReports::Shutdown();
InteractionModelWriter::Shutdown();
InteractionModelCommands::Shutdown();
}
/////////// ReadClient Callback Interface /////////
void InteractionModel::OnAttributeData(const ConcreteDataAttributePath & path, TLV::TLVReader * data, const StatusIB & status)
{
OnResponse(status, data);
}
void InteractionModel::OnEventData(const EventHeader & eventHeader, TLV::TLVReader * data, const StatusIB * status)
{
OnResponse(status == nullptr ? StatusIB() : *status, data);
}
void InteractionModel::OnError(CHIP_ERROR error)
{
StatusIB status(error);
OnResponse(status, nullptr);
}
void InteractionModel::OnDone(ReadClient * aReadClient)
{
InteractionModelReports::CleanupReadClient(aReadClient);
ContinueOnChipMainThread(CHIP_NO_ERROR);
}
void InteractionModel::OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams)
{
InteractionModelReports::OnDeallocatePaths(std::move(aReadPrepareParams));
}
void InteractionModel::OnSubscriptionEstablished(SubscriptionId subscriptionId)
{
ContinueOnChipMainThread(CHIP_NO_ERROR);
}
/////////// WriteClient Callback Interface /////////
void InteractionModel::OnResponse(const WriteClient * client, const ConcreteDataAttributePath & path, StatusIB status)
{
OnResponse(status, nullptr);
}
void InteractionModel::OnError(const WriteClient * client, CHIP_ERROR error)
{
StatusIB status(error);
OnResponse(status, nullptr);
}
void InteractionModel::OnDone(WriteClient * client)
{
mWriteClient.reset();
ContinueOnChipMainThread(CHIP_NO_ERROR);
}
/////////// CommandSender Callback Interface /////////
void InteractionModel::OnResponse(CommandSender * client, const ConcreteCommandPath & path, const StatusIB & status,
TLV::TLVReader * data)
{
OnResponse(status, data);
}
void InteractionModel::OnError(const CommandSender * client, CHIP_ERROR error)
{
StatusIB status(error);
OnResponse(status, nullptr);
}
void InteractionModel::OnDone(CommandSender * client)
{
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 InteractionModelConfig::GetAttributePaths(std::vector<EndpointId> endpointIds, std::vector<ClusterId> clusterIds,
std::vector<AttributeId> attributeIds,
const Optional<std::vector<DataVersion>> & dataVersions,
AttributePathsConfig & pathsConfig)
{
const size_t endpointCount = endpointIds.size();
const size_t clusterCount = clusterIds.size();
const size_t attributeCount = attributeIds.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,
"\nCommand 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.",
static_cast<unsigned int>(clusterCount), static_cast<unsigned int>(attributeCount),
static_cast<unsigned int>(endpointCount));
return CHIP_ERROR_INVALID_ARGUMENT;
}
pathsConfig.count = pathsCount;
pathsConfig.attributePathParams = std::make_unique<AttributePathParams[]>(pathsCount);
pathsConfig.dataVersionFilter = std::make_unique<DataVersionFilter[]>(pathsCount);
for (size_t i = 0; i < pathsCount; i++)
{
ClusterId clusterId = clusterIds.at((hasSameIdsCount || multipleClusters) ? i : 0);
AttributeId attributeId = attributeIds.at((hasSameIdsCount || multipleAttributes) ? i : 0);
EndpointId endpointId = endpointIds.at((hasSameIdsCount || multipleEndpoints) ? i : 0);
ChipLogProgress(chipTool, "\tcluster " ChipLogFormatMEI ", attribute: " ChipLogFormatMEI ", endpoint %u",
ChipLogValueMEI(clusterId), ChipLogValueMEI(attributeId), endpointId);
if (clusterId != kInvalidClusterId)
{
pathsConfig.attributePathParams[i].mClusterId = clusterId;
}
if (attributeId != kInvalidAttributeId)
{
pathsConfig.attributePathParams[i].mAttributeId = attributeId;
}
if (endpointId != kInvalidEndpointId)
{
pathsConfig.attributePathParams[i].mEndpointId = endpointId;
}
if (dataVersions.HasValue())
{
DataVersion dataVersion = dataVersions.Value().at((hasSameIdsCount || multipleDataVersions) ? i : 0);
pathsConfig.dataVersionFilter[i].mEndpointId = endpointId;
pathsConfig.dataVersionFilter[i].mClusterId = clusterId;
pathsConfig.dataVersionFilter[i].mDataVersion.SetValue(dataVersion);
}
}
return CHIP_NO_ERROR;
}
CHIP_ERROR InteractionModelReports::ReportAttribute(DeviceProxy * device, std::vector<EndpointId> endpointIds,
std::vector<ClusterId> clusterIds, std::vector<AttributeId> attributeIds,
ReadClient::InteractionType interactionType)
{
ChipLogProgress(chipTool,
"Sending %sAttribute to:", interactionType == ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read");
InteractionModelConfig::AttributePathsConfig pathsConfig;
ReturnErrorOnFailure(
InteractionModelConfig::GetAttributePaths(endpointIds, clusterIds, attributeIds, mDataVersions, pathsConfig));
ReadPrepareParams params(device->GetSecureSession().Value());
params.mpEventPathParamsList = nullptr;
params.mEventPathParamsListSize = 0;
params.mpAttributePathParamsList = pathsConfig.attributePathParams.get();
params.mAttributePathParamsListSize = pathsConfig.count;
if (mFabricFiltered.HasValue())
{
params.mIsFabricFiltered = mFabricFiltered.Value();
}
if (mDataVersions.HasValue())
{
params.mpDataVersionFilterList = pathsConfig.dataVersionFilter.get();
params.mDataVersionFilterListSize = pathsConfig.count;
}
if (interactionType == ReadClient::InteractionType::Subscribe)
{
params.mMinIntervalFloorSeconds = mMinInterval;
params.mMaxIntervalCeilingSeconds = mMaxInterval;
if (mKeepSubscriptions.HasValue())
{
params.mKeepSubscriptions = mKeepSubscriptions.Value();
}
params.mIsPeerLIT = mIsPeerLIT;
}
auto client = std::make_unique<ReadClient>(InteractionModelEngine::GetInstance(), device->GetExchangeManager(),
mBufferedReadAdapter, interactionType);
if (interactionType == ReadClient::InteractionType::Read)
{
ReturnErrorOnFailure(client->SendRequest(params));
}
else if (mAutoResubscribe.ValueOr(false))
{
pathsConfig.attributePathParams.release();
if (mDataVersions.HasValue())
{
pathsConfig.dataVersionFilter.release();
}
ReturnErrorOnFailure(client->SendAutoResubscribeRequest(std::move(params)));
}
else
{
// We want to allow certain kinds of spec-invalid subscriptions so we
// can test how the server reacts to them.
ReturnErrorOnFailure(client->SendSubscribeRequestWithoutValidation(params));
}
mReadClients.push_back(std::move(client));
return CHIP_NO_ERROR;
}
CHIP_ERROR InteractionModelReports::ReportEvent(DeviceProxy * device, std::vector<EndpointId> endpointIds,
std::vector<ClusterId> clusterIds, std::vector<EventId> eventIds,
chip::app::ReadClient::InteractionType interactionType)
{
const size_t clusterCount = clusterIds.size();
const size_t eventCount = eventIds.size();
const size_t endpointCount = endpointIds.size();
const size_t isUrgentCount = mIsUrgents.HasValue() ? mIsUrgents.Value().size() : 0;
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);
VerifyOrReturnError(isUrgentCount <= 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 == ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read",
static_cast<unsigned int>(clusterCount), static_cast<unsigned int>(eventCount),
static_cast<unsigned int>(endpointCount));
return CHIP_ERROR_INVALID_ARGUMENT;
}
auto eventPathParams = std::make_unique<EventPathParams[]>(pathsCount);
ChipLogProgress(chipTool,
"Sending %sEvent to:", interactionType == ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read");
for (size_t i = 0; i < pathsCount; i++)
{
ClusterId clusterId = clusterIds.at((hasSameIdsCount || multipleClusters) ? i : 0);
EventId eventId = eventIds.at((hasSameIdsCount || multipleEvents) ? i : 0);
EndpointId endpointId = endpointIds.at((hasSameIdsCount || multipleEndpoints) ? i : 0);
ChipLogProgress(chipTool, "\tcluster " ChipLogFormatMEI ", event: " ChipLogFormatMEI ", endpoint %u",
ChipLogValueMEI(clusterId), ChipLogValueMEI(eventId), endpointId);
if (clusterId != kInvalidClusterId)
{
eventPathParams[i].mClusterId = clusterId;
}
if (eventId != kInvalidEventId)
{
eventPathParams[i].mEventId = eventId;
}
if (endpointId != kInvalidEndpointId)
{
eventPathParams[i].mEndpointId = endpointId;
}
if (mIsUrgents.HasValue() && mIsUrgents.Value().size() > i)
{
eventPathParams[i].mIsUrgentEvent = mIsUrgents.Value().at(i);
}
}
ReadPrepareParams params(device->GetSecureSession().Value());
params.mpEventPathParamsList = eventPathParams.get();
params.mEventPathParamsListSize = pathsCount;
params.mEventNumber = mEventNumber;
params.mpAttributePathParamsList = nullptr;
params.mAttributePathParamsListSize = 0;
if (mFabricFiltered.HasValue())
{
params.mIsFabricFiltered = mFabricFiltered.Value();
}
if (interactionType == ReadClient::InteractionType::Subscribe)
{
params.mMinIntervalFloorSeconds = mMinInterval;
params.mMaxIntervalCeilingSeconds = mMaxInterval;
if (mKeepSubscriptions.HasValue())
{
params.mKeepSubscriptions = mKeepSubscriptions.Value();
}
params.mIsPeerLIT = mIsPeerLIT;
}
auto client = std::make_unique<ReadClient>(InteractionModelEngine::GetInstance(), device->GetExchangeManager(),
mBufferedReadAdapter, interactionType);
if (mAutoResubscribe.ValueOr(false))
{
eventPathParams.release();
ReturnErrorOnFailure(client->SendAutoResubscribeRequest(std::move(params)));
}
else
{
ReturnErrorOnFailure(client->SendRequest(params));
}
mReadClients.push_back(std::move(client));
return CHIP_NO_ERROR;
}
void InteractionModelReports::CleanupReadClient(ReadClient * aReadClient)
{
mReadClients.erase(
std::remove_if(mReadClients.begin(), mReadClients.end(), [aReadClient](auto & item) { return item.get() == aReadClient; }),
mReadClients.end());
}
CHIP_ERROR InteractionModelReports::ReportNone(chip::DeviceProxy * device, chip::app::ReadClient::InteractionType interactionType)
{
AttributePathParams attributePathParams[kMaxAllowedPaths];
EventPathParams eventPathParams[kMaxAllowedPaths];
ReadPrepareParams params(device->GetSecureSession().Value());
params.mpEventPathParamsList = eventPathParams;
params.mEventPathParamsListSize = 0;
params.mEventNumber = mEventNumber;
params.mpAttributePathParamsList = attributePathParams;
params.mAttributePathParamsListSize = 0;
if (mFabricFiltered.HasValue())
{
params.mIsFabricFiltered = mFabricFiltered.Value();
}
if (interactionType == ReadClient::InteractionType::Subscribe)
{
params.mMinIntervalFloorSeconds = mMinInterval;
params.mMaxIntervalCeilingSeconds = mMaxInterval;
if (mKeepSubscriptions.HasValue())
{
params.mKeepSubscriptions = mKeepSubscriptions.Value();
}
}
auto client = std::make_unique<ReadClient>(InteractionModelEngine::GetInstance(), device->GetExchangeManager(),
mBufferedReadAdapter, interactionType);
ReturnErrorOnFailure(client->SendRequest(params));
mReadClients.push_back(std::move(client));
return CHIP_NO_ERROR;
}
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)
{
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];
size_t attributeIndex = 0;
size_t eventIndex = 0;
size_t pathsCount = clusterCount;
for (size_t i = 0; i < pathsCount; i++)
{
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 = eventCount;
params.mEventNumber = mEventNumber;
params.mpAttributePathParamsList = attributePathParams;
params.mAttributePathParamsListSize = attributeCount;
if (mFabricFiltered.HasValue())
{
params.mIsFabricFiltered = mFabricFiltered.Value();
}
if (interactionType == ReadClient::InteractionType::Subscribe)
{
params.mMinIntervalFloorSeconds = mMinInterval;
params.mMaxIntervalCeilingSeconds = mMaxInterval;
if (mKeepSubscriptions.HasValue())
{
params.mKeepSubscriptions = mKeepSubscriptions.Value();
}
params.mIsPeerLIT = mIsPeerLIT;
}
auto client = std::make_unique<ReadClient>(InteractionModelEngine::GetInstance(), device->GetExchangeManager(),
mBufferedReadAdapter, interactionType);
ReturnErrorOnFailure(client->SendRequest(params));
mReadClients.push_back(std::move(client));
return CHIP_NO_ERROR;
}
void InteractionModelReports::OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams)
{
if (aReadPrepareParams.mpAttributePathParamsList != nullptr)
{
delete[] aReadPrepareParams.mpAttributePathParamsList;
}
if (aReadPrepareParams.mpDataVersionFilterList != nullptr)
{
delete[] aReadPrepareParams.mpDataVersionFilterList;
}
if (aReadPrepareParams.mpEventPathParamsList != nullptr)
{
delete[] aReadPrepareParams.mpEventPathParamsList;
}
}