| /* |
| * 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; |
| }; |