diff --git a/examples/chip-tool/commands/clusters/ModelCommand.cpp b/examples/chip-tool/commands/clusters/ModelCommand.cpp index c908f9fa71b548..94b2b36c5538a3 100644 --- a/examples/chip-tool/commands/clusters/ModelCommand.cpp +++ b/examples/chip-tool/commands/clusters/ModelCommand.cpp @@ -103,3 +103,9 @@ void ModelCommand::CheckPeerICDType() } } } + +bool ModelCommand::IsPeerLIT() +{ + CheckPeerICDType(); + return mIsPeerLIT.ValueOr(false); +} diff --git a/examples/chip-tool/commands/clusters/ModelCommand.h b/examples/chip-tool/commands/clusters/ModelCommand.h index 9561932c9b74e0..d4e8eac613f468 100644 --- a/examples/chip-tool/commands/clusters/ModelCommand.h +++ b/examples/chip-tool/commands/clusters/ModelCommand.h @@ -70,7 +70,9 @@ class ModelCommand : public CHIPCommand void Shutdown() override; protected: - bool IsPeerLIT() { return mIsPeerLIT.ValueOr(false); } + bool IsPeerLIT(); + + chip::NodeId GetDestinationId() const { return mDestinationId; } chip::Optional mTimeout; diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index c35eb11836d6c8..7e871f8e781e14 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -18,6 +18,7 @@ #include "CHIPCommand.h" +#include #include #include #include @@ -52,7 +53,6 @@ chip::Credentials::GroupDataProviderImpl CHIPCommand::sGroupDataProvider{ kMaxGr // All fabrics share the same ICD client storage. chip::app::DefaultICDClientStorage CHIPCommand::sICDClientStorage; chip::Crypto::RawKeySessionKeystore CHIPCommand::sSessionKeystore; -chip::app::DefaultCheckInDelegate CHIPCommand::sCheckInDelegate; chip::app::CheckInHandler CHIPCommand::sCheckInHandler; namespace { @@ -153,9 +153,9 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack() auto engine = chip::app::InteractionModelEngine::GetInstance(); VerifyOrReturnError(engine != nullptr, CHIP_ERROR_INCORRECT_STATE); - ReturnLogErrorOnFailure(sCheckInDelegate.Init(&sICDClientStorage, engine)); + ReturnLogErrorOnFailure(ChipToolCheckInDelegate()->Init(&sICDClientStorage, engine)); ReturnLogErrorOnFailure(sCheckInHandler.Init(DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(), - &sICDClientStorage, &sCheckInDelegate, engine)); + &sICDClientStorage, ChipToolCheckInDelegate(), engine)); CommissionerIdentity nullIdentity{ kIdentityNull, chip::kUndefinedNodeId }; ReturnLogErrorOnFailure(InitializeCommissioner(nullIdentity, kIdentityNullFabricId)); diff --git a/examples/chip-tool/commands/icd/ICDCommand.cpp b/examples/chip-tool/commands/icd/ICDCommand.cpp index fbfc6a2083a5d5..505e6adfbfea3d 100644 --- a/examples/chip-tool/commands/icd/ICDCommand.cpp +++ b/examples/chip-tool/commands/icd/ICDCommand.cpp @@ -23,6 +23,7 @@ #include using namespace ::chip; +using namespace ::chip::app; CHIP_ERROR ICDListCommand::RunCommand() { @@ -64,13 +65,73 @@ CHIP_ERROR ICDListCommand::RunCommand() return CHIP_NO_ERROR; } +CHIP_ERROR ICDWaitForDeviceCommand::RunCommand() +{ + if (!IsPeerLIT()) + { + ChipLogError(chipTool, "The device is not a registered LIT-ICD device."); + return CHIP_ERROR_NOT_FOUND; + } + mInterestedNode = ScopedNodeId(GetDestinationId(), CurrentCommissioner().GetFabricIndex()); + ChipLogProgress(chipTool, "Please trigger the device active mode."); + return CHIP_NO_ERROR; +} + +void ICDWaitForDeviceCommand::OnCheckInComplete(const chip::app::ICDClientInfo & clientInfo) +{ + DefaultCheckInDelegate::OnCheckInComplete(clientInfo); + + if (clientInfo.peer_node != mInterestedNode) + { + ChipLogDetail(chipTool, "The node " ChipLogFormatScopedNodeId " is not the one we are interested in.", + ChipLogValueScopedNodeId(clientInfo.peer_node)); + return; + } + + ChipLogDetail(chipTool, "Received check-in message from the node, send stay active request to the device."); + mInterestedNode = ScopedNodeId(); + + // Intentionally call RunCommand, since it includes all necessary steps for SendCommand. + CHIP_ERROR err = ClusterCommand::RunCommand(); + if (err != CHIP_NO_ERROR) + { + SetCommandExitStatus(err); + return; + } +} + +CHIP_ERROR ICDWaitForDeviceCommand::SendCommand(DeviceProxy * device, + std::vector /* not used, always send to endpoint 0 */) +{ + Clusters::IcdManagement::Commands::StayActiveRequest::Type request; + request.stayActiveDuration = mStayActiveDurationSeconds; + return ClusterCommand::SendCommand(device, kRootEndpointId, Clusters::IcdManagement::Id, + Clusters::IcdManagement::Commands::StayActiveRequest::Id, request); +} + +namespace { +DefaultCheckInDelegate * sCheckInDelegate; +} + void registerCommandsICD(Commands & commands, CredentialIssuerCommands * credsIssuerConfig) { const char * name = "ICD"; + auto icdWaitForDeviceCommand = make_unique(credsIssuerConfig); + + // This should be safe within chip-tool, since the lifespan of Commands is longer than any commands and the CHIPStack. + // So this object will not be used after free within chip-tool. + sCheckInDelegate = static_cast(icdWaitForDeviceCommand.get()); + commands_list list = { make_unique(credsIssuerConfig), + std::move(icdWaitForDeviceCommand), }; commands.RegisterCommandSet(name, list, "Commands for client-side ICD management."); } + +DefaultCheckInDelegate * ChipToolCheckInDelegate() +{ + return sCheckInDelegate; +} diff --git a/examples/chip-tool/commands/icd/ICDCommand.h b/examples/chip-tool/commands/icd/ICDCommand.h index b36d66a7dbfcb9..ffb316dfc0f5d3 100644 --- a/examples/chip-tool/commands/icd/ICDCommand.h +++ b/examples/chip-tool/commands/icd/ICDCommand.h @@ -19,8 +19,12 @@ #pragma once #include "../common/CHIPCommand.h" +#include "commands/clusters/ClusterCommand.h" #include "commands/common/Commands.h" +#include +#include +#include #include class ICDCommand : public CHIPCommand @@ -42,4 +46,29 @@ class ICDListCommand : public ICDCommand CHIP_ERROR RunCommand() override; }; +class ICDWaitForDeviceCommand : public ClusterCommand, public chip::app::DefaultCheckInDelegate +{ +public: + ICDWaitForDeviceCommand(CredentialIssuerCommands * credIssuerCmds) : ClusterCommand("wait-for-device", credIssuerCmds) + { + ModelCommand::AddArguments(/* skipEndpoints= */ true); + AddArgument("stay-active-duration-seconds", 30, UINT32_MAX, &mStayActiveDurationSeconds, + "The requested duration in seconds for the device to stay active after check-in completes."); + } + + virtual ~ICDWaitForDeviceCommand() = default; + + CHIP_ERROR RunCommand() override; + + void OnCheckInComplete(const chip::app::ICDClientInfo & clientInfo) override; + + CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endPointIds) override; + +private: + chip::ScopedNodeId mInterestedNode; + uint32_t mStayActiveDurationSeconds = 30; +}; + void registerCommandsICD(Commands & commands, CredentialIssuerCommands * credsIssuerConfig); + +chip::app::DefaultCheckInDelegate * ChipToolCheckInDelegate(); diff --git a/examples/tv-casting-app/tv-casting-common/commands/clusters/ModelCommand.cpp b/examples/tv-casting-app/tv-casting-common/commands/clusters/ModelCommand.cpp index bc14214af4cce9..1210af574603f4 100644 --- a/examples/tv-casting-app/tv-casting-common/commands/clusters/ModelCommand.cpp +++ b/examples/tv-casting-app/tv-casting-common/commands/clusters/ModelCommand.cpp @@ -81,3 +81,9 @@ void ModelCommand::Shutdown() mOnDeviceConnectedCallback.Cancel(); mOnDeviceConnectionFailureCallback.Cancel(); } + +bool ModelCommand::IsPeerLIT() +{ + // Does not support tv-casting-app + return false; +}