blob: b79ec5eb28ec194f1eb74b5abe8539bd8e5c5a00 [file] [log] [blame]
/*
* Copyright (c) 2020 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.
*
*/
#pragma once
#include <app/tests/suites/commands/interaction_model/InteractionModel.h>
#include "DataModelLogger.h"
#include "ModelCommand.h"
class ReportCommand : public InteractionModelReports, public ModelCommand, public chip::app::ReadClient::Callback
{
public:
ReportCommand(const char * commandName, CredentialIssuerCommands * credsIssuerConfig) :
InteractionModelReports(this), ModelCommand(commandName, credsIssuerConfig, /* supportsMultipleEndpoints = */ true)
{}
/////////// ReadClient Callback Interface /////////
void OnAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data,
const chip::app::StatusIB & status) override
{
CHIP_ERROR error = status.ToChipError();
if (CHIP_NO_ERROR != error)
{
ChipLogError(chipTool, "Response Failure: %s", chip::ErrorStr(error));
mError = error;
return;
}
if (data == nullptr)
{
ChipLogError(chipTool, "Response Failure: No Data");
mError = CHIP_ERROR_INTERNAL;
return;
}
error = DataModelLogger::LogAttribute(path, data);
if (CHIP_NO_ERROR != error)
{
ChipLogError(chipTool, "Response Failure: Can not decode Data");
mError = error;
return;
}
}
void OnEventData(const chip::app::EventHeader & eventHeader, chip::TLV::TLVReader * data,
const chip::app::StatusIB * status) override
{
if (status != nullptr)
{
CHIP_ERROR error = status->ToChipError();
if (CHIP_NO_ERROR != error)
{
ChipLogError(chipTool, "Response Failure: %s", chip::ErrorStr(error));
mError = error;
return;
}
}
if (data == nullptr)
{
ChipLogError(chipTool, "Response Failure: No Data");
mError = CHIP_ERROR_INTERNAL;
return;
}
CHIP_ERROR error = DataModelLogger::LogEvent(eventHeader, data);
if (CHIP_NO_ERROR != error)
{
ChipLogError(chipTool, "Response Failure: Can not decode Data");
mError = error;
return;
}
}
void OnError(CHIP_ERROR error) override
{
ChipLogProgress(chipTool, "Error: %s", chip::ErrorStr(error));
mError = error;
}
void OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams) override
{
InteractionModelReports::OnDeallocatePaths(std::move(aReadPrepareParams));
}
void Shutdown() override
{
// We don't shut down InteractionModelReports here; we leave it for
// Cleanup to handle.
mError = CHIP_NO_ERROR;
ModelCommand::Shutdown();
}
void Cleanup() override { InteractionModelReports::Shutdown(); }
protected:
// Use a 3x-longer-than-default timeout because wildcard reads can take a
// while.
chip::System::Clock::Timeout GetWaitDuration() const override
{
return mTimeout.HasValue() ? chip::System::Clock::Seconds16(mTimeout.Value()) : (ModelCommand::GetWaitDuration() * 3);
}
CHIP_ERROR mError = CHIP_NO_ERROR;
};
class ReadCommand : public ReportCommand
{
protected:
ReadCommand(const char * commandName, CredentialIssuerCommands * credsIssuerConfig) :
ReportCommand(commandName, credsIssuerConfig)
{}
void OnDone(chip::app::ReadClient * aReadClient) override
{
InteractionModelReports::CleanupReadClient(aReadClient);
SetCommandExitStatus(mError);
}
};
class SubscribeCommand : public ReportCommand
{
protected:
SubscribeCommand(const char * commandName, CredentialIssuerCommands * credsIssuerConfig) :
ReportCommand(commandName, credsIssuerConfig)
{}
void OnSubscriptionEstablished(chip::SubscriptionId subscriptionId) override
{
mSubscriptionEstablished = true;
SetCommandExitStatus(CHIP_NO_ERROR);
}
void OnDone(chip::app::ReadClient * aReadClient) override
{
InteractionModelReports::CleanupReadClient(aReadClient);
if (!mSubscriptionEstablished)
{
SetCommandExitStatus(mError);
}
// else we must be getting here from Cleanup(), which means we have
// already done our exit status thing.
}
void Shutdown() override
{
mSubscriptionEstablished = false;
ReportCommand::Shutdown();
}
// For subscriptions we always defer interactive cleanup. Either our
// ReadClients will terminate themselves (in which case they will be removed
// from our list anyway), or they should hang around until shutdown.
bool DeferInteractiveCleanup() override { return true; }
private:
bool mSubscriptionEstablished = false;
};
class ReadAttribute : public ReadCommand
{
public:
ReadAttribute(CredentialIssuerCommands * credsIssuerConfig) : ReadCommand("read-by-id", 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.");
AddAttributeIdArgument();
AddCommonArguments();
ReadCommand::AddArguments();
}
ReadAttribute(chip::ClusterId clusterId, CredentialIssuerCommands * credsIssuerConfig) :
ReadCommand("read-by-id", credsIssuerConfig), mClusterIds(1, clusterId)
{
AddAttributeIdArgument();
AddCommonArguments();
ReadCommand::AddArguments();
}
ReadAttribute(chip::ClusterId clusterId, const char * attributeName, chip::AttributeId attributeId,
CredentialIssuerCommands * credsIssuerConfig) :
ReadCommand("read", credsIssuerConfig),
mClusterIds(1, clusterId), mAttributeIds(1, attributeId)
{
AddArgument("attr-name", attributeName);
AddCommonArguments();
ReadCommand::AddArguments();
}
~ReadAttribute() {}
CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds) override
{
return ReadCommand::ReadAttribute(device, endpointIds, mClusterIds, mAttributeIds, mFabricFiltered, mDataVersion);
}
private:
void AddAttributeIdArgument()
{
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.");
}
void AddCommonArguments()
{
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered,
"Boolean indicating whether to do a fabric-filtered read. Defaults to true.");
AddArgument("data-version", 0, UINT32_MAX, &mDataVersion,
"Comma-separated list of data versions for the clusters being read.");
}
std::vector<chip::ClusterId> mClusterIds;
std::vector<chip::AttributeId> mAttributeIds;
chip::Optional<bool> mFabricFiltered;
chip::Optional<std::vector<chip::DataVersion>> mDataVersion;
};
class SubscribeAttribute : public SubscribeCommand
{
public:
SubscribeAttribute(CredentialIssuerCommands * credsIssuerConfig) : SubscribeCommand("subscribe-by-id", credsIssuerConfig)
{
AddArgument("cluster-ids", 0, UINT32_MAX, &mClusterIds,
"Comma-separated list of cluster ids to subscribe to (e.g. \"6\" or \"8,0x201\").\n Allowed to be 0xFFFFFFFF "
"to indicate a wildcard cluster.");
AddAttributeIdArgument();
AddCommonArguments();
SubscribeCommand::AddArguments();
}
SubscribeAttribute(chip::ClusterId clusterId, CredentialIssuerCommands * credsIssuerConfig) :
SubscribeCommand("subscribe-by-id", credsIssuerConfig), mClusterIds(1, clusterId)
{
AddAttributeIdArgument();
AddCommonArguments();
SubscribeCommand::AddArguments();
}
SubscribeAttribute(chip::ClusterId clusterId, const char * attributeName, chip::AttributeId attributeId,
CredentialIssuerCommands * credsIssuerConfig) :
SubscribeCommand("subscribe", credsIssuerConfig),
mClusterIds(1, clusterId), mAttributeIds(1, attributeId)
{
AddArgument("attr-name", attributeName);
AddCommonArguments();
SubscribeCommand::AddArguments();
}
~SubscribeAttribute() {}
CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds) override
{
return SubscribeCommand::SubscribeAttribute(device, endpointIds, mClusterIds, mAttributeIds, mMinInterval, mMaxInterval,
mFabricFiltered, mDataVersion, mKeepSubscriptions, mAutoResubscribe);
}
private:
void AddAttributeIdArgument()
{
AddArgument("attribute-ids", 0, UINT32_MAX, &mAttributeIds,
"Comma-separated list of attribute ids to subscribe to (e.g. \"0\" or \"1,0xFFFC,0xFFFD\").\n Allowed to be "
"0xFFFFFFFF to indicate a wildcard attribute.");
}
void AddCommonArguments()
{
AddArgument("min-interval", 0, UINT16_MAX, &mMinInterval,
"Server should not send a new report if less than this number of seconds has elapsed since the last report.");
AddArgument("max-interval", 0, UINT16_MAX, &mMaxInterval,
"Server must send a report if this number of seconds has elapsed since the last report.");
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered,
"Boolean indicating whether to do a fabric-filtered subscription. Defaults to true.");
AddArgument("data-version", 0, UINT32_MAX, &mDataVersion,
"Comma-separated list of data versions for the clusters being subscribed to.");
AddArgument("keepSubscriptions", 0, 1, &mKeepSubscriptions,
"Boolean indicating whether to keep existing subscriptions when creating the new one. Defaults to false.");
AddArgument("auto-resubscribe", 0, 1, &mAutoResubscribe,
"Boolean indicating whether the subscription should auto-resubscribe. Defaults to false.");
}
std::vector<chip::ClusterId> mClusterIds;
std::vector<chip::AttributeId> mAttributeIds;
uint16_t mMinInterval;
uint16_t mMaxInterval;
chip::Optional<bool> mFabricFiltered;
chip::Optional<std::vector<chip::DataVersion>> mDataVersion;
chip::Optional<bool> mKeepSubscriptions;
chip::Optional<bool> mAutoResubscribe;
};
class ReadEvent : public ReadCommand
{
public:
ReadEvent(CredentialIssuerCommands * credsIssuerConfig) : ReadCommand("read-event-by-id", credsIssuerConfig)
{
AddArgument("cluster-id", 0, UINT32_MAX, &mClusterIds);
AddArgument("event-id", 0, UINT32_MAX, &mEventIds);
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered);
AddArgument("event-min", 0, UINT64_MAX, &mEventNumber);
ReadCommand::AddArguments();
}
ReadEvent(chip::ClusterId clusterId, CredentialIssuerCommands * credsIssuerConfig) :
ReadCommand("read-event-by-id", credsIssuerConfig), mClusterIds(1, clusterId)
{
AddArgument("event-id", 0, UINT32_MAX, &mEventIds);
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered);
AddArgument("event-min", 0, UINT64_MAX, &mEventNumber);
ReadCommand::AddArguments();
}
ReadEvent(chip::ClusterId clusterId, const char * eventName, chip::EventId eventId,
CredentialIssuerCommands * credsIssuerConfig) :
ReadCommand("read-event", credsIssuerConfig),
mClusterIds(1, clusterId), mEventIds(1, eventId)
{
AddArgument("event-name", eventName);
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered);
AddArgument("event-min", 0, UINT64_MAX, &mEventNumber);
ReadCommand::AddArguments();
}
~ReadEvent() {}
CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds) override
{
return ReadCommand::ReadEvent(device, endpointIds, mClusterIds, mEventIds, mFabricFiltered, mEventNumber);
}
private:
std::vector<chip::ClusterId> mClusterIds;
std::vector<chip::EventId> mEventIds;
chip::Optional<bool> mFabricFiltered;
chip::Optional<chip::EventNumber> mEventNumber;
};
class SubscribeEvent : public SubscribeCommand
{
public:
SubscribeEvent(CredentialIssuerCommands * credsIssuerConfig) : SubscribeCommand("subscribe-event-by-id", credsIssuerConfig)
{
AddArgument("cluster-id", 0, UINT32_MAX, &mClusterIds);
AddArgument("event-id", 0, UINT32_MAX, &mEventIds);
AddCommonArguments();
SubscribeCommand::AddArguments();
}
SubscribeEvent(chip::ClusterId clusterId, CredentialIssuerCommands * credsIssuerConfig) :
SubscribeCommand("subscribe-event-by-id", credsIssuerConfig), mClusterIds(1, clusterId)
{
AddArgument("event-id", 0, UINT32_MAX, &mEventIds);
AddCommonArguments();
SubscribeCommand::AddArguments();
}
SubscribeEvent(chip::ClusterId clusterId, const char * eventName, chip::EventId eventId,
CredentialIssuerCommands * credsIssuerConfig) :
SubscribeCommand("subscribe-event", credsIssuerConfig),
mClusterIds(1, clusterId), mEventIds(1, eventId)
{
AddArgument("event-name", eventName, "Event name.");
AddCommonArguments();
SubscribeCommand::AddArguments();
}
void AddCommonArguments()
{
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);
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.");
AddArgument(
"is-urgent", 0, 1, &mIsUrgents,
"Sets isUrgent in the Subscribe Request.\n"
" The queueing of any urgent event SHALL force an immediate generation of reports containing all events queued "
"leading up to (and including) the urgent event in question.\n"
" This argument takes a comma separated list of true/false values.\n"
" If the number of paths exceeds the number of entries provided to is-urgent, then isUrgent will be false for the "
"extra paths.");
AddArgument("auto-resubscribe", 0, 1, &mAutoResubscribe,
"Boolean indicating whether the subscription should auto-resubscribe. Defaults to false.");
}
~SubscribeEvent() {}
CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds) override
{
return SubscribeCommand::SubscribeEvent(device, endpointIds, mClusterIds, mEventIds, mMinInterval, mMaxInterval,
mFabricFiltered, mEventNumber, mKeepSubscriptions, mIsUrgents, mAutoResubscribe);
}
private:
std::vector<chip::ClusterId> mClusterIds;
std::vector<chip::EventId> mEventIds;
uint16_t mMinInterval;
uint16_t mMaxInterval;
chip::Optional<bool> mFabricFiltered;
chip::Optional<chip::EventNumber> mEventNumber;
chip::Optional<bool> mKeepSubscriptions;
chip::Optional<std::vector<bool>> mIsUrgents;
chip::Optional<bool> mAutoResubscribe;
};
class ReadAll : public ReadCommand
{
public:
ReadAll(CredentialIssuerCommands * credsIssuerConfig) : ReadCommand("read-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("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();
}
~ReadAll() {}
void OnDone(chip::app::ReadClient * aReadClient) override
{
InteractionModelReports::CleanupReadClient(aReadClient);
SetCommandExitStatus(mError);
}
CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds) override
{
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;
};