Skip to content

Commit

Permalink
Update CommandSender to support sending batch commands (#30675)
Browse files Browse the repository at this point in the history
* Update CommandSender to support sending batch commands
  • Loading branch information
tehampson authored and pull[bot] committed Mar 5, 2024
1 parent dab58a5 commit 1030754
Show file tree
Hide file tree
Showing 6 changed files with 289 additions and 49 deletions.
1 change: 1 addition & 0 deletions docs/ERROR_CODES.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ This file was **AUTOMATICALLY** generated by
| 182 | 0xB6 | `CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB` |
| 185 | 0xB9 | `CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_IB` |
| 186 | 0xBA | `CHIP_ERROR_IM_MALFORMED_EVENT_DATA_IB` |
| 187 | 0xBB | `CHIP_ERROR_MAXIMUM_PATHS_PER_INVOKE_EXCEEDED` |
| 188 | 0xBC | `CHIP_ERROR_PEER_NODE_NOT_FOUND` |
| 189 | 0xBD | `CHIP_ERROR_HSM` |
| 191 | 0xBF | `CHIP_ERROR_REAL_TIME_NOT_SYNCED` |
Expand Down
94 changes: 81 additions & 13 deletions src/app/CommandSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,33 @@

namespace chip {
namespace app {
namespace {

// Gets the CommandRef if available. Error returned if we expected CommandRef and it wasn't
// provided in the response.
template <typename ParserT>
CHIP_ERROR GetRef(ParserT aParser, Optional<uint16_t> & aRef, bool commandRefExpected)
{
CHIP_ERROR err = CHIP_NO_ERROR;
uint16_t ref;
err = aParser.GetRef(&ref);

VerifyOrReturnError(err == CHIP_NO_ERROR || err == CHIP_END_OF_TLV, err);
if (err == CHIP_END_OF_TLV)
{
if (commandRefExpected)
{
return CHIP_ERROR_INVALID_ARGUMENT;
}
aRef = NullOptional;
return CHIP_NO_ERROR;
}

aRef = MakeOptional(ref);
return CHIP_NO_ERROR;
}

} // namespace

CommandSender::CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest,
bool aSuppressResponse) :
Expand Down Expand Up @@ -296,8 +323,10 @@ CHIP_ERROR CommandSender::ProcessInvokeResponseIB(InvokeResponseIB::Parser & aIn
StatusIB statusIB;

{
bool hasDataResponse = false;
bool commandRefExpected = (mFinishedCommandCount > 1);
bool hasDataResponse = false;
TLV::TLVReader commandDataReader;
AdditionalResponseData additionalResponseData;

CommandStatusIB::Parser commandStatus;
err = aInvokeResponse.GetStatus(&commandStatus);
Expand All @@ -312,6 +341,7 @@ CHIP_ERROR CommandSender::ProcessInvokeResponseIB(InvokeResponseIB::Parser & aIn
StatusIB::Parser status;
commandStatus.GetErrorStatus(&status);
ReturnErrorOnFailure(status.DecodeStatusIB(statusIB));
ReturnErrorOnFailure(GetRef(commandStatus, additionalResponseData.mCommandRef, commandRefExpected));
}
else if (CHIP_END_OF_TLV == err)
{
Expand All @@ -323,6 +353,7 @@ CHIP_ERROR CommandSender::ProcessInvokeResponseIB(InvokeResponseIB::Parser & aIn
ReturnErrorOnFailure(commandPath.GetClusterId(&clusterId));
ReturnErrorOnFailure(commandPath.GetCommandId(&commandId));
commandData.GetFields(&commandDataReader);
ReturnErrorOnFailure(GetRef(commandData, additionalResponseData.mCommandRef, commandRefExpected));
err = CHIP_NO_ERROR;
hasDataResponse = true;
}
Expand Down Expand Up @@ -355,8 +386,8 @@ CHIP_ERROR CommandSender::ProcessInvokeResponseIB(InvokeResponseIB::Parser & aIn
{
if (statusIB.IsSuccess())
{
mpCallback->OnResponse(this, ConcreteCommandPath(endpointId, clusterId, commandId), statusIB,
hasDataResponse ? &commandDataReader : nullptr);
mpCallback->OnResponseWithAdditionalData(this, ConcreteCommandPath(endpointId, clusterId, commandId), statusIB,
hasDataResponse ? &commandDataReader : nullptr, additionalResponseData);
}
else
{
Expand All @@ -367,22 +398,46 @@ CHIP_ERROR CommandSender::ProcessInvokeResponseIB(InvokeResponseIB::Parser & aIn
return CHIP_NO_ERROR;
}

CHIP_ERROR CommandSender::PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct)
CHIP_ERROR CommandSender::SetCommandSenderConfig(CommandSender::ConfigParameters & aConfigParams)
{
#if CHIP_CONFIG_SENDING_BATCH_COMMANDS_ENABLED
VerifyOrReturnError(mState == State::Idle, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(aConfigParams.mRemoteMaxPathsPerInvoke > 0, CHIP_ERROR_INVALID_ARGUMENT);

mRemoteMaxPathsPerInvoke = aConfigParams.mRemoteMaxPathsPerInvoke;
mBatchCommandsEnabled = (aConfigParams.mRemoteMaxPathsPerInvoke > 1);
return CHIP_NO_ERROR;
#else
VerifyOrReturnError(aConfigParams.mRemoteMaxPathsPerInvoke == 1, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
return CHIP_NO_ERROR;
#endif
}

CHIP_ERROR CommandSender::PrepareCommand(const CommandPathParams & aCommandPathParams, AdditionalCommandParameters & aOptionalArgs)
{
ReturnErrorOnFailure(AllocateBuffer());

//
// We must not be in the middle of preparing a command, or having prepared or sent one.
// We must not be in the middle of preparing a command, and must not have already sent InvokeRequestMessage.
//
VerifyOrReturnError(mState == State::Idle, CHIP_ERROR_INCORRECT_STATE);
bool canAddAnotherCommand = (mState == State::AddedCommand && mBatchCommandsEnabled);
VerifyOrReturnError(mState == State::Idle || canAddAnotherCommand, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(mFinishedCommandCount < mRemoteMaxPathsPerInvoke, CHIP_ERROR_MAXIMUM_PATHS_PER_INVOKE_EXCEEDED);

VerifyOrReturnError(!aOptionalArgs.mCommandRef.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
if (mBatchCommandsEnabled)
{
aOptionalArgs.mCommandRef.SetValue(mFinishedCommandCount);
}

InvokeRequests::Builder & invokeRequests = mInvokeRequestBuilder.GetInvokeRequests();
CommandDataIB::Builder & invokeRequest = invokeRequests.CreateCommandData();
ReturnErrorOnFailure(invokeRequests.GetError());
CommandPathIB::Builder & path = invokeRequest.CreatePath();
ReturnErrorOnFailure(invokeRequest.GetError());
ReturnErrorOnFailure(path.Encode(aCommandPathParams));

if (aStartDataStruct)
if (aOptionalArgs.mStartOrEndDataStruct)
{
ReturnErrorOnFailure(invokeRequest.GetWriter()->StartContainer(TLV::ContextTag(CommandDataIB::Tag::kFields),
TLV::kTLVType_Structure, mDataElementContainerType));
Expand All @@ -392,25 +447,35 @@ CHIP_ERROR CommandSender::PrepareCommand(const CommandPathParams & aCommandPathP
return CHIP_NO_ERROR;
}

CHIP_ERROR CommandSender::FinishCommand(bool aEndDataStruct)
CHIP_ERROR CommandSender::FinishCommand(const AdditionalCommandParameters & aOptionalArgs)
{
CHIP_ERROR err = CHIP_NO_ERROR;

VerifyOrReturnError(mState == State::AddingCommand, err = CHIP_ERROR_INCORRECT_STATE);

CommandDataIB::Builder & commandData = mInvokeRequestBuilder.GetInvokeRequests().GetCommandData();

if (aEndDataStruct)
if (aOptionalArgs.mStartOrEndDataStruct)
{
ReturnErrorOnFailure(commandData.GetWriter()->EndContainer(mDataElementContainerType));
}

if (mBatchCommandsEnabled)
{
// If error below occurs, aOptionalArgs.mCommandRef was modified since PerpareCommand was called.
VerifyOrReturnError(aOptionalArgs.mCommandRef.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
}

if (aOptionalArgs.mCommandRef.HasValue())
{
ReturnErrorOnFailure(commandData.Ref(aOptionalArgs.mCommandRef.Value()));
}

ReturnErrorOnFailure(commandData.EndOfCommandDataIB());
ReturnErrorOnFailure(mInvokeRequestBuilder.GetInvokeRequests().EndOfInvokeRequests());
ReturnErrorOnFailure(mInvokeRequestBuilder.EndOfInvokeRequestMessage());

MoveToState(State::AddedCommand);

mFinishedCommandCount++;
return CHIP_NO_ERROR;
}

Expand All @@ -424,9 +489,10 @@ TLV::TLVWriter * CommandSender::GetCommandDataIBTLVWriter()
return mInvokeRequestBuilder.GetInvokeRequests().GetCommandData().GetWriter();
}

CHIP_ERROR CommandSender::FinishCommand(const Optional<uint16_t> & aTimedInvokeTimeoutMs)
CHIP_ERROR CommandSender::FinishCommand(const Optional<uint16_t> & aTimedInvokeTimeoutMs,
const AdditionalCommandParameters & aOptionalArgs)
{
ReturnErrorOnFailure(FinishCommand(/* aEndDataStruct = */ false));
ReturnErrorOnFailure(FinishCommand(aOptionalArgs));
if (!mTimedInvokeTimeoutMs.HasValue())
{
mTimedInvokeTimeoutMs = aTimedInvokeTimeoutMs;
Expand All @@ -442,6 +508,8 @@ CHIP_ERROR CommandSender::FinishCommand(const Optional<uint16_t> & aTimedInvokeT
CHIP_ERROR CommandSender::Finalize(System::PacketBufferHandle & commandPacket)
{
VerifyOrReturnError(mState == State::AddedCommand, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorOnFailure(mInvokeRequestBuilder.GetInvokeRequests().EndOfInvokeRequests());
ReturnErrorOnFailure(mInvokeRequestBuilder.EndOfInvokeRequestMessage());
return mCommandMessageWriter.Finalize(&commandPacket);
}

Expand Down
Loading

0 comments on commit 1030754

Please sign in to comment.