/* * * Copyright (c) 2021 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 #include #include namespace chip { namespace Controller { namespace Internal { // Cancellation functions on InvokeCommandRequest() are for internal use only. typedef std::function InvokeCancelFn; } // namespace Internal /* * A typed command invocation function that takes as input a cluster-object representation of a command request and * callbacks for success and failure and either returns a decoded cluster-object representation of the response through * the provided success callback or calls the provided failure callback. * * The RequestObjectT is generally expected to be a ClusterName::Commands::CommandName::Type struct, but any object * that can be encoded using the DataModel::Encode machinery and exposes the * GetClusterId() and GetCommandId() functions and a ResponseType type * is expected to work. * * The ResponseType is expected to be one of two things: * * - If a data response is expected on success, a struct type decodable via DataModel::Decode which has GetClusterId() and * GetCommandId() methods. A ClusterName::Commands::ResponseCommandName::DecodableType is typically used. * - If a status response is expected on success, DataModel::NullObjectType. * */ template CHIP_ERROR InvokeCommandRequest(Messaging::ExchangeManager * aExchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId, const RequestObjectT & requestCommandData, typename TypedCommandCallback::OnSuccessCallbackType onSuccessCb, typename TypedCommandCallback::OnErrorCallbackType onErrorCb, const Optional & timedInvokeTimeoutMs, const Optional & responseTimeout = NullOptional, Internal::InvokeCancelFn * outCancelFn = nullptr) { // InvokeCommandRequest expects responses, so cannot happen over a group session. VerifyOrReturnError(!sessionHandle->IsGroupSession(), CHIP_ERROR_INVALID_ARGUMENT); app::CommandPathParams commandPath = { endpointId, 0, RequestObjectT::GetClusterId(), RequestObjectT::GetCommandId(), (app::CommandPathFlags::kEndpointIdValid) }; // // Let's create a handle version of the decoder to ensure we do correct clean-up of it if things go south at any point below // auto decoder = chip::Platform::MakeUnique>(onSuccessCb, onErrorCb); VerifyOrReturnError(decoder != nullptr, CHIP_ERROR_NO_MEMORY); // // Upon successful completion of SendCommandRequest below, we're expected to free up the respective allocated objects // in the OnDone callback. // auto onDone = [rawDecoderPtr = decoder.get()](app::CommandSender * commandSender) { chip::Platform::Delete(commandSender); chip::Platform::Delete(rawDecoderPtr); }; decoder->SetOnDoneCallback(onDone); auto commandSender = chip::Platform::MakeUnique(decoder.get(), aExchangeMgr, timedInvokeTimeoutMs.HasValue()); VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY); ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, requestCommandData, timedInvokeTimeoutMs)); ReturnErrorOnFailure(commandSender->SendCommandRequest(sessionHandle, responseTimeout)); // If requested by the caller, provide a way to cancel the invoke interaction. if (outCancelFn != nullptr) { *outCancelFn = [rawDecoderPtr = decoder.get(), rawCommandSender = commandSender.get()]() { chip::Platform::Delete(rawCommandSender); chip::Platform::Delete(rawDecoderPtr); }; } // // We've effectively transferred ownership of the above allocated objects to CommandSender, and we need to wait for it to call // us back when processing is completed (through OnDone) to eventually free up resources. // // So signal that by releasing the smart pointer. // decoder.release(); commandSender.release(); return CHIP_NO_ERROR; } /* * A typed group command invocation function that takes as input a cluster-object representation of a command request. * * The RequestObjectT is generally expected to be a ClusterName::Commands::CommandName::Type struct, but any object * that can be encoded using the DataModel::Encode machinery and exposes the GetClusterId() and GetCommandId() functions * and a ResponseType type is expected to work. * * Since this sends a group command, no response will be received and all allocated resources will be cleared before exiting this * function */ template CHIP_ERROR InvokeGroupCommandRequest(Messaging::ExchangeManager * exchangeMgr, chip::FabricIndex fabric, chip::GroupId groupId, const RequestObjectT & requestCommandData) { app::CommandPathParams commandPath = { groupId, RequestObjectT::GetClusterId(), RequestObjectT::GetCommandId(), app::CommandPathFlags::kGroupIdValid }; Transport::OutgoingGroupSession session(groupId, fabric); auto commandSender = chip::Platform::MakeUnique(nullptr, exchangeMgr); VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY); ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, requestCommandData)); return commandSender->SendGroupCommandRequest(SessionHandle(session)); } template CHIP_ERROR InvokeCommandRequest(Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId, const RequestObjectT & requestCommandData, typename TypedCommandCallback::OnSuccessCallbackType onSuccessCb, typename TypedCommandCallback::OnErrorCallbackType onErrorCb, uint16_t timedInvokeTimeoutMs, const Optional & responseTimeout = NullOptional) { return InvokeCommandRequest(exchangeMgr, sessionHandle, endpointId, requestCommandData, onSuccessCb, onErrorCb, MakeOptional(timedInvokeTimeoutMs), responseTimeout); } template = 0> CHIP_ERROR InvokeCommandRequest(Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId, const RequestObjectT & requestCommandData, typename TypedCommandCallback::OnSuccessCallbackType onSuccessCb, typename TypedCommandCallback::OnErrorCallbackType onErrorCb, const Optional & responseTimeout = NullOptional) { return InvokeCommandRequest(exchangeMgr, sessionHandle, endpointId, requestCommandData, onSuccessCb, onErrorCb, NullOptional, responseTimeout); } } // namespace Controller } // namespace chip