From ddeb8701156dbe41b8e5365b3bd6bd638af3e30f Mon Sep 17 00:00:00 2001 From: Yunhan Wang Date: Thu, 28 Oct 2021 18:05:09 -0700 Subject: [PATCH] Refresh IM Invoke encoding with latest spec --- src/app/BUILD.gn | 13 +- src/app/Command.cpp | 156 +------ src/app/Command.h | 31 +- src/app/CommandHandler.cpp | 157 ++++++- src/app/CommandHandler.h | 28 +- src/app/CommandSender.cpp | 213 +++++++-- src/app/CommandSender.h | 25 +- src/app/InteractionModelEngine.h | 1 - src/app/MessageDef/CommandDataIB.cpp | 152 ++----- src/app/MessageDef/CommandDataIB.h | 44 +- src/app/MessageDef/CommandPathIB.cpp | 4 +- src/app/MessageDef/CommandPathIB.h | 2 +- src/app/MessageDef/CommandStatusIB.cpp | 173 ++++++++ src/app/MessageDef/CommandStatusIB.h | 151 +++++++ src/app/MessageDef/InvokeCommand.cpp | 161 ------- src/app/MessageDef/InvokeRequestMessage.cpp | 184 ++++++++ src/app/MessageDef/InvokeRequestMessage.h | 151 +++++++ .../{CommandList.cpp => InvokeRequests.cpp} | 53 +-- .../{CommandList.h => InvokeRequests.h} | 22 +- src/app/MessageDef/InvokeResponseIB.cpp | 166 +++++++ src/app/MessageDef/InvokeResponseIB.h | 145 +++++++ src/app/MessageDef/InvokeResponseMessage.cpp | 156 +++++++ ...nvokeCommand.h => InvokeResponseMessage.h} | 48 ++- src/app/MessageDef/InvokeResponses.cpp | 96 +++++ src/app/MessageDef/InvokeResponses.h | 88 ++++ .../operational-credentials-server.cpp | 3 +- src/app/tests/TestCommandInteraction.cpp | 202 ++++++--- src/app/tests/TestMessageDef.cpp | 408 ++++++++++++++---- .../tests/integration/chip_im_initiator.cpp | 1 - src/lib/core/CHIPError.cpp | 12 + src/lib/core/CHIPError.h | 36 ++ 31 files changed, 2338 insertions(+), 744 deletions(-) create mode 100644 src/app/MessageDef/CommandStatusIB.cpp create mode 100644 src/app/MessageDef/CommandStatusIB.h delete mode 100644 src/app/MessageDef/InvokeCommand.cpp create mode 100644 src/app/MessageDef/InvokeRequestMessage.cpp create mode 100644 src/app/MessageDef/InvokeRequestMessage.h rename src/app/MessageDef/{CommandList.cpp => InvokeRequests.cpp} (57%) rename src/app/MessageDef/{CommandList.h => InvokeRequests.h} (86%) create mode 100644 src/app/MessageDef/InvokeResponseIB.cpp create mode 100644 src/app/MessageDef/InvokeResponseIB.h create mode 100644 src/app/MessageDef/InvokeResponseMessage.cpp rename src/app/MessageDef/{InvokeCommand.h => InvokeResponseMessage.h} (65%) create mode 100644 src/app/MessageDef/InvokeResponses.cpp create mode 100644 src/app/MessageDef/InvokeResponses.h diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 5fa15d41afd031..021e391a659927 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -58,11 +58,8 @@ static_library("app") { "MessageDef/Builder.cpp", "MessageDef/Builder.h", "MessageDef/CommandDataIB.cpp", - "MessageDef/CommandDataIB.h", - "MessageDef/CommandList.cpp", - "MessageDef/CommandList.h", "MessageDef/CommandPathIB.cpp", - "MessageDef/CommandPathIB.h", + "MessageDef/CommandStatusIB.cpp", "MessageDef/EventDataElement.cpp", "MessageDef/EventDataElement.h", "MessageDef/EventList.cpp", @@ -71,8 +68,11 @@ static_library("app") { "MessageDef/EventPath.h", "MessageDef/EventPathList.cpp", "MessageDef/EventPathList.h", - "MessageDef/InvokeCommand.cpp", - "MessageDef/InvokeCommand.h", + "MessageDef/InvokeRequestMessage.cpp", + "MessageDef/InvokeRequests.cpp", + "MessageDef/InvokeResponseIB.cpp", + "MessageDef/InvokeResponseMessage.cpp", + "MessageDef/InvokeResponses.cpp", "MessageDef/ListBuilder.cpp", "MessageDef/ListBuilder.h", "MessageDef/ListParser.cpp", @@ -86,7 +86,6 @@ static_library("app") { "MessageDef/ReportData.cpp", "MessageDef/ReportData.h", "MessageDef/StatusIB.cpp", - "MessageDef/StatusIB.h", "MessageDef/StatusResponse.cpp", "MessageDef/SubscribeRequest.cpp", "MessageDef/SubscribeResponse.cpp", diff --git a/src/app/Command.cpp b/src/app/Command.cpp index b2bdcb305090eb..22f7198477c68e 100644 --- a/src/app/Command.cpp +++ b/src/app/Command.cpp @@ -23,10 +23,6 @@ */ #include "Command.h" -#include "CommandHandler.h" -#include "CommandSender.h" -#include "InteractionModelEngine.h" - #include #include @@ -35,165 +31,21 @@ namespace app { Command::Command() {} -CHIP_ERROR Command::AllocateBuffer() -{ - CHIP_ERROR err = CHIP_NO_ERROR; - CommandList::Builder commandListBuilder; - - if (!mBufferAllocated) - { - mCommandMessageWriter.Reset(); - - System::PacketBufferHandle commandPacket = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes); - VerifyOrExit(!commandPacket.IsNull(), err = CHIP_ERROR_NO_MEMORY); - - mCommandMessageWriter.Init(std::move(commandPacket)); - err = mInvokeCommandBuilder.Init(&mCommandMessageWriter); - SuccessOrExit(err); - - commandListBuilder = mInvokeCommandBuilder.CreateCommandListBuilder(); - err = commandListBuilder.GetError(); - SuccessOrExit(err); - - mCommandIndex = 0; - - mBufferAllocated = true; - } - -exit: - return err; -} - -CHIP_ERROR Command::ProcessCommandMessage(System::PacketBufferHandle && payload, CommandRoleId aCommandRoleId) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - chip::System::PacketBufferTLVReader reader; - chip::TLV::TLVReader commandListReader; - InvokeCommand::Parser invokeCommandParser; - CommandList::Parser commandListParser; - - reader.Init(std::move(payload)); - err = reader.Next(); - SuccessOrExit(err); - - err = invokeCommandParser.Init(reader); - SuccessOrExit(err); - -#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - err = invokeCommandParser.CheckSchemaValidity(); - SuccessOrExit(err); -#endif - err = invokeCommandParser.GetCommandList(&commandListParser); - SuccessOrExit(err); - - commandListParser.GetReader(&commandListReader); - - while (CHIP_NO_ERROR == (err = commandListReader.Next())) - { - VerifyOrExit(chip::TLV::AnonymousTag == commandListReader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG); - VerifyOrExit(chip::TLV::kTLVType_Structure == commandListReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - CommandDataIB::Parser commandElement; - - err = commandElement.Init(commandListReader); - SuccessOrExit(err); - - err = ProcessCommandDataIB(commandElement); - SuccessOrExit(err); - } - - // if we have exhausted this container - if (CHIP_END_OF_TLV == err) - { - err = CHIP_NO_ERROR; - } - -exit: - return err; -} - -CHIP_ERROR Command::PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - CommandDataIB::Builder commandDataIB; - - err = AllocateBuffer(); - SuccessOrExit(err); - - // - // We must not be in the middle of preparing a command, or having prepared or sent one. - // - VerifyOrExit(mState == CommandState::Idle, err = CHIP_ERROR_INCORRECT_STATE); - - commandDataIB = mInvokeCommandBuilder.GetCommandListBuilder().CreateCommandDataIBBuilder(); - err = commandDataIB.GetError(); - SuccessOrExit(err); - - err = ConstructCommandPath(aCommandPathParams, commandDataIB); - SuccessOrExit(err); - - if (aStartDataStruct) - { - err = commandDataIB.GetWriter()->StartContainer(TLV::ContextTag(CommandDataIB::kCsTag_Data), TLV::kTLVType_Structure, - mDataElementContainerType); - } - - MoveToState(CommandState::AddingCommand); - -exit: - return err; -} - -TLV::TLVWriter * Command::GetCommandDataIBTLVWriter() -{ - if (mState != CommandState::AddingCommand) - { - return nullptr; - } - else - { - return mInvokeCommandBuilder.GetCommandListBuilder().GetCommandDataIBBuilder().GetWriter(); - } -} - CHIP_ERROR Command::Finalize(System::PacketBufferHandle & commandPacket) { VerifyOrReturnError(mState == CommandState::AddedCommand, CHIP_ERROR_INCORRECT_STATE); return mCommandMessageWriter.Finalize(&commandPacket); } -CHIP_ERROR Command::FinishCommand(bool aEndDataStruct) +CHIP_ERROR Command::ConstructCommandPath(const CommandPathParams & aCommandPathParams, CommandPathIB::Builder & aCommandPath) { - CHIP_ERROR err = CHIP_NO_ERROR; - - VerifyOrReturnError(mState == CommandState::AddingCommand, err = CHIP_ERROR_INCORRECT_STATE); - - CommandDataIB::Builder commandDataIB = mInvokeCommandBuilder.GetCommandListBuilder().GetCommandDataIBBuilder(); - if (aEndDataStruct) - { - ReturnErrorOnFailure(commandDataIB.GetWriter()->EndContainer(mDataElementContainerType)); - } - - ReturnErrorOnFailure(commandDataIB.EndOfCommandDataIB().GetError()); - ReturnErrorOnFailure(mInvokeCommandBuilder.GetCommandListBuilder().EndOfCommandList().GetError()); - ReturnErrorOnFailure(mInvokeCommandBuilder.EndOfInvokeCommand().GetError()); - - MoveToState(CommandState::AddedCommand); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR Command::ConstructCommandPath(const CommandPathParams & aCommandPathParams, CommandDataIB::Builder aCommandDataIB) -{ - CommandPathIB::Builder commandPath = aCommandDataIB.CreateCommandPathBuilder(); if (aCommandPathParams.mFlags.Has(CommandPathFlags::kEndpointIdValid)) { - commandPath.EndpointId(aCommandPathParams.mEndpointId); + aCommandPath.EndpointId(aCommandPathParams.mEndpointId); } - commandPath.ClusterId(aCommandPathParams.mClusterId).CommandId(aCommandPathParams.mCommandId).EndOfCommandPath(); - - return commandPath.GetError(); + aCommandPath.ClusterId(aCommandPathParams.mClusterId).CommandId(aCommandPathParams.mCommandId).EndOfCommandPathIB(); + return aCommandPath.GetError(); } void Command::Abort() diff --git a/src/app/Command.h b/src/app/Command.h index f396ad778c789d..5e8cb64b62f0c8 100644 --- a/src/app/Command.h +++ b/src/app/Command.h @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include #include @@ -47,12 +45,6 @@ namespace app { class Command { public: - enum class CommandRoleId - { - SenderId = 0, - HandlerId = 1, - }; - enum class CommandState { Idle, ///< Default state that the object starts out in, where no work has commenced @@ -70,12 +62,6 @@ class Command */ virtual ~Command() { Abort(); } - /* - * A set of methods to construct command request or response payloads - */ - CHIP_ERROR PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct = true); - TLV::TLVWriter * GetCommandDataIBTLVWriter(); - CHIP_ERROR FinishCommand(bool aEndDataStruct = true); CHIP_ERROR Finalize(System::PacketBufferHandle & commandPacket); virtual CHIP_ERROR AddStatus(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus) @@ -102,19 +88,9 @@ class Command */ Messaging::ExchangeContext * GetExchangeContext() const { return mpExchangeCtx; } - virtual CHIP_ERROR ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement) = 0; - protected: Command(); - /* - * Allocates a packet buffer used for encoding an invoke request/response payload. - * - * This can be called multiple times safely, as it will only allocate the buffer once for the lifetime - * of this object. - */ - CHIP_ERROR AllocateBuffer(); - /* * The actual closure of the exchange happens automatically in the exchange layer. * This function just sets the internally tracked exchange pointer to null to align @@ -123,15 +99,14 @@ class Command void Close(); void MoveToState(const CommandState aTargetState); - CHIP_ERROR ProcessCommandMessage(System::PacketBufferHandle && payload, CommandRoleId aCommandRoleId); - CHIP_ERROR ConstructCommandPath(const CommandPathParams & aCommandPathParams, CommandDataIB::Builder aCommandDataIB); + CHIP_ERROR ConstructCommandPath(const CommandPathParams & aCommandPathParams, CommandPathIB::Builder & aCommandPath); const char * GetStateStr() const; - InvokeCommand::Builder mInvokeCommandBuilder; Messaging::ExchangeContext * mpExchangeCtx = nullptr; uint8_t mCommandIndex = 0; CommandState mState = CommandState::Idle; chip::System::PacketBufferTLVWriter mCommandMessageWriter; + bool mBufferAllocated = false; private: /* @@ -143,8 +118,6 @@ class Command void Abort(); friend class TestCommandInteraction; - TLV::TLVType mDataElementContainerType = TLV::kTLVType_NotSpecified; - bool mBufferAllocated = false; }; } // namespace app } // namespace chip diff --git a/src/app/CommandHandler.cpp b/src/app/CommandHandler.cpp index 44612eeed3df81..23f18d8e93a691 100644 --- a/src/app/CommandHandler.cpp +++ b/src/app/CommandHandler.cpp @@ -34,7 +34,32 @@ namespace chip { namespace app { -CommandHandler::CommandHandler(Callback * apCallback) : mpCallback(apCallback) {} +CommandHandler::CommandHandler(Callback * apCallback) : mpCallback(apCallback), mSuppressResponse(false) {} + +CHIP_ERROR CommandHandler::AllocateBuffer() +{ + if (!mBufferAllocated) + { + mCommandMessageWriter.Reset(); + + System::PacketBufferHandle commandPacket = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes); + VerifyOrReturnError(!commandPacket.IsNull(), CHIP_ERROR_NO_MEMORY); + + mCommandMessageWriter.Init(std::move(commandPacket)); + ReturnErrorOnFailure(mInvokeResponseMessage.Init(&mCommandMessageWriter)); + + mInvokeResponseMessage.SuppressResponse(mSuppressResponse); + ReturnErrorOnFailure(mInvokeResponseMessage.GetError()); + + mInvokeResponseMessage.CreateInvokeResponses(); + ReturnErrorOnFailure(mInvokeResponseMessage.GetError()); + + mCommandIndex = 0; + mBufferAllocated = true; + } + + return CHIP_NO_ERROR; +} CHIP_ERROR CommandHandler::OnInvokeCommandRequest(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader, System::PacketBufferHandle && payload) @@ -49,7 +74,7 @@ CHIP_ERROR CommandHandler::OnInvokeCommandRequest(Messaging::ExchangeContext * e mpExchangeCtx = ec; - err = ProcessCommandMessage(std::move(payload), CommandRoleId::HandlerId); + err = ProcessInvokeRequestMessage(std::move(payload)); SuccessOrExit(err); err = SendCommandResponse(); @@ -60,8 +85,43 @@ CHIP_ERROR CommandHandler::OnInvokeCommandRequest(Messaging::ExchangeContext * e return err; } +CHIP_ERROR CommandHandler::ProcessInvokeRequestMessage(System::PacketBufferHandle && payload) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + System::PacketBufferTLVReader reader; + TLV::TLVReader invokeRequestsReader; + InvokeRequestMessage::Parser invokeRequestMessage; + InvokeRequests::Parser invokeRequests; + reader.Init(std::move(payload)); + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(invokeRequestMessage.Init(reader)); +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + ReturnErrorOnFailure(invokeRequestMessage.CheckSchemaValidity()); +#endif + ReturnErrorOnFailure(invokeRequestMessage.GetSuppressResponse(&mSuppressResponse)); + ReturnErrorOnFailure(invokeRequestMessage.GetTimedRequest(&mTimedRequest)); + ReturnErrorOnFailure(invokeRequestMessage.GetInvokeRequests(&invokeRequests)); + + invokeRequests.GetReader(&invokeRequestsReader); + while (CHIP_NO_ERROR == (err = invokeRequestsReader.Next())) + { + VerifyOrReturnError(TLV::AnonymousTag == invokeRequestsReader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG); + CommandDataIB::Parser commandData; + ReturnErrorOnFailure(commandData.Init(invokeRequestsReader)); + ReturnErrorOnFailure(ProcessCommandData(commandData)); + } + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + err = CHIP_NO_ERROR; + } + return err; +} + void CommandHandler::Close() { + mSuppressResponse = false; MoveToState(CommandState::AwaitingDestruction); Command::Close(); @@ -90,16 +150,16 @@ CHIP_ERROR CommandHandler::SendCommandResponse() return CHIP_NO_ERROR; } -CHIP_ERROR CommandHandler::ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement) +CHIP_ERROR CommandHandler::ProcessCommandData(CommandDataIB::Parser & aCommandElement) { CHIP_ERROR err = CHIP_NO_ERROR; CommandPathIB::Parser commandPath; - chip::TLV::TLVReader commandDataReader; - chip::ClusterId clusterId; - chip::CommandId commandId; - chip::EndpointId endpointId; + TLV::TLVReader commandDataReader; + ClusterId clusterId; + CommandId commandId; + EndpointId endpointId; - err = aCommandElement.GetCommandPath(&commandPath); + err = aCommandElement.GetPath(&commandPath); SuccessOrExit(err); err = commandPath.GetClusterId(&clusterId); @@ -110,10 +170,8 @@ CHIP_ERROR CommandHandler::ProcessCommandDataIB(CommandDataIB::Parser & aCommand err = commandPath.GetEndpointId(&endpointId); SuccessOrExit(err); - VerifyOrExit(ServerClusterCommandExists(ConcreteCommandPath(endpointId, clusterId, commandId)), err = CHIP_ERROR_INVALID_PROFILE_ID); - err = aCommandElement.GetData(&commandDataReader); if (CHIP_END_OF_TLV == err) { @@ -168,10 +226,10 @@ CHIP_ERROR CommandHandler::AddStatusInternal(const ConcreteCommandPath & aComman aCommandPath.mClusterId, aCommandPath.mCommandId, chip::app::CommandPathFlags::kEndpointIdValid }; - err = PrepareCommand(commandPathParams, false /* aStartDataStruct */); + err = PrepareStatus(commandPathParams); SuccessOrExit(err); - statusIBBuilder = mInvokeCommandBuilder.GetCommandListBuilder().GetCommandDataIBBuilder().CreateStatusIBBuilder(); + statusIBBuilder = mInvokeResponseMessage.GetInvokeResponses().GetInvokeResponse().GetStatus().CreateErrorStatus(); // // TODO: Most of the callers are incorrectly passing SecureChannel as the protocol ID, when in fact, the status code provided @@ -184,7 +242,7 @@ CHIP_ERROR CommandHandler::AddStatusInternal(const ConcreteCommandPath & aComman err = statusIBBuilder.GetError(); SuccessOrExit(err); - err = FinishCommand(false /* aEndDataStruct */); + err = FinishStatus(); exit: return err; @@ -216,5 +274,78 @@ CHIP_ERROR CommandHandler::PrepareResponse(const ConcreteCommandPath & aRequestC return PrepareCommand(params, false /* aStartDataStruct */); } +CHIP_ERROR CommandHandler::PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct) +{ + ReturnErrorOnFailure(AllocateBuffer()); + // + // We must not be in the middle of preparing a command, or having prepared or sent one. + // + VerifyOrReturnError(mState == CommandState::Idle, CHIP_ERROR_INCORRECT_STATE); + CommandDataIB::Builder commandData = mInvokeResponseMessage.GetInvokeResponses().CreateInvokeResponse().CreateCommand(); + ReturnErrorOnFailure(commandData.GetError()); + ReturnErrorOnFailure(ConstructCommandPath(aCommandPathParams, commandData.CreatePath())); + if (aStartDataStruct) + { + ReturnErrorOnFailure(commandData.GetWriter()->StartContainer(TLV::ContextTag(to_underlying(CommandDataIB::Tag::kData)), + TLV::kTLVType_Structure, mDataElementContainerType)); + } + MoveToState(CommandState::AddingCommand); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommandHandler::FinishCommand(bool aStartDataStruct) +{ + VerifyOrReturnError(mState == CommandState::AddingCommand, CHIP_ERROR_INCORRECT_STATE); + CommandDataIB::Builder commandData = mInvokeResponseMessage.GetInvokeResponses().GetInvokeResponse().GetCommand(); + if (aStartDataStruct) + { + ReturnErrorOnFailure(commandData.GetWriter()->EndContainer(mDataElementContainerType)); + } + ReturnErrorOnFailure(commandData.EndOfCommandDataIB().GetError()); + ReturnErrorOnFailure(mInvokeResponseMessage.GetInvokeResponses().GetInvokeResponse().EndOfInvokeResponseIB().GetError()); + ReturnErrorOnFailure(mInvokeResponseMessage.GetInvokeResponses().EndOfInvokeResponses().GetError()); + ReturnErrorOnFailure(mInvokeResponseMessage.EndOfInvokeResponseMessage().GetError()); + MoveToState(CommandState::AddedCommand); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommandHandler::PrepareStatus(const CommandPathParams & aCommandPathParams) +{ + ReturnErrorOnFailure(AllocateBuffer()); + // + // We must not be in the middle of preparing a command, or having prepared or sent one. + // + VerifyOrReturnError(mState == CommandState::Idle, CHIP_ERROR_INCORRECT_STATE); + CommandStatusIB::Builder commandStatus = mInvokeResponseMessage.GetInvokeResponses().CreateInvokeResponse().CreateStatus(); + ReturnErrorOnFailure(commandStatus.GetError()); + ReturnErrorOnFailure(ConstructCommandPath(aCommandPathParams, commandStatus.CreatePath())); + MoveToState(CommandState::AddingCommand); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommandHandler::FinishStatus() +{ + VerifyOrReturnError(mState == CommandState::AddingCommand, CHIP_ERROR_INCORRECT_STATE); + ReturnErrorOnFailure( + mInvokeResponseMessage.GetInvokeResponses().GetInvokeResponse().GetStatus().EndOfCommandStatusIB().GetError()); + ReturnErrorOnFailure(mInvokeResponseMessage.GetInvokeResponses().GetInvokeResponse().EndOfInvokeResponseIB().GetError()); + ReturnErrorOnFailure(mInvokeResponseMessage.GetInvokeResponses().EndOfInvokeResponses().GetError()); + ReturnErrorOnFailure(mInvokeResponseMessage.EndOfInvokeResponseMessage().GetError()); + MoveToState(CommandState::AddedCommand); + return CHIP_NO_ERROR; +} + +TLV::TLVWriter * CommandHandler::GetCommandDataIBTLVWriter() +{ + if (mState != CommandState::AddingCommand) + { + return nullptr; + } + else + { + return mInvokeResponseMessage.GetInvokeResponses().GetInvokeResponse().GetCommand().GetWriter(); + } +} + } // namespace app } // namespace chip diff --git a/src/app/CommandHandler.h b/src/app/CommandHandler.h index 38837957397be0..72f4904b8f8962 100644 --- a/src/app/CommandHandler.h +++ b/src/app/CommandHandler.h @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -39,6 +38,9 @@ #include #include +#include +#include + namespace chip { namespace app { @@ -64,6 +66,14 @@ class CommandHandler : public Command */ CommandHandler(Callback * apCallback); + /* + * Allocates a packet buffer used for encoding an invoke response payload. + * + * This can be called multiple times safely, as it will only allocate the buffer once for the lifetime + * of this object. + */ + CHIP_ERROR AllocateBuffer(); + /* * Main entrypoint for this class to handle an invoke request. * @@ -78,6 +88,13 @@ class CommandHandler : public Command CHIP_ERROR AddClusterSpecificFailure(const ConcreteCommandPath & aCommandPath, ClusterStatus aClusterStatus) override; + CHIP_ERROR ProcessInvokeRequestMessage(System::PacketBufferHandle && payload); + CHIP_ERROR PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct = true); + CHIP_ERROR FinishCommand(bool aStartDataStruct = true); + CHIP_ERROR PrepareStatus(const CommandPathParams & aCommandPathParams); + CHIP_ERROR FinishStatus(); + TLV::TLVWriter * GetCommandDataIBTLVWriter(); + /** * API for adding a data response. The template parameter T is generally * expected to be a ClusterName::Commands::CommandName::Type struct, but any @@ -94,7 +111,7 @@ class CommandHandler : public Command ReturnErrorOnFailure(PrepareResponse(aRequestCommandPath, CommandData::GetCommandId())); TLV::TLVWriter * writer = GetCommandDataIBTLVWriter(); VerifyOrReturnError(writer != nullptr, CHIP_ERROR_INCORRECT_STATE); - ReturnErrorOnFailure(DataModel::Encode(*writer, TLV::ContextTag(CommandDataIB::kCsTag_Data), aData)); + ReturnErrorOnFailure(DataModel::Encode(*writer, TLV::ContextTag(to_underlying(CommandDataIB::Tag::kData)), aData)); return FinishCommand(/* aEndDataStruct = */ false); } @@ -106,15 +123,18 @@ class CommandHandler : public Command // safe to release this object. // void Close(); - friend class TestCommandInteraction; + CHIP_ERROR ProcessCommandData(CommandDataIB::Parser & aCommandElement); CHIP_ERROR SendCommandResponse(); - CHIP_ERROR ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement) override; CHIP_ERROR PrepareResponse(const ConcreteCommandPath & aRequestCommandPath, CommandId aResponseCommand); CHIP_ERROR AddStatusInternal(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus, const Optional & aClusterStatus); Callback * mpCallback = nullptr; + InvokeResponseMessage::Builder mInvokeResponseMessage; + TLV::TLVType mDataElementContainerType = TLV::kTLVType_NotSpecified; + bool mSuppressResponse = false; + bool mTimedRequest = false; }; } // namespace app } // namespace chip diff --git a/src/app/CommandSender.cpp b/src/app/CommandSender.cpp index c400caeac7a38c..b22354bf356bfc 100644 --- a/src/app/CommandSender.cpp +++ b/src/app/CommandSender.cpp @@ -33,9 +33,34 @@ namespace chip { namespace app { CommandSender::CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr) : - mpCallback(apCallback), mpExchangeMgr(apExchangeMgr) + mpCallback(apCallback), mpExchangeMgr(apExchangeMgr), mSuppressResponse(false), mTimedRequest(false) {} +CHIP_ERROR CommandSender::AllocateBuffer() +{ + if (!mBufferAllocated) + { + mCommandMessageWriter.Reset(); + + System::PacketBufferHandle commandPacket = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes); + VerifyOrReturnError(!commandPacket.IsNull(), CHIP_ERROR_NO_MEMORY); + + mCommandMessageWriter.Init(std::move(commandPacket)); + ReturnErrorOnFailure(mInvokeRequestMessage.Init(&mCommandMessageWriter)); + + mInvokeRequestMessage.SuppressResponse(mSuppressResponse).TimedRequest(mTimedRequest); + ReturnErrorOnFailure(mInvokeRequestMessage.GetError()); + + mInvokeRequestMessage.CreateInvokeRequests(); + ReturnErrorOnFailure(mInvokeRequestMessage.GetError()); + + mCommandIndex = 0; + mBufferAllocated = true; + } + + return CHIP_NO_ERROR; +} + CHIP_ERROR CommandSender::SendCommandRequest(SessionHandle session, System::Clock::Timeout timeout) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -71,7 +96,7 @@ CHIP_ERROR CommandSender::OnMessageReceived(Messaging::ExchangeContext * apExcha VerifyOrExit(aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::InvokeCommandResponse), err = CHIP_ERROR_INVALID_MESSAGE_TYPE); - SuccessOrExit(err = ProcessCommandMessage(std::move(aPayload), CommandRoleId::SenderId)); + err = ProcessInvokeResponseMessage(std::move(aPayload)); exit: if (mpCallback != nullptr) @@ -89,6 +114,58 @@ CHIP_ERROR CommandSender::OnMessageReceived(Messaging::ExchangeContext * apExcha return err; } +CHIP_ERROR CommandSender::ProcessInvokeResponseMessage(System::PacketBufferHandle && payload) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + System::PacketBufferTLVReader reader; + TLV::TLVReader invokeResponsesReader; + InvokeResponseMessage::Parser invokeResponseMessage; + InvokeResponses::Parser invokeResponses; + bool suppressResponse = false; + + reader.Init(std::move(payload)); + err = reader.Next(); + SuccessOrExit(err); + + err = invokeResponseMessage.Init(reader); + SuccessOrExit(err); + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = invokeResponseMessage.CheckSchemaValidity(); + SuccessOrExit(err); +#endif + + err = invokeResponseMessage.GetSuppressResponse(&suppressResponse); + SuccessOrExit(err); + + err = invokeResponseMessage.GetInvokeResponses(&invokeResponses); + SuccessOrExit(err); + + invokeResponses.GetReader(&invokeResponsesReader); + + while (CHIP_NO_ERROR == (err = invokeResponsesReader.Next())) + { + VerifyOrExit(TLV::AnonymousTag == invokeResponsesReader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG); + + InvokeResponseIB::Parser invokeResponse; + + err = invokeResponse.Init(invokeResponsesReader); + SuccessOrExit(err); + + err = ProcessInvokeResponse(invokeResponse); + SuccessOrExit(err); + } + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + err = CHIP_NO_ERROR; + } + +exit: + return err; +} + void CommandSender::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) { ChipLogProgress(DataManagement, "Time out! failed to receive invoke command response from Exchange: " ChipLogFormatExchange, @@ -106,6 +183,8 @@ void CommandSender::OnResponseTimeout(Messaging::ExchangeContext * apExchangeCon void CommandSender::Close() { + mSuppressResponse = false; + mTimedRequest = false; MoveToState(CommandState::AwaitingDestruction); Command::Close(); @@ -116,45 +195,59 @@ void CommandSender::Close() } } -CHIP_ERROR CommandSender::ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement) +CHIP_ERROR CommandSender::ProcessInvokeResponse(InvokeResponseIB::Parser & aInvokeResponse) { CHIP_ERROR err = CHIP_NO_ERROR; - chip::ClusterId clusterId; - chip::CommandId commandId; - chip::EndpointId endpointId; + ClusterId clusterId; + CommandId commandId; + EndpointId endpointId; // Default to success when an invoke response is received. StatusIB statusIB; - { - CommandPathIB::Parser commandPath; - - err = aCommandElement.GetCommandPath(&commandPath); - SuccessOrExit(err); - - err = commandPath.GetClusterId(&clusterId); - SuccessOrExit(err); - - err = commandPath.GetCommandId(&commandId); - SuccessOrExit(err); - - err = commandPath.GetEndpointId(&endpointId); - SuccessOrExit(err); - } - { bool hasDataResponse = false; - chip::TLV::TLVReader commandDataReader; + TLV::TLVReader commandDataReader; - StatusIB::Parser statusIBParser; - err = aCommandElement.GetStatusIB(&statusIBParser); + CommandStatusIB::Parser commandStatus; + err = aInvokeResponse.GetStatus(&commandStatus); if (CHIP_NO_ERROR == err) { - err = statusIBParser.DecodeStatusIB(statusIB); + CommandPathIB::Parser commandPath; + commandStatus.GetPath(&commandPath); + err = commandPath.GetClusterId(&clusterId); + SuccessOrExit(err); + + err = commandPath.GetCommandId(&commandId); + SuccessOrExit(err); + + err = commandPath.GetEndpointId(&endpointId); + SuccessOrExit(err); + + StatusIB::Parser status; + commandStatus.GetErrorStatus(&status); + err = status.DecodeStatusIB(statusIB); + SuccessOrExit(err); } else if (CHIP_END_OF_TLV == err) { hasDataResponse = true; - err = aCommandElement.GetData(&commandDataReader); + + CommandDataIB::Parser commandData; + CommandPathIB::Parser commandPath; + err = aInvokeResponse.GetCommand(&commandData); + SuccessOrExit(err); + commandData.GetPath(&commandPath); + + err = commandPath.GetClusterId(&clusterId); + SuccessOrExit(err); + + err = commandPath.GetCommandId(&commandId); + SuccessOrExit(err); + + err = commandPath.GetEndpointId(&endpointId); + SuccessOrExit(err); + + commandData.GetData(&commandDataReader); } if (err != CHIP_NO_ERROR) @@ -199,5 +292,71 @@ CHIP_ERROR CommandSender::ProcessCommandDataIB(CommandDataIB::Parser & aCommandE return err; } +CHIP_ERROR CommandSender::PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + CommandDataIB::Builder commandData; + + err = AllocateBuffer(); + SuccessOrExit(err); + + // + // We must not be in the middle of preparing a command, or having prepared or sent one. + // + VerifyOrExit(mState == CommandState::Idle, err = CHIP_ERROR_INCORRECT_STATE); + + commandData = mInvokeRequestMessage.GetInvokeRequests().CreateCommandData(); + err = commandData.GetError(); + SuccessOrExit(err); + + err = ConstructCommandPath(aCommandPathParams, commandData.CreatePath()); + SuccessOrExit(err); + + if (aStartDataStruct) + { + err = commandData.GetWriter()->StartContainer(TLV::ContextTag(to_underlying(CommandDataIB::Tag::kData)), + TLV::kTLVType_Structure, mDataElementContainerType); + } + + MoveToState(CommandState::AddingCommand); + +exit: + return err; +} + +CHIP_ERROR CommandSender::FinishCommand(bool aEndDataStruct) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrReturnError(mState == CommandState::AddingCommand, err = CHIP_ERROR_INCORRECT_STATE); + + CommandDataIB::Builder commandData = mInvokeRequestMessage.GetInvokeRequests().GetCommandData(); + + if (aEndDataStruct) + { + ReturnErrorOnFailure(commandData.GetWriter()->EndContainer(mDataElementContainerType)); + } + + ReturnErrorOnFailure(commandData.EndOfCommandDataIB().GetError()); + ReturnErrorOnFailure(mInvokeRequestMessage.GetInvokeRequests().EndOfInvokeRequests().GetError()); + ReturnErrorOnFailure(mInvokeRequestMessage.EndOfInvokeRequestMessage().GetError()); + + MoveToState(CommandState::AddedCommand); + + return CHIP_NO_ERROR; +} + +TLV::TLVWriter * CommandSender::GetCommandDataIBTLVWriter() +{ + if (mState != CommandState::AddingCommand) + { + return nullptr; + } + else + { + return mInvokeRequestMessage.GetInvokeRequests().GetCommandData().GetWriter(); + } +} + } // namespace app } // namespace chip diff --git a/src/app/CommandSender.h b/src/app/CommandSender.h index 656f0a4e64333d..a2c4f92928fb12 100644 --- a/src/app/CommandSender.h +++ b/src/app/CommandSender.h @@ -39,8 +39,8 @@ #include #include -#include -#include +#include +#include #define COMMON_STATUS_SUCCESS 0 @@ -118,6 +118,18 @@ class CommandSender final : public Command, public Messaging::ExchangeDelegate */ CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr); + /* + * Allocates a packet buffer used for encoding an invoke request payload. + * + * This can be called multiple times safely, as it will only allocate the buffer once for the lifetime + * of this object. + */ + CHIP_ERROR AllocateBuffer(); + + CHIP_ERROR ProcessInvokeResponse(InvokeResponseIB::Parser & aInvokeResponse); + CHIP_ERROR PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct = true); + CHIP_ERROR FinishCommand(bool aEndDataStruct = true); + TLV::TLVWriter * GetCommandDataIBTLVWriter(); /** * API for adding a data request. The template parameter T is generally * expected to be a ClusterName::Commands::CommandName::Type struct, but any @@ -133,7 +145,7 @@ class CommandSender final : public Command, public Messaging::ExchangeDelegate ReturnErrorOnFailure(PrepareCommand(aCommandPath, /* aStartDataStruct = */ false)); TLV::TLVWriter * writer = GetCommandDataIBTLVWriter(); VerifyOrReturnError(writer != nullptr, CHIP_ERROR_INCORRECT_STATE); - ReturnErrorOnFailure(DataModel::Encode(*writer, TLV::ContextTag(CommandDataIB::kCsTag_Data), aData)); + ReturnErrorOnFailure(DataModel::Encode(*writer, TLV::ContextTag(to_underlying(CommandDataIB::Tag::kData)), aData)); return FinishCommand(/* aEndDataStruct = */ false); } @@ -156,6 +168,7 @@ class CommandSender final : public Command, public Messaging::ExchangeDelegate CHIP_ERROR SendCommandRequest(SessionHandle session, System::Clock::Timeout timeout = kImMessageTimeout); private: + friend class TestCommandInteraction; // ExchangeDelegate interface implementation. Private so people won't // accidentally call it on us when we're not being treated as an actual // ExchangeDelegate. @@ -170,10 +183,14 @@ class CommandSender final : public Command, public Messaging::ExchangeDelegate // void Close(); - CHIP_ERROR ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement) override; + CHIP_ERROR ProcessInvokeResponseMessage(System::PacketBufferHandle && payload); Callback * mpCallback = nullptr; Messaging::ExchangeManager * mpExchangeMgr = nullptr; + InvokeRequestMessage::Builder mInvokeRequestMessage; + TLV::TLVType mDataElementContainerType = TLV::kTLVType_NotSpecified; + bool mSuppressResponse = false; + bool mTimedRequest = false; }; } // namespace app diff --git a/src/app/InteractionModelEngine.h b/src/app/InteractionModelEngine.h index f236b005292694..7f1fb97efbc558 100644 --- a/src/app/InteractionModelEngine.h +++ b/src/app/InteractionModelEngine.h @@ -39,7 +39,6 @@ #include #include -#include #include #include #include diff --git a/src/app/MessageDef/CommandDataIB.cpp b/src/app/MessageDef/CommandDataIB.cpp index e42fe57ce85bab..98b318e13a297f 100644 --- a/src/app/MessageDef/CommandDataIB.cpp +++ b/src/app/MessageDef/CommandDataIB.cpp @@ -226,9 +226,8 @@ CommandDataIB::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) con CHIP_ERROR CommandDataIB::Parser::CheckSchemaValidity() const { CHIP_ERROR err = CHIP_NO_ERROR; - uint16_t TagPresenceMask = 0; - chip::TLV::TLVReader reader; - uint32_t tagNum = 0; + int TagPresenceMask = 0; + TLV::TLVReader reader; PRETTY_PRINT("CommandDataIB ="); PRETTY_PRINT("{"); @@ -238,54 +237,29 @@ CHIP_ERROR CommandDataIB::Parser::CheckSchemaValidity() const while (CHIP_NO_ERROR == (err = reader.Next())) { - VerifyOrExit(chip::TLV::IsContextTag(reader.GetTag()), err = CHIP_ERROR_INVALID_TLV_TAG); - - tagNum = chip::TLV::TagNumFromTag(reader.GetTag()); + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); switch (tagNum) { - case kCsTag_CommandPath: + case to_underlying(Tag::kPath): // check if this tag has appeared before - VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_CommandPath)), err = CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << kCsTag_CommandPath); - VerifyOrExit(chip::TLV::kTLVType_List == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kPath))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kPath)); { CommandPathIB::Parser path; - err = path.Init(reader); - SuccessOrExit(err); - + ReturnErrorOnFailure(path.Init(reader)); PRETTY_PRINT_INCDEPTH(); - err = path.CheckSchemaValidity(); - SuccessOrExit(err); + ReturnErrorOnFailure(path.CheckSchemaValidity()); PRETTY_PRINT_DECDEPTH(); } break; - case kCsTag_Data: - // check if this tag has appeared before - VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_Data)), err = CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << kCsTag_Data); - - err = ParseData(reader, 0); - SuccessOrExit(err); - break; - case kCsTag_StatusIB: + case to_underlying(Tag::kData): // check if this tag has appeared before - VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_StatusIB)), err = CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << kCsTag_StatusIB); - - { - StatusIB::Parser status; - err = status.Init(reader); - SuccessOrExit(err); - - PRETTY_PRINT_INCDEPTH(); - err = status.CheckSchemaValidity(); - SuccessOrExit(err); - PRETTY_PRINT_DECDEPTH(); - } - + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kData))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kData)); + ReturnErrorOnFailure(ParseData(reader, 0)); break; default: PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); @@ -296,113 +270,67 @@ CHIP_ERROR CommandDataIB::Parser::CheckSchemaValidity() const PRETTY_PRINT("},"); PRETTY_PRINT(""); - // if we have exhausted this container if (CHIP_END_OF_TLV == err) { - // check for at most field: - const uint16_t CheckDataField = 1 << kCsTag_Data; - const uint16_t CheckStatusIBField = 1 << kCsTag_StatusIB; + const int RequiredFields = 1 << to_underlying(Tag::kPath); - if ((TagPresenceMask & CheckDataField) == CheckDataField && (TagPresenceMask & CheckStatusIBField) == CheckStatusIBField) + if ((TagPresenceMask & RequiredFields) == RequiredFields) { - // kCsTag_Data and kCsTag_StatusIB both exist - err = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + err = CHIP_NO_ERROR; } else { - err = CHIP_NO_ERROR; + err = CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE; } } - SuccessOrExit(err); - err = reader.ExitContainer(mOuterContainerType); -exit: - return err; + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; } #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK -CHIP_ERROR CommandDataIB::Parser::GetCommandPath(CommandPathIB::Parser * const apCommandPath) const +CHIP_ERROR CommandDataIB::Parser::GetPath(CommandPathIB::Parser * const apPath) const { - CHIP_ERROR err = CHIP_NO_ERROR; - chip::TLV::TLVReader reader; - - err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_CommandPath), reader); - SuccessOrExit(err); - - VerifyOrExit(chip::TLV::kTLVType_List == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - err = apCommandPath->Init(reader); - SuccessOrExit(err); - -exit: - ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err)); - return err; + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kPath)), reader)); + ReturnErrorOnFailure(apPath->Init(reader)); + return CHIP_NO_ERROR; } -CHIP_ERROR CommandDataIB::Parser::GetData(chip::TLV::TLVReader * const apReader) const +CHIP_ERROR CommandDataIB::Parser::GetData(TLV::TLVReader * const apReader) const { - CHIP_ERROR err = CHIP_NO_ERROR; - - err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_Data), *apReader); - SuccessOrExit(err); - -exit: - ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err)); - - return err; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kData)), *apReader)); + return CHIP_NO_ERROR; } -CHIP_ERROR CommandDataIB::Parser::GetStatusIB(StatusIB::Parser * const apStatusIB) const +CHIP_ERROR CommandDataIB::Builder::_Init(TLV::TLVWriter * const apWriter, const TLV::Tag aTag) { - CHIP_ERROR err = CHIP_NO_ERROR; - chip::TLV::TLVReader reader; - - err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_StatusIB), reader); - SuccessOrExit(err); - - err = apStatusIB->Init(reader); - SuccessOrExit(err); - -exit: - ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err)); - - return err; + mpWriter = apWriter; + mError = mpWriter->StartContainer(aTag, TLV::kTLVType_Structure, mOuterContainerType); + ReturnErrorOnFailure(mError); + return mError; } - -CHIP_ERROR CommandDataIB::Builder::Init(chip::TLV::TLVWriter * const apWriter) +CHIP_ERROR CommandDataIB::Builder::Init(TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse) { - return InitAnonymousStructure(apWriter); + return _Init(apWriter, TLV::ContextTag(aContextTagToUse)); } -CommandPathIB::Builder & CommandDataIB::Builder::CreateCommandPathBuilder() +CHIP_ERROR CommandDataIB::Builder::Init(chip::TLV::TLVWriter * const apWriter) { - // skip if error has already been set - VerifyOrExit(CHIP_NO_ERROR == mError, mCommandPathBuilder.ResetError(mError)); - - mError = mCommandPathBuilder.Init(mpWriter, kCsTag_CommandPath); - -exit: - // on error, mAttributePathBuilder would be un-/partial initialized and cannot be used to write anything - return mCommandPathBuilder; + return _Init(apWriter, TLV::AnonymousTag); } -StatusIB::Builder & CommandDataIB::Builder::CreateStatusIBBuilder() +CommandPathIB::Builder & CommandDataIB::Builder::CreatePath() { - // skip if error has already been set - VerifyOrExit(CHIP_NO_ERROR == mError, mStatusIBBuilder.ResetError(mError)); - - mError = mStatusIBBuilder.Init(mpWriter, kCsTag_StatusIB); - -exit: - // on error, mStatusIBBuilder would be un-/partial initialized and cannot be used to write anything - return mStatusIBBuilder; + mError = mPath.Init(mpWriter, to_underlying(Tag::kPath)); + return mPath; } CommandDataIB::Builder & CommandDataIB::Builder::EndOfCommandDataIB() { EndOfContainer(); - return *this; } }; // namespace app diff --git a/src/app/MessageDef/CommandDataIB.h b/src/app/MessageDef/CommandDataIB.h index f3175caef54b16..3d441d7833d700 100644 --- a/src/app/MessageDef/CommandDataIB.h +++ b/src/app/MessageDef/CommandDataIB.h @@ -39,11 +39,10 @@ namespace chip { namespace app { namespace CommandDataIB { -enum +enum class Tag : uint8_t { - kCsTag_CommandPath = 0, - kCsTag_Data = 1, - kCsTag_StatusIB = 2, + kPath = 0, + kData = 1, }; class Parser : public chip::app::Parser @@ -78,13 +77,13 @@ class Parser : public chip::app::Parser /** * @brief Get a TLVReader for the CommandPathIB. Next() must be called before accessing them. * - * @param [in] apCommandPath A pointer to apCommandPath + * @param [in] apPath A pointer to apCommandPath * * @return #CHIP_NO_ERROR on success * #CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not a Path * #CHIP_END_OF_TLV if there is no such element */ - CHIP_ERROR GetCommandPath(CommandPathIB::Parser * const apCommandPath) const; + CHIP_ERROR GetPath(CommandPathIB::Parser * const apPath) const; /** * @brief Get a TLVReader for the Data. Next() must be called before accessing them. @@ -96,17 +95,6 @@ class Parser : public chip::app::Parser */ CHIP_ERROR GetData(chip::TLV::TLVReader * const apReader) const; - /** - * @brief Get a TLVReader for the StatusIB. Next() must be called before accessing them. - * - * @param [in] apStatusIB A pointer to apStatusIB - * - * @return #CHIP_NO_ERROR on success - * # CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not a structure - * #CHIP_END_OF_TLV if there is no such element - */ - CHIP_ERROR GetStatusIB(StatusIB::Parser * const apStatusIB) const; - protected: // A recursively callable function to parse a data element and pretty-print it. CHIP_ERROR ParseData(chip::TLV::TLVReader & aReader, int aDepth) const; @@ -116,7 +104,7 @@ class Builder : public chip::app::Builder { public: /** - * @brief Initialize a AttributeDataList::Builder for writing into a TLV stream + * @brief Initialize a CommandDataIB::Builder for writing into a TLV stream * * @param [in] apWriter A pointer to TLVWriter * @@ -125,18 +113,21 @@ class Builder : public chip::app::Builder CHIP_ERROR Init(chip::TLV::TLVWriter * const apWriter); /** - * @brief Initialize a CommandPathIB::Builder for writing into the TLV stream + * Init the AttributeDataIB container with an particular context tag. * - * @return A reference to CommandPathIB::Builder + * @param[in] apWriter Pointer to the TLVWriter that is encoding the message. + * @param[in] aContextTagToUse A contextTag to use. + * + * @return CHIP_ERROR codes returned by chip::TLV objects. */ - CommandPathIB::Builder & CreateCommandPathBuilder(); + CHIP_ERROR Init(chip::TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse); /** - * @brief Initialize a StatusIB::Builder for writing into the TLV stream + * @brief Initialize a CommandPathIB::Builder for writing into the TLV stream * - * @return A reference to StatusIB::Builder + * @return A reference to CommandPathIB::Builder */ - StatusIB::Builder & CreateStatusIBBuilder(); + CommandPathIB::Builder & CreatePath(); /** * @brief Mark the end of this CommandDataIB @@ -146,8 +137,9 @@ class Builder : public chip::app::Builder CommandDataIB::Builder & EndOfCommandDataIB(); private: - CommandPathIB::Builder mCommandPathBuilder; - StatusIB::Builder mStatusIBBuilder; + CHIP_ERROR _Init(TLV::TLVWriter * const apWriter, const TLV::Tag aTag); + + CommandPathIB::Builder mPath; }; }; // namespace CommandDataIB }; // namespace app diff --git a/src/app/MessageDef/CommandPathIB.cpp b/src/app/MessageDef/CommandPathIB.cpp index 70ae23be0f066e..415773db3ec91c 100644 --- a/src/app/MessageDef/CommandPathIB.cpp +++ b/src/app/MessageDef/CommandPathIB.cpp @@ -56,7 +56,7 @@ CHIP_ERROR CommandPathIB::Parser::Init(const chip::TLV::TLVReader & aReader) CHIP_ERROR CommandPathIB::Parser::CheckSchemaValidity() const { CHIP_ERROR err = CHIP_NO_ERROR; - uint16_t TagPresenceMask = 0; + int TagPresenceMask = 0; chip::TLV::TLVReader reader; PRETTY_PRINT("CommandPathIB ="); PRETTY_PRINT("{"); @@ -204,7 +204,7 @@ CommandPathIB::Builder & CommandPathIB::Builder::CommandId(const chip::CommandId return *this; } -CommandPathIB::Builder & CommandPathIB::Builder::EndOfCommandPath() +CommandPathIB::Builder & CommandPathIB::Builder::EndOfCommandPathIB() { EndOfContainer(); return *this; diff --git a/src/app/MessageDef/CommandPathIB.h b/src/app/MessageDef/CommandPathIB.h index 0867c91f757e65..7de6c549fa7323 100644 --- a/src/app/MessageDef/CommandPathIB.h +++ b/src/app/MessageDef/CommandPathIB.h @@ -161,7 +161,7 @@ class Builder : public chip::app::Builder * * @return A reference to *this */ - CommandPathIB::Builder & EndOfCommandPath(); + CommandPathIB::Builder & EndOfCommandPathIB(); private: CHIP_ERROR _Init(TLV::TLVWriter * const apWriter, const TLV::Tag aTag); diff --git a/src/app/MessageDef/CommandStatusIB.cpp b/src/app/MessageDef/CommandStatusIB.cpp new file mode 100644 index 00000000000000..c31e6ee33efd17 --- /dev/null +++ b/src/app/MessageDef/CommandStatusIB.cpp @@ -0,0 +1,173 @@ +/** + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2018 Google LLC. + * Copyright (c) 2016-2017 Nest Labs, Inc. + * 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. + */ +/** + * @file + * This file defines CommandStatusIB parser and builder in CHIP interaction model + * + */ + +#include "CommandStatusIB.h" + +#include "MessageDefHelper.h" + +#include +#include +#include + +#include + +using namespace chip; +using namespace chip::TLV; + +namespace chip { +namespace app { +CHIP_ERROR CommandStatusIB::Parser::Init(const chip::TLV::TLVReader & aReader) +{ + mReader.Init(aReader); + VerifyOrReturnError(chip::TLV::kTLVType_Structure == mReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(mReader.EnterContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR CommandStatusIB::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int TagPresenceMask = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("CommandStatusIB ="); + PRETTY_PRINT("{"); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); + switch (tagNum) + { + case to_underlying(Tag::kPath): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kPath))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kPath)); + { + CommandPathIB::Parser path; + ReturnErrorOnFailure(path.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(path.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + case to_underlying(Tag::kErrorStatus): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kErrorStatus))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kErrorStatus)); + { + StatusIB::Parser errorStatus; + ReturnErrorOnFailure(errorStatus.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(errorStatus.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + default: + PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); + break; + } + } + + PRETTY_PRINT("},"); + PRETTY_PRINT(""); + + if (CHIP_END_OF_TLV == err) + { + const int RequiredFields = (1 << to_underlying(Tag::kPath)) | (1 << to_underlying(Tag::kErrorStatus)); + + if ((TagPresenceMask & RequiredFields) == RequiredFields) + { + err = CHIP_NO_ERROR; + } + else + { + err = CHIP_ERROR_IM_MALFORMED_COMMAND_STATUS_IB; + } + } + + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CHIP_ERROR CommandStatusIB::Parser::GetPath(CommandPathIB::Parser * const apPath) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kPath)), reader)); + ReturnErrorOnFailure(apPath->Init(reader)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommandStatusIB::Parser::GetErrorStatus(StatusIB::Parser * const apErrorStatus) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kErrorStatus)), reader)); + ReturnErrorOnFailure(apErrorStatus->Init(reader)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommandStatusIB::Builder::_Init(TLV::TLVWriter * const apWriter, const TLV::Tag aTag) +{ + mpWriter = apWriter; + mError = mpWriter->StartContainer(aTag, TLV::kTLVType_Structure, mOuterContainerType); + ReturnErrorOnFailure(mError); + return mError; +} + +CHIP_ERROR CommandStatusIB::Builder::Init(TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse) +{ + return _Init(apWriter, TLV::ContextTag(aContextTagToUse)); +} + +CHIP_ERROR CommandStatusIB::Builder::Init(chip::TLV::TLVWriter * const apWriter) +{ + return _Init(apWriter, TLV::AnonymousTag); +} + +CommandPathIB::Builder & CommandStatusIB::Builder::CreatePath() +{ + mError = mPath.Init(mpWriter, to_underlying(Tag::kPath)); + return mPath; +} + +StatusIB::Builder & CommandStatusIB::Builder::CreateErrorStatus() +{ + mError = mErrorStatus.Init(mpWriter, to_underlying(Tag::kErrorStatus)); + return mErrorStatus; +} + +CommandStatusIB::Builder & CommandStatusIB::Builder::EndOfCommandStatusIB() +{ + EndOfContainer(); + return *this; +} +}; // namespace app +}; // namespace chip diff --git a/src/app/MessageDef/CommandStatusIB.h b/src/app/MessageDef/CommandStatusIB.h new file mode 100644 index 00000000000000..1fe9509aa7a482 --- /dev/null +++ b/src/app/MessageDef/CommandStatusIB.h @@ -0,0 +1,151 @@ +/** + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2016-2017 Nest Labs, Inc. + * + * 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. + */ +/** + * @file + * This file defines CommandDataElement parser and builder in CHIP interaction model + * + */ + +#pragma once + +#include "Builder.h" +#include "CommandPathIB.h" + +#include "Parser.h" +#include "StatusIB.h" + +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace CommandStatusIB { +enum class Tag : uint8_t +{ + kPath = 0, + kErrorStatus = 1, +}; + +class Parser : public chip::app::Parser +{ +public: + /** + * @brief Initialize the parser object with TLVReader + * + * @param [in] aReader A pointer to a TLVReader, which should point to the beginning of this CommandStatusIB + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR Init(const TLV::TLVReader & aReader); + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + /** + * @brief Roughly verify the message is correctly formed + * 1) all mandatory tags are present + * 2) all elements have expected data type + * 3) any tag can only appear once + * 4) At the top level of the structure, unknown tags are ignored for forward compatibility + * @note The main use of this function is to print out what we're + * receiving during protocol development and debugging. + * The encoding rule has changed in IM encoding spec so this + * check is only "roughly" conformant now. + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR CheckSchemaValidity() const; +#endif + + /** + * @brief Get a TLVReader for the CommandPathIB. Next() must be called before accessing them. + * + * @param [in] apPath A pointer to apPath + * + * @return #CHIP_NO_ERROR on success + * #CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not a Path + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetPath(CommandPathIB::Parser * const apPath) const; + + /** + * @brief Get a TLVReader for the StatusIB. Next() must be called before accessing them. + * + * @param [in] apErrorStatus A pointer to apErrorStatus + * + * @return #CHIP_NO_ERROR on success + * # CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not a structure + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetErrorStatus(StatusIB::Parser * const apErrorStatus) const; +}; + +class Builder : public chip::app::Builder +{ +public: + /** + * @brief Initialize a CommandStatusIB::Builder for writing into a TLV stream + * + * @param [in] apWriter A pointer to TLVWriter + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR Init(chip::TLV::TLVWriter * const apWriter); + + /** + * Init the CommandStatusIB container with an particular context tag.. + * + * @param[in] apWriter Pointer to the TLVWriter that is encoding the message. + * @param[in] aContextTagToUse A contextTag to use. + * + * @return CHIP_ERROR codes returned by chip::TLV objects. + */ + CHIP_ERROR Init(chip::TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse); + + /** + * @brief Initialize a CommandPathIB::Builder for writing into the TLV stream + * + * @return A reference to CommandPathIB::Builder + */ + CommandPathIB::Builder & CreatePath(); + + /** + * @brief Initialize a StatusIB::Builder for writing into the TLV stream + * + * @return A reference to StatusIB::Builder + */ + StatusIB::Builder & CreateErrorStatus(); + + /** + * @brief Mark the end of this CommandStatusIB + * + * @return A reference to *this + */ + CommandStatusIB::Builder & EndOfCommandStatusIB(); + +private: + CHIP_ERROR _Init(TLV::TLVWriter * const apWriter, const TLV::Tag aTag); + + CommandPathIB::Builder mPath; + StatusIB::Builder mErrorStatus; +}; +}; // namespace CommandStatusIB +}; // namespace app +}; // namespace chip diff --git a/src/app/MessageDef/InvokeCommand.cpp b/src/app/MessageDef/InvokeCommand.cpp deleted file mode 100644 index 03213c71caa853..00000000000000 --- a/src/app/MessageDef/InvokeCommand.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/** - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Google LLC. - * Copyright (c) 2016-2017 Nest Labs, Inc. - * 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. - */ -/** - * @file - * This file defines InvokeCommand parser and builder in CHIP interaction model - * - */ - -#include -#include -#include - -#include "InvokeCommand.h" -#include "MessageDefHelper.h" - -#include - -using namespace chip; -using namespace chip::TLV; - -namespace chip { -namespace app { -CHIP_ERROR InvokeCommand::Parser::Init(const chip::TLV::TLVReader & aReader) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - // make a copy of the reader here - mReader.Init(aReader); - - VerifyOrExit(chip::TLV::kTLVType_Structure == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - err = mReader.EnterContainer(mOuterContainerType); - -exit: - - return err; -} - -#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK -CHIP_ERROR InvokeCommand::Parser::CheckSchemaValidity() const -{ - CHIP_ERROR err = CHIP_NO_ERROR; - uint16_t TagPresenceMask = 0; - chip::TLV::TLVReader reader; - CommandList::Parser commandList; - - PRETTY_PRINT("InvokeCommand ="); - PRETTY_PRINT("{"); - - // make a copy of the reader - reader.Init(mReader); - - while (CHIP_NO_ERROR == (err = reader.Next())) - { - const Tag tag = reader.GetTag(); - - if (chip::TLV::ContextTag(kCsTag_CommandList) == tag) - { - VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_CommandList)), err = CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << kCsTag_CommandList); - VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - commandList.Init(reader); - - PRETTY_PRINT_INCDEPTH(); - - err = commandList.CheckSchemaValidity(); - SuccessOrExit(err); - - PRETTY_PRINT_DECDEPTH(); - } - else - { - PRETTY_PRINT("\tUnknown tag 0x%" PRIx64, tag); - } - } - - PRETTY_PRINT("}"); - PRETTY_PRINT(""); - - // if we have exhausted this container - if (CHIP_END_OF_TLV == err) - { - // if we have at least the DataList or EventList field - if ((TagPresenceMask & (1 << kCsTag_CommandList))) - { - err = CHIP_NO_ERROR; - } - } - SuccessOrExit(err); - err = reader.ExitContainer(mOuterContainerType); - -exit: - - return err; -} -#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - -CHIP_ERROR InvokeCommand::Parser::GetCommandList(CommandList::Parser * const apCommandList) const -{ - CHIP_ERROR err = CHIP_NO_ERROR; - chip::TLV::TLVReader reader; - - err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_CommandList), reader); - SuccessOrExit(err); - - VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - - err = apCommandList->Init(reader); - SuccessOrExit(err); - -exit: - ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err)); - - return err; -} - -CHIP_ERROR InvokeCommand::Builder::Init(chip::TLV::TLVWriter * const apWriter) -{ - return InitAnonymousStructure(apWriter); -} - -CommandList::Builder & InvokeCommand::Builder::CreateCommandListBuilder() -{ - // skip if error has already been set - VerifyOrExit(CHIP_NO_ERROR == mError, mCommandListBuilder.ResetError(mError)); - - mError = mCommandListBuilder.Init(mpWriter, kCsTag_CommandList); - -exit: - // on error, mCommandListBuilder would be un-/partial initialized and cannot be used to write anything - return mCommandListBuilder; -} - -CommandList::Builder & InvokeCommand::Builder::GetCommandListBuilder() -{ - return mCommandListBuilder; -} - -InvokeCommand::Builder & InvokeCommand::Builder::EndOfInvokeCommand() -{ - EndOfContainer(); - return *this; -} -}; // namespace app -}; // namespace chip diff --git a/src/app/MessageDef/InvokeRequestMessage.cpp b/src/app/MessageDef/InvokeRequestMessage.cpp new file mode 100644 index 00000000000000..f3dc82b24415f2 --- /dev/null +++ b/src/app/MessageDef/InvokeRequestMessage.cpp @@ -0,0 +1,184 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * 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. + */ +/** + * @file + * This file defines InvokeRequestMessage parser and builder in CHIP interaction model + * + */ + +#include +#include +#include + +#include "InvokeRequestMessage.h" +#include "MessageDefHelper.h" + +#include + +using namespace chip; +using namespace chip::TLV; + +namespace chip { +namespace app { +CHIP_ERROR InvokeRequestMessage::Parser::Init(const chip::TLV::TLVReader & aReader) +{ + mReader.Init(aReader); + VerifyOrReturnError(chip::TLV::kTLVType_Structure == mReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(mReader.EnterContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR InvokeRequestMessage::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int TagPresenceMask = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("InvokeRequestMessage ="); + PRETTY_PRINT("{"); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); + switch (tagNum) + { + case to_underlying(Tag::kSuppressResponse): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kSuppressResponse))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kSuppressResponse)); +#if CHIP_DETAIL_LOGGING + { + bool suppressResponse; + ReturnLogErrorOnFailure(reader.Get(suppressResponse)); + PRETTY_PRINT("\tsuppressResponse = %s, ", suppressResponse ? "true" : "false"); + } +#endif // CHIP_DETAIL_LOGGING + break; + + case to_underlying(Tag::kTimedRequest): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kTimedRequest))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kTimedRequest)); +#if CHIP_DETAIL_LOGGING + { + bool timedRequest; + ReturnLogErrorOnFailure(reader.Get(timedRequest)); + PRETTY_PRINT("\ttimedRequest = %s, ", timedRequest ? "true" : "false"); + } +#endif // CHIP_DETAIL_LOGGING + break; + case to_underlying(Tag::kInvokeRequests): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kInvokeRequests))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kInvokeRequests)); + { + InvokeRequests::Parser invokeRequests; + ReturnErrorOnFailure(invokeRequests.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(invokeRequests.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + default: + PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); + break; + } + } + + PRETTY_PRINT("},"); + PRETTY_PRINT(""); + + if (CHIP_END_OF_TLV == err) + { + const int RequiredFields = (1 << to_underlying(Tag::kSuppressResponse)) | (1 << to_underlying(Tag::kTimedRequest)) | + (1 << to_underlying(Tag::kInvokeRequests)); + + if ((TagPresenceMask & RequiredFields) == RequiredFields) + { + err = CHIP_NO_ERROR; + } + else + { + err = CHIP_ERROR_IM_MALFORMED_INVOKE_REQUEST_MESSAGE; + } + } + + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CHIP_ERROR InvokeRequestMessage::Parser::GetSuppressResponse(bool * const apSuppressResponse) const +{ + return GetSimpleValue(to_underlying(Tag::kSuppressResponse), TLV::kTLVType_Boolean, apSuppressResponse); +} + +CHIP_ERROR InvokeRequestMessage::Parser::GetTimedRequest(bool * const apTimedRequest) const +{ + return GetSimpleValue(to_underlying(Tag::kSuppressResponse), TLV::kTLVType_Boolean, apTimedRequest); +} + +CHIP_ERROR InvokeRequestMessage::Parser::GetInvokeRequests(InvokeRequests::Parser * const apInvokeRequests) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kInvokeRequests)), reader)); + ReturnErrorOnFailure(apInvokeRequests->Init(reader)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR InvokeRequestMessage::Builder::Init(chip::TLV::TLVWriter * const apWriter) +{ + return InitAnonymousStructure(apWriter); +} + +InvokeRequestMessage::Builder & InvokeRequestMessage::Builder::SuppressResponse(const bool aSuppressResponse) +{ + if (mError == CHIP_NO_ERROR) + { + mError = mpWriter->PutBoolean(TLV::ContextTag(to_underlying(Tag::kSuppressResponse)), aSuppressResponse); + } + return *this; +} + +InvokeRequestMessage::Builder & InvokeRequestMessage::Builder::TimedRequest(const bool aTimedRequest) +{ + if (mError == CHIP_NO_ERROR) + { + mError = mpWriter->PutBoolean(TLV::ContextTag(to_underlying(Tag::kTimedRequest)), aTimedRequest); + } + return *this; +} + +InvokeRequests::Builder & InvokeRequestMessage::Builder::CreateInvokeRequests() +{ + mError = mInvokeRequests.Init(mpWriter, to_underlying(Tag::kInvokeRequests)); + return mInvokeRequests; +} + +InvokeRequestMessage::Builder & InvokeRequestMessage::Builder::EndOfInvokeRequestMessage() +{ + EndOfContainer(); + return *this; +} +}; // namespace app +}; // namespace chip diff --git a/src/app/MessageDef/InvokeRequestMessage.h b/src/app/MessageDef/InvokeRequestMessage.h new file mode 100644 index 00000000000000..3671fa7117ed22 --- /dev/null +++ b/src/app/MessageDef/InvokeRequestMessage.h @@ -0,0 +1,151 @@ +/** + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2016-2017 Nest Labs, Inc. + * + * 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. + */ +/** + * @file + * This file defines InvokeCommand parser and builder in CHIP interaction model + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "Builder.h" +#include "InvokeRequests.h" +#include "Parser.h" + +namespace chip { +namespace app { +namespace InvokeRequestMessage { +enum class Tag : uint8_t +{ + kSuppressResponse = 0, + kTimedRequest = 1, + kInvokeRequests = 2, +}; + +class Parser : public chip::app::Parser +{ +public: + /** + * @brief Initialize the parser object with TLVReader + * + * @param [in] aReader A pointer to a TLVReader, which should point to the beginning of this request + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR Init(const chip::TLV::TLVReader & aReader); + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + /** + * @brief Roughly verify the message is correctly formed + * 1) all mandatory tags are present + * 2) all elements have expected data type + * 3) any tag can only appear once + * 4) At the top level of the structure, unknown tags are ignored for forward compatibility + * @note The main use of this function is to print out what we're + * receiving during protocol development and debugging. + * The encoding rule has changed in IM encoding spec so this + * check is only "roughly" conformant now. + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR CheckSchemaValidity() const; +#endif + + /** + * @brief Get SuppressResponse. Next() must be called before accessing them. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetSuppressResponse(bool * const apSuppressResponse) const; + + /** + * @brief Get TimedRequest. Next() must be called before accessing them. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetTimedRequest(bool * const apTimedRequest) const; + + /** + * @brief Get a parser for a InvokeRequest. + * + * @param [in] apInvokeRequests A pointer to the invoke response list parser. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetInvokeRequests(InvokeRequests::Parser * const apInvokeRequests) const; +}; + +class Builder : public chip::app::Builder +{ +public: + /** + * @brief Initialize a InvokeCommand::Builder for writing into a TLV stream + * + * @param [in] apWriter A pointer to TLVWriter + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR Init(chip::TLV::TLVWriter * const apWriter); + + /** + * @brief when sets to true, it means do not send a response to this action + */ + InvokeRequestMessage::Builder & SuppressResponse(const bool aSuppressResponse); + + /** + * @brief This is flag to indication if ths action is part of a timed invoke transaction + */ + InvokeRequestMessage::Builder & TimedRequest(const bool aTimedRequest); + + /** + * @brief Initialize a InvokeRequests::Builder for writing into the TLV stream + * + * @return A reference to InvokeRequests::Builder + */ + InvokeRequests::Builder & CreateInvokeRequests(); + + /** + * @brief Get reference to InvokeRequests::Builder + * + * @return A reference to InvokeRequests::Builder + */ + InvokeRequests::Builder & GetInvokeRequests() { return mInvokeRequests; } + + /** + * @brief Mark the end of this InvokeCommand + * + * @return A reference to *this + */ + InvokeRequestMessage::Builder & EndOfInvokeRequestMessage(); + +private: + InvokeRequests::Builder mInvokeRequests; +}; +}; // namespace InvokeRequestMessage +}; // namespace app +}; // namespace chip diff --git a/src/app/MessageDef/CommandList.cpp b/src/app/MessageDef/InvokeRequests.cpp similarity index 57% rename from src/app/MessageDef/CommandList.cpp rename to src/app/MessageDef/InvokeRequests.cpp index 73f33c41f4f55a..6c296cf4b31176 100644 --- a/src/app/MessageDef/CommandList.cpp +++ b/src/app/MessageDef/InvokeRequests.cpp @@ -21,7 +21,7 @@ * */ -#include "CommandList.h" +#include "InvokeRequests.h" #include "MessageDefHelper.h" @@ -37,13 +37,13 @@ using namespace chip::TLV; namespace chip { namespace app { #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK -CHIP_ERROR CommandList::Parser::CheckSchemaValidity() const +CHIP_ERROR InvokeRequests::Parser::CheckSchemaValidity() const { - CHIP_ERROR err = CHIP_NO_ERROR; - size_t NumCommands = 0; - chip::TLV::TLVReader reader; + CHIP_ERROR err = CHIP_NO_ERROR; + size_t numCommandDatas = 0; + TLV::TLVReader reader; - PRETTY_PRINT("CommandList ="); + PRETTY_PRINT("InvokeRequests ="); PRETTY_PRINT("["); // make a copy of the reader @@ -51,22 +51,16 @@ CHIP_ERROR CommandList::Parser::CheckSchemaValidity() const while (CHIP_NO_ERROR == (err = reader.Next())) { - VerifyOrExit(chip::TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG); - VerifyOrExit(chip::TLV::kTLVType_Structure == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - + VerifyOrReturnError(TLV::AnonymousTag == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG); { - CommandDataIB::Parser data; - err = data.Init(reader); - SuccessOrExit(err); - + CommandDataIB::Parser commandData; + ReturnErrorOnFailure(commandData.Init(reader)); PRETTY_PRINT_INCDEPTH(); - err = data.CheckSchemaValidity(); - SuccessOrExit(err); - + ReturnErrorOnFailure(commandData.CheckSchemaValidity()); PRETTY_PRINT_DECDEPTH(); } - ++NumCommands; + ++numCommandDatas; } PRETTY_PRINT("],"); @@ -76,33 +70,24 @@ CHIP_ERROR CommandList::Parser::CheckSchemaValidity() const if (CHIP_END_OF_TLV == err) { // if we have at least one data element - if (NumCommands > 0) + if (numCommandDatas > 0) { err = CHIP_NO_ERROR; } } - SuccessOrExit(err); - err = reader.ExitContainer(mOuterContainerType); - -exit: - - return err; + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; } #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK -CommandDataIB::Builder & CommandList::Builder::CreateCommandDataIBBuilder() +CommandDataIB::Builder & InvokeRequests::Builder::CreateCommandData() { - // skip if error has already been set - VerifyOrExit(CHIP_NO_ERROR == mError, mCommandDataIBBuilder.ResetError(mError)); - - mError = mCommandDataIBBuilder.Init(mpWriter); - -exit: - // on error, mCommandDataIBBuilder would be un-/partial initialized and cannot be used to write anything - return mCommandDataIBBuilder; + mError = mCommandData.Init(mpWriter); + return mCommandData; } -CommandList::Builder & CommandList::Builder::EndOfCommandList() +InvokeRequests::Builder & InvokeRequests::Builder::EndOfInvokeRequests() { EndOfContainer(); return *this; diff --git a/src/app/MessageDef/CommandList.h b/src/app/MessageDef/InvokeRequests.h similarity index 86% rename from src/app/MessageDef/CommandList.h rename to src/app/MessageDef/InvokeRequests.h index 3422ffe43eccde..a6501cd45e458f 100644 --- a/src/app/MessageDef/CommandList.h +++ b/src/app/MessageDef/InvokeRequests.h @@ -23,10 +23,6 @@ #pragma once -#include "CommandDataIB.h" -#include "ListBuilder.h" -#include "ListParser.h" - #include #include #include @@ -34,9 +30,13 @@ #include #include +#include "CommandDataIB.h" +#include "ListBuilder.h" +#include "ListParser.h" + namespace chip { namespace app { -namespace CommandList { +namespace InvokeRequests { class Parser : public ListParser { public: @@ -66,23 +66,23 @@ class Builder : public ListBuilder * * @return A reference to CommandDataIB::Builder */ - CommandDataIB::Builder & CreateCommandDataIBBuilder(); + CommandDataIB::Builder & CreateCommandData(); /** * @return A reference to CommandDataIB::Builder */ - CommandDataIB::Builder & GetCommandDataIBBuilder() { return mCommandDataIBBuilder; }; + CommandDataIB::Builder & GetCommandData() { return mCommandData; }; /** - * @brief Mark the end of this CommandList + * @brief Mark the end of this InvokeRequests * * @return A reference to *this */ - CommandList::Builder & EndOfCommandList(); + InvokeRequests::Builder & EndOfInvokeRequests(); private: - CommandDataIB::Builder mCommandDataIBBuilder; + CommandDataIB::Builder mCommandData; }; -}; // namespace CommandList +}; // namespace InvokeRequests }; // namespace app }; // namespace chip diff --git a/src/app/MessageDef/InvokeResponseIB.cpp b/src/app/MessageDef/InvokeResponseIB.cpp new file mode 100644 index 00000000000000..e16842d5eafdd0 --- /dev/null +++ b/src/app/MessageDef/InvokeResponseIB.cpp @@ -0,0 +1,166 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * 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. + */ +/** + * @file + * This file defines InvokeResponse parser and builder in CHIP interaction model + * + */ + +#include +#include +#include + +#include "InvokeResponseIB.h" +#include "MessageDefHelper.h" + +#include + +using namespace chip; +using namespace chip::TLV; + +namespace chip { +namespace app { +CHIP_ERROR InvokeResponseIB::Parser::Init(const chip::TLV::TLVReader & aReader) +{ + mReader.Init(aReader); + VerifyOrReturnError(chip::TLV::kTLVType_Structure == mReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(mReader.EnterContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR InvokeResponseIB::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int TagPresenceMask = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("InvokeResponseIB ="); + PRETTY_PRINT("{"); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); + switch (tagNum) + { + case to_underlying(Tag::kCommand): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kCommand))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kCommand)); + { + CommandDataIB::Parser command; + ReturnErrorOnFailure(command.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(command.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + case to_underlying(Tag::kStatus): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kStatus))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kStatus)); + { + CommandStatusIB::Parser status; + ReturnErrorOnFailure(status.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(status.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + default: + PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); + break; + } + } + + PRETTY_PRINT("},"); + PRETTY_PRINT(""); + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + // check for at most field: + const int CheckCommandField = 1 << to_underlying(Tag::kCommand); + const int CheckStatusField = (1 << to_underlying(Tag::kStatus)); + + if ((TagPresenceMask & CheckCommandField) == CheckCommandField && (TagPresenceMask & CheckStatusField) == CheckStatusField) + { + // kPath and kErrorStatus both exist + err = CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_IB; + } + else if ((TagPresenceMask & CheckCommandField) != CheckCommandField && + (TagPresenceMask & CheckStatusField) != CheckStatusField) + { + // kPath and kErrorStatus not exist + err = CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_IB; + } + else + { + err = CHIP_NO_ERROR; + } + } + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CHIP_ERROR InvokeResponseIB::Parser::GetCommand(CommandDataIB::Parser * const apCommand) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kCommand)), reader)); + ReturnErrorOnFailure(apCommand->Init(reader)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR InvokeResponseIB::Parser::GetStatus(CommandStatusIB::Parser * const apStatus) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kStatus)), reader)); + ReturnErrorOnFailure(apStatus->Init(reader)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR InvokeResponseIB::Builder::Init(chip::TLV::TLVWriter * const apWriter) +{ + return InitAnonymousStructure(apWriter); +} + +CommandDataIB::Builder & InvokeResponseIB::Builder::CreateCommand() +{ + mError = mCommand.Init(mpWriter, to_underlying(Tag::kCommand)); + return mCommand; +} + +CommandStatusIB::Builder & InvokeResponseIB::Builder::CreateStatus() +{ + mError = mStatus.Init(mpWriter, to_underlying(Tag::kStatus)); + return mStatus; +} + +InvokeResponseIB::Builder & InvokeResponseIB::Builder::EndOfInvokeResponseIB() +{ + EndOfContainer(); + return *this; +} +}; // namespace app +}; // namespace chip diff --git a/src/app/MessageDef/InvokeResponseIB.h b/src/app/MessageDef/InvokeResponseIB.h new file mode 100644 index 00000000000000..a804f95fb653ea --- /dev/null +++ b/src/app/MessageDef/InvokeResponseIB.h @@ -0,0 +1,145 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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. + */ +/** + * @file + * This file defines InvokeResponse parser and builder in CHIP interaction model + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "Builder.h" +#include "CommandDataIB.h" +#include "CommandStatusIB.h" +#include "Parser.h" + +namespace chip { +namespace app { +namespace InvokeResponseIB { +enum class Tag : uint8_t +{ + kCommand = 0, + kStatus = 1, +}; + +class Parser : public chip::app::Parser +{ +public: + /** + * @brief Initialize the parser object with TLVReader + * + * @param [in] aReader A pointer to a TLVReader, which should point to the beginning of this request + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR Init(const chip::TLV::TLVReader & aReader); + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + /** + * @brief Roughly verify the message is correctly formed + * 1) all mandatory tags are present + * 2) all elements have expected data type + * 3) any tag can only appear once + * 4) At the top level of the structure, unknown tags are ignored for forward compatibility + * @note The main use of this function is to print out what we're + * receiving during protocol development and debugging. + * The encoding rule has changed in IM encoding spec so this + * check is only "roughly" conformant now. + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR CheckSchemaValidity() const; +#endif + + /** + * @brief Get a parser for a Command. + * + * @param [in] apCommand A pointer to the CommandDataIB parser. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetCommand(CommandDataIB::Parser * const apCommand) const; + + /** + * @brief Get a parser for a Status. + * + * @param [in] apCommand A pointer to the CommandStatusIB parser. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetStatus(CommandStatusIB::Parser * const apStatus) const; +}; + +class Builder : public chip::app::Builder +{ +public: + /** + * @brief Initialize a InvokeResponse::Builder for writing into a TLV stream + * + * @param [in] apWriter A pointer to TLVWriter + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR Init(chip::TLV::TLVWriter * const apWriter); + + /** + * @brief Initialize a CommandDataIB::Builder for writing into the TLV stream + * + * @return A reference to CommandDataIB::Builder + */ + CommandDataIB::Builder & CreateCommand(); + + /** + * @return A reference to CommandDataIB::Builder + */ + CommandDataIB::Builder & GetCommand() { return mCommand; } + + /** + * @return A reference to CommandStatusIB::Builder + */ + CommandStatusIB::Builder & GetStatus() { return mStatus; } + + /** + * @brief Initialize a CommandStatusIB::Builder for writing into the TLV stream + * + * @return A reference to CommandStatusIB::Builder + */ + CommandStatusIB::Builder & CreateStatus(); + + /** + * @brief Mark the end of this InvokeCommand + * + * @return A reference to *this + */ + InvokeResponseIB::Builder & EndOfInvokeResponseIB(); + +private: + CommandDataIB::Builder mCommand; + CommandStatusIB::Builder mStatus; +}; +}; // namespace InvokeResponseIB +}; // namespace app +}; // namespace chip diff --git a/src/app/MessageDef/InvokeResponseMessage.cpp b/src/app/MessageDef/InvokeResponseMessage.cpp new file mode 100644 index 00000000000000..ff722583cfb3a9 --- /dev/null +++ b/src/app/MessageDef/InvokeResponseMessage.cpp @@ -0,0 +1,156 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * 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. + */ +/** + * @file + * This file defines InvokeResponseMessage parser and builder in CHIP interaction model + * + */ + +#include +#include +#include + +#include "InvokeResponseMessage.h" +#include "MessageDefHelper.h" + +#include + +using namespace chip; +using namespace chip::TLV; + +namespace chip { +namespace app { +CHIP_ERROR InvokeResponseMessage::Parser::Init(const chip::TLV::TLVReader & aReader) +{ + mReader.Init(aReader); + VerifyOrReturnError(chip::TLV::kTLVType_Structure == mReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(mReader.EnterContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR InvokeResponseMessage::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int TagPresenceMask = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("InvokeResponseMessage ="); + PRETTY_PRINT("{"); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); + switch (tagNum) + { + case to_underlying(Tag::kSuppressResponse): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kSuppressResponse))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kSuppressResponse)); +#if CHIP_DETAIL_LOGGING + { + bool suppressResponse; + ReturnLogErrorOnFailure(reader.Get(suppressResponse)); + PRETTY_PRINT("\tsuppressResponse = %s, ", suppressResponse ? "true" : "false"); + } +#endif // CHIP_DETAIL_LOGGING + break; + case to_underlying(Tag::kInvokeResponses): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kInvokeResponses))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kInvokeResponses)); + { + InvokeResponses::Parser invokeResponses; + ReturnErrorOnFailure(invokeResponses.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(invokeResponses.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + default: + PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); + break; + } + } + + PRETTY_PRINT("},"); + PRETTY_PRINT(""); + + if (CHIP_END_OF_TLV == err) + { + const int RequiredFields = (1 << to_underlying(Tag::kSuppressResponse)) | (1 << to_underlying(Tag::kInvokeResponses)); + + if ((TagPresenceMask & RequiredFields) == RequiredFields) + { + err = CHIP_NO_ERROR; + } + else + { + err = CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE; + } + } + + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CHIP_ERROR InvokeResponseMessage::Parser::GetSuppressResponse(bool * const apSuppressResponse) const +{ + return GetSimpleValue(to_underlying(Tag::kSuppressResponse), TLV::kTLVType_Boolean, apSuppressResponse); +} + +CHIP_ERROR InvokeResponseMessage::Parser::GetInvokeResponses(InvokeResponses::Parser * const apStatus) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kInvokeResponses)), reader)); + ReturnErrorOnFailure(apStatus->Init(reader)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR InvokeResponseMessage::Builder::Init(chip::TLV::TLVWriter * const apWriter) +{ + return InitAnonymousStructure(apWriter); +} + +InvokeResponseMessage::Builder & InvokeResponseMessage::Builder::SuppressResponse(const bool aSuppressResponse) +{ + if (mError == CHIP_NO_ERROR) + { + mError = mpWriter->PutBoolean(TLV::ContextTag(to_underlying(Tag::kSuppressResponse)), aSuppressResponse); + } + return *this; +} + +InvokeResponses::Builder & InvokeResponseMessage::Builder::CreateInvokeResponses() +{ + mError = mInvokeResponses.Init(mpWriter, to_underlying(Tag::kInvokeResponses)); + return mInvokeResponses; +} + +InvokeResponseMessage::Builder & InvokeResponseMessage::Builder::EndOfInvokeResponseMessage() +{ + EndOfContainer(); + return *this; +} +}; // namespace app +}; // namespace chip diff --git a/src/app/MessageDef/InvokeCommand.h b/src/app/MessageDef/InvokeResponseMessage.h similarity index 65% rename from src/app/MessageDef/InvokeCommand.h rename to src/app/MessageDef/InvokeResponseMessage.h index 763118aab8586f..55b9a425d3346f 100644 --- a/src/app/MessageDef/InvokeCommand.h +++ b/src/app/MessageDef/InvokeResponseMessage.h @@ -31,16 +31,16 @@ #include #include "Builder.h" -#include "CommandDataIB.h" -#include "CommandList.h" +#include "InvokeResponses.h" #include "Parser.h" namespace chip { namespace app { -namespace InvokeCommand { -enum +namespace InvokeResponseMessage { +enum class Tag : uint8_t { - kCsTag_CommandList = 0, + kSuppressResponse = 0, + kInvokeResponses = 1, }; class Parser : public chip::app::Parser @@ -73,14 +73,22 @@ class Parser : public chip::app::Parser #endif /** - * @brief Get a parser for a CommandList. + * @brief Get SuppressResponse. Next() must be called before accessing them. * - * @param [in] apCommandList A pointer to the command list parser. + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetSuppressResponse(bool * const apSuppressResponse) const; + + /** + * @brief Get a parser for a InvokeRequest. + * + * @param [in] apInvokeResponses A pointer to the invoke response list parser. * * @return #CHIP_NO_ERROR on success * #CHIP_END_OF_TLV if there is no such element */ - CHIP_ERROR GetCommandList(CommandList::Parser * const apCommandList) const; + CHIP_ERROR GetInvokeResponses(InvokeResponses::Parser * const apInvokeResponses) const; }; class Builder : public chip::app::Builder @@ -96,29 +104,35 @@ class Builder : public chip::app::Builder CHIP_ERROR Init(chip::TLV::TLVWriter * const apWriter); /** - * @brief Initialize a CommandList::Builder for writing into the TLV stream + * @brief This is set to 'true' by the subscriber to indicate preservation of previous subscriptions. If omitted, it implies + * 'false' as a value. + */ + InvokeResponseMessage::Builder & SuppressResponse(const bool aSuppressResponse); + + /** + * @brief Initialize a InvokeResponses::Builder for writing into the TLV stream * - * @return A reference to CommandList::Builder + * @return A reference to InvokeResponses::Builder */ - CommandList::Builder & CreateCommandListBuilder(); + InvokeResponses::Builder & CreateInvokeResponses(); /** - * @brief Get reference to CommandList::Builder + * @brief Get reference to InvokeResponses::Builder * - * @return A reference to CommandList::Builder + * @return A reference to InvokeResponses::Builder */ - CommandList::Builder & GetCommandListBuilder(); + InvokeResponses::Builder & GetInvokeResponses() { return mInvokeResponses; } /** * @brief Mark the end of this InvokeCommand * * @return A reference to *this */ - InvokeCommand::Builder & EndOfInvokeCommand(); + InvokeResponseMessage::Builder & EndOfInvokeResponseMessage(); private: - CommandList::Builder mCommandListBuilder; + InvokeResponses::Builder mInvokeResponses; }; -}; // namespace InvokeCommand +}; // namespace InvokeResponseMessage }; // namespace app }; // namespace chip diff --git a/src/app/MessageDef/InvokeResponses.cpp b/src/app/MessageDef/InvokeResponses.cpp new file mode 100644 index 00000000000000..3f723d56c66ae6 --- /dev/null +++ b/src/app/MessageDef/InvokeResponses.cpp @@ -0,0 +1,96 @@ +/** + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2018 Google LLC. + * Copyright (c) 2016-2017 Nest Labs, Inc. + * 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. + */ +/** + * @file + * This file defines CommandList parser and builder in CHIP interaction model + * + */ + +#include "InvokeResponses.h" + +#include "MessageDefHelper.h" + +#include +#include +#include + +#include + +using namespace chip; +using namespace chip::TLV; + +namespace chip { +namespace app { +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR InvokeResponses::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + size_t numInvokeResponses = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("InvokeResponses ="); + PRETTY_PRINT("["); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::AnonymousTag == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG); + { + InvokeResponseIB::Parser invokeResponse; + ReturnErrorOnFailure(invokeResponse.Init(reader)); + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(invokeResponse.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + + ++numInvokeResponses; + } + + PRETTY_PRINT("],"); + PRETTY_PRINT(""); + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + // if we have at least one data element + if (numInvokeResponses > 0) + { + err = CHIP_NO_ERROR; + } + } + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(reader.ExitContainer(mOuterContainerType)); + return CHIP_NO_ERROR; +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +InvokeResponseIB::Builder & InvokeResponses::Builder::CreateInvokeResponse() +{ + mError = mInvokeResponse.Init(mpWriter); + return mInvokeResponse; +} + +InvokeResponses::Builder & InvokeResponses::Builder::EndOfInvokeResponses() +{ + EndOfContainer(); + return *this; +} +}; // namespace app +}; // namespace chip diff --git a/src/app/MessageDef/InvokeResponses.h b/src/app/MessageDef/InvokeResponses.h new file mode 100644 index 00000000000000..1ac11d28c95aae --- /dev/null +++ b/src/app/MessageDef/InvokeResponses.h @@ -0,0 +1,88 @@ +/** + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2016-2017 Nest Labs, Inc. + * + * 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. + */ +/** + * @file + * This file defines CommandList parser and builder in CHIP interaction model + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "InvokeResponseIB.h" +#include "ListBuilder.h" +#include "ListParser.h" + +namespace chip { +namespace app { +namespace InvokeResponses { +class Parser : public ListParser +{ +public: +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + /** + * @brief Roughly verify the message is correctly formed + * 1) all mandatory tags are present + * 2) all elements have expected data type + * 3) any tag can only appear once + * 4) At the top level of the structure, unknown tags are ignored for forward compatibility + * @note The main use of this function is to print out what we're + * receiving during protocol development and debugging. + * The encoding rule has changed in IM encoding spec so this + * check is only "roughly" conformant now. + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR CheckSchemaValidity() const; +#endif +}; + +class Builder : public ListBuilder +{ +public: + /** + * @brief Initialize a CommandDataIB::Builder for writing into the TLV stream + * + * @return A reference to InvokeResponseIB::Builder + */ + InvokeResponseIB::Builder & CreateInvokeResponse(); + + /** + * @return A reference to InvokeResponseIB::Builder + */ + InvokeResponseIB::Builder & GetInvokeResponse() { return mInvokeResponse; }; + + /** + * @brief Mark the end of this InvokeResponses + * + * @return A reference to *this + */ + InvokeResponses::Builder & EndOfInvokeResponses(); + +private: + InvokeResponseIB::Builder mInvokeResponse; +}; +}; // namespace InvokeResponses +}; // namespace app +}; // namespace chip diff --git a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp index 1f3816a7ba9cb0..b86f9934c8adc8 100644 --- a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp +++ b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp @@ -424,7 +424,8 @@ namespace { FabricInfo gFabricBeingCommissioned; -CHIP_ERROR SendNOCResponse(app::Command * commandObj, EmberAfNodeOperationalCertStatus status, uint8_t index, CharSpan debug_text) +CHIP_ERROR SendNOCResponse(app::CommandHandler * commandObj, EmberAfNodeOperationalCertStatus status, uint8_t index, + CharSpan debug_text) { app::CommandPathParams cmdParams = { emberAfCurrentEndpoint(), /* group id */ 0, OperationalCredentials::Id, Commands::NOCResponse::Id, (app::CommandPathFlags::kEndpointIdValid) }; diff --git a/src/app/tests/TestCommandInteraction.cpp b/src/app/tests/TestCommandInteraction.cpp index 3586e30541b2b8..c897b4ef0f2a4d 100644 --- a/src/app/tests/TestCommandInteraction.cpp +++ b/src/app/tests/TestCommandInteraction.cpp @@ -61,6 +61,12 @@ constexpr CommandId kTestNonExistCommandId = 0; } // namespace namespace app { +bool ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath) +{ + // Mock cluster catalog, only support one command on one cluster on one endpoint. + return (aCommandPath.mEndpointId == kTestEndpointId && aCommandPath.mClusterId == kTestClusterId && + aCommandPath.mCommandId != kTestNonExistCommandId); +} void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, chip::TLV::TLVReader & aReader, CommandHandler * apCommandObj) @@ -139,13 +145,6 @@ class MockCommandHandlerCallback : public CommandHandler::Callback int onFinalCalledTimes = 0; } mockCommandHandlerDelegate; -bool ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath) -{ - // Mock cluster catalog, only support one command on one cluster on one endpoint. - return (aCommandPath.mEndpointId == kTestEndpointId && aCommandPath.mClusterId == kTestClusterId && - aCommandPath.mCommandId != kTestNonExistCommandId); -} - class TestCommandInteraction { public: @@ -174,11 +173,16 @@ class TestCommandInteraction } private: - static void GenerateReceivedCommand(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, - bool aNeedCommandData, EndpointId aEndpointId = kTestEndpointId, - ClusterId aClusterId = kTestClusterId, CommandId aCommandId = kTestCommandId); - static void AddCommandDataIB(nlTestSuite * apSuite, void * apContext, Command * apCommand, bool aNeedStatusCode, - CommandId aCommandId = kTestCommandId); + static void GenerateInvokeRequest(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, + bool aNeedCommandData, EndpointId aEndpointId = kTestEndpointId, + ClusterId aClusterId = kTestClusterId, CommandId aCommandId = kTestCommandId); + static void GenerateInvokeResponse(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, + bool aNeedCommandData, EndpointId aEndpointId = kTestEndpointId, + ClusterId aClusterId = kTestClusterId, CommandId aCommandId = kTestCommandId); + static void AddInvokeRequestData(nlTestSuite * apSuite, void * apContext, CommandSender * apCommandSender, + CommandId aCommandId = kTestCommandId); + static void AddInvokeResponseData(nlTestSuite * apSuite, void * apContext, CommandHandler * apCommandHandler, + bool aNeedStatusCode, CommandId aCommandId = kTestCommandId); static void ValidateCommandHandlerWithSendCommand(nlTestSuite * apSuite, void * apContext, bool aNeedStatusCode); }; @@ -198,36 +202,95 @@ CommandPathParams MakeTestCommandPath(CommandId aCommandId = kTestCommandId) return CommandPathParams(kTestEndpointId, 0, kTestClusterId, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid)); } -void TestCommandInteraction::GenerateReceivedCommand(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, - bool aNeedCommandData, EndpointId aEndpointId, ClusterId aClusterId, - CommandId aCommandId) +void TestCommandInteraction::GenerateInvokeRequest(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, + bool aNeedCommandData, EndpointId aEndpointId, ClusterId aClusterId, + CommandId aCommandId) + +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeRequestMessage::Builder invokeRequestMessageBuilder; + System::PacketBufferTLVWriter writer; + writer.Init(std::move(aPayload)); + + err = invokeRequestMessageBuilder.Init(&writer); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + invokeRequestMessageBuilder.SuppressResponse(true).TimedRequest(true); + InvokeRequests::Builder invokeRequests = invokeRequestMessageBuilder.CreateInvokeRequests(); + NL_TEST_ASSERT(apSuite, invokeRequestMessageBuilder.GetError() == CHIP_NO_ERROR); + + CommandDataIB::Builder commandDataIBBuilder = invokeRequests.CreateCommandData(); + NL_TEST_ASSERT(apSuite, invokeRequests.GetError() == CHIP_NO_ERROR); + + CommandPathIB::Builder commandPathBuilder = commandDataIBBuilder.CreatePath(); + NL_TEST_ASSERT(apSuite, commandDataIBBuilder.GetError() == CHIP_NO_ERROR); + + commandPathBuilder.EndpointId(aEndpointId).ClusterId(aClusterId).CommandId(aCommandId).EndOfCommandPathIB(); + NL_TEST_ASSERT(apSuite, commandPathBuilder.GetError() == CHIP_NO_ERROR); + + if (aNeedCommandData) + { + chip::TLV::TLVWriter * pWriter = commandDataIBBuilder.GetWriter(); + chip::TLV::TLVType dummyType = chip::TLV::kTLVType_NotSpecified; + err = pWriter->StartContainer(chip::TLV::ContextTag(chip::to_underlying(CommandDataIB::Tag::kData)), + chip::TLV::kTLVType_Structure, dummyType); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + err = pWriter->PutBoolean(chip::TLV::ContextTag(1), true); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + err = pWriter->EndContainer(dummyType); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + } + + commandDataIBBuilder.EndOfCommandDataIB(); + NL_TEST_ASSERT(apSuite, commandDataIBBuilder.GetError() == CHIP_NO_ERROR); + + invokeRequests.EndOfInvokeRequests(); + NL_TEST_ASSERT(apSuite, invokeRequests.GetError() == CHIP_NO_ERROR); + + invokeRequestMessageBuilder.EndOfInvokeRequestMessage(); + NL_TEST_ASSERT(apSuite, invokeRequestMessageBuilder.GetError() == CHIP_NO_ERROR); + + err = writer.Finalize(&aPayload); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +} + +void TestCommandInteraction::GenerateInvokeResponse(nlTestSuite * apSuite, void * apContext, System::PacketBufferHandle & aPayload, + bool aNeedCommandData, EndpointId aEndpointId, ClusterId aClusterId, + CommandId aCommandId) { CHIP_ERROR err = CHIP_NO_ERROR; - InvokeCommand::Builder invokeCommandBuilder; + InvokeResponseMessage::Builder invokeResponseMessageBuilder; System::PacketBufferTLVWriter writer; writer.Init(std::move(aPayload)); - err = invokeCommandBuilder.Init(&writer); + err = invokeResponseMessageBuilder.Init(&writer); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - CommandList::Builder commandList = invokeCommandBuilder.CreateCommandListBuilder(); - NL_TEST_ASSERT(apSuite, invokeCommandBuilder.GetError() == CHIP_NO_ERROR); + invokeResponseMessageBuilder.SuppressResponse(true); + InvokeResponses::Builder invokeResponses = invokeResponseMessageBuilder.CreateInvokeResponses(); + NL_TEST_ASSERT(apSuite, invokeResponseMessageBuilder.GetError() == CHIP_NO_ERROR); - CommandDataIB::Builder commandDataIBBuilder = commandList.CreateCommandDataIBBuilder(); - NL_TEST_ASSERT(apSuite, commandList.GetError() == CHIP_NO_ERROR); + InvokeResponseIB::Builder invokeResponseIBBuilder = invokeResponses.CreateInvokeResponse(); + NL_TEST_ASSERT(apSuite, invokeResponses.GetError() == CHIP_NO_ERROR); + + CommandDataIB::Builder commandDataIBBuilder = invokeResponseIBBuilder.CreateCommand(); + NL_TEST_ASSERT(apSuite, commandDataIBBuilder.GetError() == CHIP_NO_ERROR); - CommandPathIB::Builder commandPathBuilder = commandDataIBBuilder.CreateCommandPathBuilder(); + CommandPathIB::Builder commandPathBuilder = commandDataIBBuilder.CreatePath(); NL_TEST_ASSERT(apSuite, commandDataIBBuilder.GetError() == CHIP_NO_ERROR); - commandPathBuilder.EndpointId(aEndpointId).ClusterId(aClusterId).CommandId(aCommandId).EndOfCommandPath(); + commandPathBuilder.EndpointId(aEndpointId).ClusterId(aClusterId).CommandId(aCommandId).EndOfCommandPathIB(); NL_TEST_ASSERT(apSuite, commandPathBuilder.GetError() == CHIP_NO_ERROR); if (aNeedCommandData) { chip::TLV::TLVWriter * pWriter = commandDataIBBuilder.GetWriter(); chip::TLV::TLVType dummyType = chip::TLV::kTLVType_NotSpecified; - err = pWriter->StartContainer(chip::TLV::ContextTag(CommandDataIB::kCsTag_Data), chip::TLV::kTLVType_Structure, dummyType); + err = pWriter->StartContainer(chip::TLV::ContextTag(chip::to_underlying(CommandDataIB::Tag::kData)), + chip::TLV::kTLVType_Structure, dummyType); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); err = pWriter->PutBoolean(chip::TLV::ContextTag(1), true); @@ -240,18 +303,39 @@ void TestCommandInteraction::GenerateReceivedCommand(nlTestSuite * apSuite, void commandDataIBBuilder.EndOfCommandDataIB(); NL_TEST_ASSERT(apSuite, commandDataIBBuilder.GetError() == CHIP_NO_ERROR); - commandList.EndOfCommandList(); - NL_TEST_ASSERT(apSuite, commandList.GetError() == CHIP_NO_ERROR); + invokeResponseIBBuilder.EndOfInvokeResponseIB(); + NL_TEST_ASSERT(apSuite, invokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); - invokeCommandBuilder.EndOfInvokeCommand(); - NL_TEST_ASSERT(apSuite, invokeCommandBuilder.GetError() == CHIP_NO_ERROR); + invokeResponses.EndOfInvokeResponses(); + NL_TEST_ASSERT(apSuite, invokeResponses.GetError() == CHIP_NO_ERROR); + + invokeResponseMessageBuilder.EndOfInvokeResponseMessage(); + NL_TEST_ASSERT(apSuite, invokeResponseMessageBuilder.GetError() == CHIP_NO_ERROR); err = writer.Finalize(&aPayload); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } -void TestCommandInteraction::AddCommandDataIB(nlTestSuite * apSuite, void * apContext, Command * apCommand, bool aNeedStatusCode, - CommandId aCommandId) +void TestCommandInteraction::AddInvokeRequestData(nlTestSuite * apSuite, void * apContext, CommandSender * apCommandSender, + CommandId aCommandId) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + auto commandPathParams = MakeTestCommandPath(aCommandId); + + err = apCommandSender->PrepareCommand(commandPathParams); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + chip::TLV::TLVWriter * writer = apCommandSender->GetCommandDataIBTLVWriter(); + + err = writer->PutBoolean(chip::TLV::ContextTag(1), true); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + err = apCommandSender->FinishCommand(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +} + +void TestCommandInteraction::AddInvokeResponseData(nlTestSuite * apSuite, void * apContext, CommandHandler * apCommandHandler, + bool aNeedStatusCode, CommandId aCommandId) { CHIP_ERROR err = CHIP_NO_ERROR; auto commandPathParams = MakeTestCommandPath(aCommandId); @@ -262,19 +346,19 @@ void TestCommandInteraction::AddCommandDataIB(nlTestSuite * apSuite, void * apCo 3, // ClusterId 4 // CommandId ); - apCommand->AddStatus(commandPath, Protocols::InteractionModel::Status::Success); + apCommandHandler->AddStatus(commandPath, Protocols::InteractionModel::Status::Success); } else { - err = apCommand->PrepareCommand(commandPathParams); + err = apCommandHandler->PrepareCommand(commandPathParams); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - chip::TLV::TLVWriter * writer = apCommand->GetCommandDataIBTLVWriter(); + chip::TLV::TLVWriter * writer = apCommandHandler->GetCommandDataIBTLVWriter(); err = writer->PutBoolean(chip::TLV::ContextTag(1), true); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = apCommand->FinishCommand(); + err = apCommandHandler->FinishCommand(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } } @@ -318,12 +402,12 @@ void TestCommandInteraction::TestCommandSenderWithSendCommand(nlTestSuite * apSu System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); - AddCommandDataIB(apSuite, apContext, &commandSender, false); + AddInvokeRequestData(apSuite, apContext, &commandSender); err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - GenerateReceivedCommand(apSuite, apContext, buf, true /*aNeedCommandData*/); - err = commandSender.ProcessCommandMessage(std::move(buf), Command::CommandRoleId::SenderId); + GenerateInvokeResponse(apSuite, apContext, buf, true /*aNeedCommandData*/); + err = commandSender.ProcessInvokeResponseMessage(std::move(buf)); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } @@ -356,8 +440,8 @@ void TestCommandInteraction::TestCommandSenderWithProcessReceivedMsg(nlTestSuite System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); - GenerateReceivedCommand(apSuite, apContext, buf, true /*aNeedCommandData*/); - err = commandSender.ProcessCommandMessage(std::move(buf), Command::CommandRoleId::SenderId); + GenerateInvokeResponse(apSuite, apContext, buf, true /*aNeedCommandData*/); + err = commandSender.ProcessInvokeResponseMessage(std::move(buf)); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } @@ -371,19 +455,19 @@ void TestCommandInteraction::ValidateCommandHandlerWithSendCommand(nlTestSuite * TestExchangeDelegate delegate; commandHandler.mpExchangeCtx = ctx.NewExchangeToAlice(&delegate); - AddCommandDataIB(apSuite, apContext, &commandHandler, aNeedStatusCode); + AddInvokeResponseData(apSuite, apContext, &commandHandler, aNeedStatusCode); err = commandHandler.Finalize(commandPacket); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK chip::System::PacketBufferTLVReader reader; - InvokeCommand::Parser invokeCommandParser; + InvokeResponseMessage::Parser invokeResponseMessageParser; reader.Init(std::move(commandPacket)); err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = invokeCommandParser.Init(reader); + err = invokeResponseMessageParser.Init(reader); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = invokeCommandParser.CheckSchemaValidity(); + err = invokeResponseMessageParser.CheckSchemaValidity(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #endif } @@ -425,13 +509,13 @@ void TestCommandInteraction::TestCommandHandlerCommandDataEncoding(nlTestSuite * #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK chip::System::PacketBufferTLVReader reader; - InvokeCommand::Parser invokeCommandParser; + InvokeResponseMessage::Parser invokeResponseMessageParser; reader.Init(std::move(commandPacket)); err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = invokeCommandParser.Init(reader); + err = invokeResponseMessageParser.Init(reader); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = invokeCommandParser.CheckSchemaValidity(); + err = invokeResponseMessageParser.CheckSchemaValidity(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #endif } @@ -448,8 +532,8 @@ void TestCommandInteraction::TestCommandHandlerWithProcessReceivedMsg(nlTestSuit app::CommandHandler commandHandler(&mockCommandHandlerDelegate); System::PacketBufferHandle commandDatabuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); - GenerateReceivedCommand(apSuite, apContext, commandDatabuf, true /*aNeedCommandData*/); - err = commandHandler.ProcessCommandMessage(std::move(commandDatabuf), Command::CommandRoleId::HandlerId); + GenerateInvokeRequest(apSuite, apContext, commandDatabuf, true /*aNeedCommandData*/); + err = commandHandler.ProcessInvokeRequestMessage(std::move(commandDatabuf)); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } @@ -460,13 +544,13 @@ void TestCommandInteraction::TestCommandHandlerWithProcessReceivedNotExistComman System::PacketBufferHandle commandDatabuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); // Use some invalid endpoint / cluster / command. - GenerateReceivedCommand(apSuite, apContext, commandDatabuf, false /*aNeedCommandData*/, 0xDE /* endpoint */, - 0xADBE /* cluster */, 0xEF /* command */); + GenerateInvokeRequest(apSuite, apContext, commandDatabuf, false /*aNeedCommandData*/, 0xDE /* endpoint */, 0xADBE /* cluster */, + 0xEF /* command */); // TODO: Need to find a way to get the response instead of only check if a function on key path is called. // We should not reach CommandDispatch if requested command does not exist. chip::isCommandDispatched = false; - err = commandHandler.ProcessCommandMessage(std::move(commandDatabuf), Command::CommandRoleId::HandlerId); + err = commandHandler.ProcessInvokeRequestMessage(std::move(commandDatabuf)); NL_TEST_ASSERT(apSuite, !chip::isCommandDispatched); } @@ -478,9 +562,9 @@ void TestCommandInteraction::TestCommandHandlerWithProcessReceivedEmptyDataMsg(n chip::isCommandDispatched = false; - GenerateReceivedCommand(apSuite, apContext, commandDatabuf, false /*aNeedCommandData*/); + GenerateInvokeRequest(apSuite, apContext, commandDatabuf, false /*aNeedCommandData*/); - err = commandHandler.ProcessCommandMessage(std::move(commandDatabuf), Command::CommandRoleId::HandlerId); + err = commandHandler.ProcessInvokeRequestMessage(std::move(commandDatabuf)); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR && chip::isCommandDispatched); } @@ -492,8 +576,9 @@ void TestCommandInteraction::TestCommandSenderCommandSuccessResponseFlow(nlTestS mockCommandSenderDelegate.ResetCounter(); app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); - AddCommandDataIB(apSuite, apContext, &commandSender, false); + AddInvokeRequestData(apSuite, apContext, &commandSender); err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, mockCommandSenderDelegate.onResponseCalledTimes == 1 && mockCommandSenderDelegate.onFinalCalledTimes == 1 && @@ -511,8 +596,9 @@ void TestCommandInteraction::TestCommandSenderCommandSpecificResponseFlow(nlTest mockCommandSenderDelegate.ResetCounter(); app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); - AddCommandDataIB(apSuite, apContext, &commandSender, false, kTestCommandIdCommandSpecificResponse); + AddInvokeRequestData(apSuite, apContext, &commandSender, kTestCommandIdCommandSpecificResponse); err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, mockCommandSenderDelegate.onResponseCalledTimes == 1 && mockCommandSenderDelegate.onFinalCalledTimes == 1 && @@ -530,8 +616,9 @@ void TestCommandInteraction::TestCommandSenderCommandFailureResponseFlow(nlTestS mockCommandSenderDelegate.ResetCounter(); app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); - AddCommandDataIB(apSuite, apContext, &commandSender, false, kTestNonExistCommandId); + AddInvokeRequestData(apSuite, apContext, &commandSender, kTestNonExistCommandId); err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, mockCommandSenderDelegate.onResponseCalledTimes == 0 && mockCommandSenderDelegate.onFinalCalledTimes == 1 && @@ -557,8 +644,9 @@ void TestCommandInteraction::TestCommandSenderAbruptDestruction(nlTestSuite * ap { app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); - AddCommandDataIB(apSuite, apContext, &commandSender, false, kTestCommandIdCommandSpecificResponse); + AddInvokeRequestData(apSuite, apContext, &commandSender, kTestCommandIdCommandSpecificResponse); err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); // diff --git a/src/app/tests/TestMessageDef.cpp b/src/app/tests/TestMessageDef.cpp index 891b6e29578d24..ab2dfee6deb4e9 100644 --- a/src/app/tests/TestMessageDef.cpp +++ b/src/app/tests/TestMessageDef.cpp @@ -23,9 +23,8 @@ */ #include -#include -#include -#include +#include +#include #include #include #include @@ -195,7 +194,7 @@ void ParseEventPathList(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) void BuildCommandPath(nlTestSuite * apSuite, CommandPathIB::Builder & aCommandPathBuilder) { - aCommandPathBuilder.EndpointId(1).ClusterId(3).CommandId(4).EndOfCommandPath(); + aCommandPathBuilder.EndpointId(1).ClusterId(3).CommandId(4).EndOfCommandPathIB(); NL_TEST_ASSERT(apSuite, aCommandPathBuilder.GetError() == CHIP_NO_ERROR); } @@ -541,7 +540,7 @@ void BuildCommandDataIB(nlTestSuite * apSuite, CommandDataIB::Builder & aCommand { CHIP_ERROR err = CHIP_NO_ERROR; - CommandPathIB::Builder commandPathBuilder = aCommandDataIBBuilder.CreateCommandPathBuilder(); + CommandPathIB::Builder commandPathBuilder = aCommandDataIBBuilder.CreatePath(); NL_TEST_ASSERT(apSuite, aCommandDataIBBuilder.GetError() == CHIP_NO_ERROR); BuildCommandPath(apSuite, commandPathBuilder); @@ -549,7 +548,8 @@ void BuildCommandDataIB(nlTestSuite * apSuite, CommandDataIB::Builder & aCommand { chip::TLV::TLVWriter * pWriter = aCommandDataIBBuilder.GetWriter(); chip::TLV::TLVType dummyType = chip::TLV::kTLVType_NotSpecified; - err = pWriter->StartContainer(chip::TLV::ContextTag(CommandDataIB::kCsTag_Data), chip::TLV::kTLVType_Structure, dummyType); + err = pWriter->StartContainer(chip::TLV::ContextTag(chip::to_underlying(CommandDataIB::Tag::kData)), + chip::TLV::kTLVType_Structure, dummyType); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); err = pWriter->PutBoolean(chip::TLV::ContextTag(1), true); @@ -571,7 +571,7 @@ void ParseCommandDataIB(nlTestSuite * apSuite, CommandDataIB::Parser & aCommandD err = aCommandDataIBParser.CheckSchemaValidity(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #endif - err = aCommandDataIBParser.GetCommandPath(&commandPathParser); + err = aCommandDataIBParser.GetPath(&commandPathParser); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); { @@ -593,55 +593,212 @@ void ParseCommandDataIB(nlTestSuite * apSuite, CommandDataIB::Parser & aCommandD } } -void BuildCommandDataIBWithStatusCode(nlTestSuite * apSuite, CommandDataIB::Builder & aCommandDataIBBuilder) +void BuildCommandStatusIB(nlTestSuite * apSuite, CommandStatusIB::Builder & aCommandStatusIBBuilder) { - CommandPathIB::Builder commandPathBuilder = aCommandDataIBBuilder.CreateCommandPathBuilder(); - NL_TEST_ASSERT(apSuite, aCommandDataIBBuilder.GetError() == CHIP_NO_ERROR); + CommandPathIB::Builder commandPathBuilder = aCommandStatusIBBuilder.CreatePath(); + NL_TEST_ASSERT(apSuite, aCommandStatusIBBuilder.GetError() == CHIP_NO_ERROR); BuildCommandPath(apSuite, commandPathBuilder); - StatusIB::Builder statusIBBuilder = aCommandDataIBBuilder.CreateStatusIBBuilder(); + StatusIB::Builder statusIBBuilder = aCommandStatusIBBuilder.CreateErrorStatus(); NL_TEST_ASSERT(apSuite, statusIBBuilder.GetError() == CHIP_NO_ERROR); BuildStatusIB(apSuite, statusIBBuilder); - aCommandDataIBBuilder.EndOfCommandDataIB(); - NL_TEST_ASSERT(apSuite, aCommandDataIBBuilder.GetError() == CHIP_NO_ERROR); + aCommandStatusIBBuilder.EndOfCommandStatusIB(); + NL_TEST_ASSERT(apSuite, aCommandStatusIBBuilder.GetError() == CHIP_NO_ERROR); } -void ParseCommandDataIBWithStatusCode(nlTestSuite * apSuite, CommandDataIB::Parser & aCommandDataIBParser) +void ParseCommandStatusIB(nlTestSuite * apSuite, CommandStatusIB::Parser & aCommandStatusIBParser) { CHIP_ERROR err = CHIP_NO_ERROR; CommandPathIB::Parser commandPathParser; - StatusIB::Parser StatusIBParser; + StatusIB::Parser statusParser; #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - err = aCommandDataIBParser.CheckSchemaValidity(); + err = aCommandStatusIBParser.CheckSchemaValidity(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #endif - err = aCommandDataIBParser.GetCommandPath(&commandPathParser); + err = aCommandStatusIBParser.GetPath(&commandPathParser); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = aCommandDataIBParser.GetStatusIB(&StatusIBParser); + err = aCommandStatusIBParser.GetErrorStatus(&statusParser); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } -void BuildCommandList(nlTestSuite * apSuite, CommandList::Builder & aCommandListBuilder) +void BuildWrongInvokeResponseIB(nlTestSuite * apSuite, InvokeResponseIB::Builder & aInvokeResponseIBBuilder) { - CommandDataIB::Builder commandDataIBBuilder = aCommandListBuilder.CreateCommandDataIBBuilder(); - NL_TEST_ASSERT(apSuite, aCommandListBuilder.GetError() == CHIP_NO_ERROR); - BuildCommandDataIB(apSuite, commandDataIBBuilder); + CommandDataIB::Builder commandDataBuilder = aInvokeResponseIBBuilder.CreateCommand(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); + BuildCommandDataIB(apSuite, commandDataBuilder); + CommandStatusIB::Builder commandStatusBuilder = aInvokeResponseIBBuilder.CreateStatus(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); + BuildCommandStatusIB(apSuite, commandStatusBuilder); + aInvokeResponseIBBuilder.EndOfInvokeResponseIB(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); +} + +void BuildInvokeResponseIBWithCommandDataIB(nlTestSuite * apSuite, InvokeResponseIB::Builder & aInvokeResponseIBBuilder) +{ + CommandDataIB::Builder commandDataBuilder = aInvokeResponseIBBuilder.CreateCommand(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); + BuildCommandDataIB(apSuite, commandDataBuilder); + aInvokeResponseIBBuilder.EndOfInvokeResponseIB(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); +} + +void BuildInvokeResponseIBWithCommandStatusIB(nlTestSuite * apSuite, InvokeResponseIB::Builder & aInvokeResponseIBBuilder) +{ + CommandStatusIB::Builder commandStatusBuilder = aInvokeResponseIBBuilder.CreateStatus(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); + BuildCommandStatusIB(apSuite, commandStatusBuilder); + aInvokeResponseIBBuilder.EndOfInvokeResponseIB(); + NL_TEST_ASSERT(apSuite, aInvokeResponseIBBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseInvokeResponseIBWithCommandDataIB(nlTestSuite * apSuite, InvokeResponseIB::Parser & aInvokeResponseIBParser) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + CommandDataIB::Parser commandDataParser; + CommandStatusIB::Parser statusIBParser; +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = aInvokeResponseIBParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif + err = aInvokeResponseIBParser.GetCommand(&commandDataParser); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +} + +void ParseInvokeResponseIBWithCommandStatusIB(nlTestSuite * apSuite, InvokeResponseIB::Parser & aInvokeResponseIBParser) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + CommandDataIB::Parser commandDataParser; + CommandStatusIB::Parser statusIBParser; +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = aInvokeResponseIBParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif + err = aInvokeResponseIBParser.GetStatus(&statusIBParser); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +} - aCommandListBuilder.EndOfCommandList(); - NL_TEST_ASSERT(apSuite, aCommandListBuilder.GetError() == CHIP_NO_ERROR); +void ParseWrongInvokeResponseIB(nlTestSuite * apSuite, InvokeResponseIB::Parser & aInvokeResponseIBParser) +{ + CommandDataIB::Parser commandDataParser; + CommandStatusIB::Parser statusIBParser; +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + CHIP_ERROR err = aInvokeResponseIBParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err != CHIP_NO_ERROR); +#endif } -void ParseCommandList(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +void BuildInvokeRequests(nlTestSuite * apSuite, InvokeRequests::Builder & aInvokeRequestsBuilder) +{ + CommandDataIB::Builder aCommandDataIBBuilder = aInvokeRequestsBuilder.CreateCommandData(); + NL_TEST_ASSERT(apSuite, aInvokeRequestsBuilder.GetError() == CHIP_NO_ERROR); + BuildCommandDataIB(apSuite, aCommandDataIBBuilder); + + aInvokeRequestsBuilder.EndOfInvokeRequests(); + NL_TEST_ASSERT(apSuite, aInvokeRequestsBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseInvokeRequests(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) { CHIP_ERROR err = CHIP_NO_ERROR; - CommandList::Parser commandListParser; - err = commandListParser.Init(aReader); + InvokeRequests::Parser invokeRequestsParser; + err = invokeRequestsParser.Init(aReader); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - err = commandListParser.CheckSchemaValidity(); + err = invokeRequestsParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif +} + +void BuildInvokeResponses(nlTestSuite * apSuite, InvokeResponses::Builder & aInvokeResponsesBuilder) +{ + InvokeResponseIB::Builder invokeResponseIBBuilder = aInvokeResponsesBuilder.CreateInvokeResponse(); + NL_TEST_ASSERT(apSuite, aInvokeResponsesBuilder.GetError() == CHIP_NO_ERROR); + BuildInvokeResponseIBWithCommandDataIB(apSuite, invokeResponseIBBuilder); + + aInvokeResponsesBuilder.EndOfInvokeResponses(); + NL_TEST_ASSERT(apSuite, aInvokeResponsesBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseInvokeResponses(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponses::Parser invokeResponsesParser; + err = invokeResponsesParser.Init(aReader); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = invokeResponsesParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif +} + +void BuildInvokeRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVWriter & aWriter) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeRequestMessage::Builder invokeRequestMessageBuilder; + err = invokeRequestMessageBuilder.Init(&aWriter); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + invokeRequestMessageBuilder.SuppressResponse(true); + invokeRequestMessageBuilder.TimedRequest(true); + InvokeRequests::Builder invokeRequestsBuilder = invokeRequestMessageBuilder.CreateInvokeRequests(); + NL_TEST_ASSERT(apSuite, invokeRequestsBuilder.GetError() == CHIP_NO_ERROR); + + BuildInvokeRequests(apSuite, invokeRequestsBuilder); + + invokeRequestMessageBuilder.EndOfInvokeRequestMessage(); + NL_TEST_ASSERT(apSuite, invokeRequestMessageBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseInvokeRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeRequestMessage::Parser invokeRequestMessageParser; + err = invokeRequestMessageParser.Init(aReader); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + bool suppressResponse = false; + bool timedRequest = false; + invokeRequestMessageParser.GetSuppressResponse(&suppressResponse); + invokeRequestMessageParser.GetTimedRequest(&timedRequest); + NL_TEST_ASSERT(apSuite, suppressResponse == true); + NL_TEST_ASSERT(apSuite, timedRequest == true); +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = invokeRequestMessageParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif +} + +void BuildInvokeResponseMessage(nlTestSuite * apSuite, chip::TLV::TLVWriter & aWriter) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponseMessage::Builder invokeResponseMessageBuilder; + err = invokeResponseMessageBuilder.Init(&aWriter); + + invokeResponseMessageBuilder.SuppressResponse(true); + InvokeResponses::Builder invokeResponsesBuilder = invokeResponseMessageBuilder.CreateInvokeResponses(); + NL_TEST_ASSERT(apSuite, invokeResponseMessageBuilder.GetError() == CHIP_NO_ERROR); + + BuildInvokeResponses(apSuite, invokeResponsesBuilder); + + invokeResponseMessageBuilder.EndOfInvokeResponseMessage(); + NL_TEST_ASSERT(apSuite, invokeResponseMessageBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseInvokeResponseMessage(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponseMessage::Parser invokeResponseMessageParser; + err = invokeResponseMessageParser.Init(aReader); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + bool suppressResponse = false; + invokeResponseMessageParser.GetSuppressResponse(&suppressResponse); + NL_TEST_ASSERT(apSuite, suppressResponse == true); +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = invokeResponseMessageParser.CheckSchemaValidity(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); #endif } @@ -704,40 +861,6 @@ void ParseReportData(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR && moreChunkedMessages); } -void BuildInvokeCommand(nlTestSuite * apSuite, chip::TLV::TLVWriter & aWriter) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - InvokeCommand::Builder invokeCommandBuilder; - - err = invokeCommandBuilder.Init(&aWriter); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - - CommandList::Builder commandList = invokeCommandBuilder.CreateCommandListBuilder(); - NL_TEST_ASSERT(apSuite, invokeCommandBuilder.GetError() == CHIP_NO_ERROR); - BuildCommandList(apSuite, commandList); - - invokeCommandBuilder.EndOfInvokeCommand(); - NL_TEST_ASSERT(apSuite, invokeCommandBuilder.GetError() == CHIP_NO_ERROR); -} - -void ParseInvokeCommand(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - InvokeCommand::Parser invokeCommandParser; - CommandList::Parser commandListParser; - - err = invokeCommandParser.Init(aReader); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - -#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - err = invokeCommandParser.CheckSchemaValidity(); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); -#endif - err = invokeCommandParser.GetCommandList(&commandListParser); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); -} - void BuildReadRequest(nlTestSuite * apSuite, chip::TLV::TLVWriter & aWriter) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -1365,16 +1488,16 @@ void CommandDataIBTest(nlTestSuite * apSuite, void * apContext) ParseCommandDataIB(apSuite, commandDataIBParser); } -void CommandDataIBWithStatusCodeTest(nlTestSuite * apSuite, void * apContext) +void CommandStatusIBTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; - CommandDataIB::Builder commandDataIBBuilder; - CommandDataIB::Parser commandDataIBParser; + CommandStatusIB::Builder commandStatusIBBuilder; + CommandStatusIB::Parser commandStatusIBParser; chip::System::PacketBufferTLVWriter writer; chip::System::PacketBufferTLVReader reader; writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); - commandDataIBBuilder.Init(&writer); - BuildCommandDataIBWithStatusCode(apSuite, commandDataIBBuilder); + commandStatusIBBuilder.Init(&writer); + BuildCommandStatusIB(apSuite, commandStatusIBBuilder); chip::System::PacketBufferHandle buf; err = writer.Finalize(&buf); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1385,19 +1508,20 @@ void CommandDataIBWithStatusCodeTest(nlTestSuite * apSuite, void * apContext) err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - commandDataIBParser.Init(reader); - ParseCommandDataIBWithStatusCode(apSuite, commandDataIBParser); + commandStatusIBParser.Init(reader); + ParseCommandStatusIB(apSuite, commandStatusIBParser); } -void CommandListTest(nlTestSuite * apSuite, void * apContext) +void InvokeResponseIBWithCommandDataIBTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponseIB::Builder invokeResponseIBBuilder; + InvokeResponseIB::Parser invokeResponseIBParser; chip::System::PacketBufferTLVWriter writer; chip::System::PacketBufferTLVReader reader; - CommandList::Builder commandListBuilder; writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); - commandListBuilder.Init(&writer); - BuildCommandList(apSuite, commandListBuilder); + invokeResponseIBBuilder.Init(&writer); + BuildInvokeResponseIBWithCommandDataIB(apSuite, invokeResponseIBBuilder); chip::System::PacketBufferHandle buf; err = writer.Finalize(&buf); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1407,16 +1531,21 @@ void CommandListTest(nlTestSuite * apSuite, void * apContext) reader.Init(std::move(buf)); err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - ParseCommandList(apSuite, reader); + + invokeResponseIBParser.Init(reader); + ParseInvokeResponseIBWithCommandDataIB(apSuite, invokeResponseIBParser); } -void ReportDataTest(nlTestSuite * apSuite, void * apContext) +void InvokeResponseIBWithCommandStatusIBTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponseIB::Builder invokeResponseIBBuilder; + InvokeResponseIB::Parser invokeResponseIBParser; chip::System::PacketBufferTLVWriter writer; chip::System::PacketBufferTLVReader reader; writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); - BuildReportData(apSuite, writer); + invokeResponseIBBuilder.Init(&writer); + BuildInvokeResponseIBWithCommandStatusIB(apSuite, invokeResponseIBBuilder); chip::System::PacketBufferHandle buf; err = writer.Finalize(&buf); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1426,16 +1555,44 @@ void ReportDataTest(nlTestSuite * apSuite, void * apContext) reader.Init(std::move(buf)); err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - ParseReportData(apSuite, reader); + + invokeResponseIBParser.Init(reader); + ParseInvokeResponseIBWithCommandStatusIB(apSuite, invokeResponseIBParser); +} + +void InvokeResponseIBWithMalformDataTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + InvokeResponseIB::Builder invokeResponseIBBuilder; + InvokeResponseIB::Parser invokeResponseIBParser; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + invokeResponseIBBuilder.Init(&writer); + BuildWrongInvokeResponseIB(apSuite, invokeResponseIBBuilder); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + invokeResponseIBParser.Init(reader); + ParseWrongInvokeResponseIB(apSuite, invokeResponseIBParser); } -void InvokeCommandTest(nlTestSuite * apSuite, void * apContext) +void InvokeRequestsTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; chip::System::PacketBufferTLVWriter writer; chip::System::PacketBufferTLVReader reader; + InvokeRequests::Builder invokeRequestsBuilder; writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); - BuildInvokeCommand(apSuite, writer); + invokeRequestsBuilder.Init(&writer); + BuildInvokeRequests(apSuite, invokeRequestsBuilder); chip::System::PacketBufferHandle buf; err = writer.Finalize(&buf); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1445,7 +1602,85 @@ void InvokeCommandTest(nlTestSuite * apSuite, void * apContext) reader.Init(std::move(buf)); err = reader.Next(); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - ParseInvokeCommand(apSuite, reader); + ParseInvokeRequests(apSuite, reader); +} + +void InvokeResponsesTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + InvokeResponses::Builder invokeResponsesBuilder; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + invokeResponsesBuilder.Init(&writer); + BuildInvokeResponses(apSuite, invokeResponsesBuilder); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + ParseInvokeResponses(apSuite, reader); +} + +void InvokeInvokeRequestMessageTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + BuildInvokeRequestMessage(apSuite, writer); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + ParseInvokeRequestMessage(apSuite, reader); +} + +void InvokeInvokeResponseMessageTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + BuildInvokeResponseMessage(apSuite, writer); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + ParseInvokeResponseMessage(apSuite, reader); +} + +void ReportDataTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + BuildReportData(apSuite, writer); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + ParseReportData(apSuite, reader); } void ReadRequestTest(nlTestSuite * apSuite, void * apContext) @@ -1626,7 +1861,6 @@ const nlTest sTests[] = NL_TEST_DEF("AttributePathListTest", AttributePathListTest), NL_TEST_DEF("EventPathTest", EventPathTest), NL_TEST_DEF("EventPathListTest", EventPathListTest), - NL_TEST_DEF("CommandPathTest", CommandPathTest), NL_TEST_DEF("EventDataElementTest", EventDataElementTest), NL_TEST_DEF("EventListTest", EventListTest), NL_TEST_DEF("StatusIBTest", StatusIBTest), @@ -1635,11 +1869,17 @@ const nlTest sTests[] = NL_TEST_DEF("AttributeDataElementTest", AttributeDataElementTest), NL_TEST_DEF("AttributeDataListTest", AttributeDataListTest), NL_TEST_DEF("AttributeDataVersionListTest", AttributeDataVersionListTest), + NL_TEST_DEF("CommandPathTest", CommandPathTest), NL_TEST_DEF("CommandDataIBTest", CommandDataIBTest), - NL_TEST_DEF("CommandDataIBWithStatusCodeTest", CommandDataIBWithStatusCodeTest), - NL_TEST_DEF("CommandListTest", CommandListTest), + NL_TEST_DEF("CommandStatusIBTest", CommandStatusIBTest), + NL_TEST_DEF("InvokeResponseIBWithCommandDataIBTest", InvokeResponseIBWithCommandDataIBTest), + NL_TEST_DEF("InvokeResponseIBWithCommandStatusIBTest", InvokeResponseIBWithCommandStatusIBTest), + NL_TEST_DEF("InvokeResponseIBWithMalformDataTest", InvokeResponseIBWithMalformDataTest), + NL_TEST_DEF("InvokeRequestsTest", InvokeRequestsTest), + NL_TEST_DEF("InvokeResponsesTest", InvokeResponsesTest), + NL_TEST_DEF("InvokeInvokeRequestMessageTest", InvokeInvokeRequestMessageTest), + NL_TEST_DEF("InvokeInvokeResponseMessageTest", InvokeInvokeResponseMessageTest), NL_TEST_DEF("ReportDataTest", ReportDataTest), - NL_TEST_DEF("InvokeCommandTest", InvokeCommandTest), NL_TEST_DEF("ReadRequestTest", ReadRequestTest), NL_TEST_DEF("WriteRequestTest", WriteRequestTest), NL_TEST_DEF("WriteResponseTest", WriteResponseTest), diff --git a/src/app/tests/integration/chip_im_initiator.cpp b/src/app/tests/integration/chip_im_initiator.cpp index bd1d7ce307e4ac..b2acaee0647bf1 100644 --- a/src/app/tests/integration/chip_im_initiator.cpp +++ b/src/app/tests/integration/chip_im_initiator.cpp @@ -607,7 +607,6 @@ void SubscribeRequestTimerHandler(chip::System::Layer * systemLayer, void * appS namespace chip { namespace app { - bool ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath) { // Always return true in test. diff --git a/src/lib/core/CHIPError.cpp b/src/lib/core/CHIPError.cpp index 6ac83ca3b511e7..27e811faaad9d1 100644 --- a/src/lib/core/CHIPError.cpp +++ b/src/lib/core/CHIPError.cpp @@ -653,6 +653,18 @@ bool FormatCHIPError(char * buf, uint16_t bufSize, CHIP_ERROR err) case CHIP_ERROR_IM_STATUS_CODE_RECEIVED.AsInteger(): desc = "Interaction Model Error"; break; + case CHIP_ERROR_IM_MALFORMED_COMMAND_STATUS_IB.AsInteger(): + desc = "Malformed Interaction Model Command Status IB"; + break; + case CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_IB.AsInteger(): + desc = "Malformed Interaction Model Invoke Response code IB"; + break; + case CHIP_ERROR_IM_MALFORMED_INVOKE_REQUEST_MESSAGE.AsInteger(): + desc = "Malformed Interaction Model Invoke Response Message"; + break; + case CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE.AsInteger(): + desc = "Malformed Interaction Model Invoke Response MESSAGE"; + break; } #endif // !CHIP_CONFIG_SHORT_ERROR_STR diff --git a/src/lib/core/CHIPError.h b/src/lib/core/CHIPError.h index 2003bb0418ce2d..3fe6730b7472ab 100644 --- a/src/lib/core/CHIPError.h +++ b/src/lib/core/CHIPError.h @@ -2216,6 +2216,42 @@ using CHIP_ERROR = ::chip::ChipError; */ #define CHIP_ERROR_ANOTHER_COMMISSIONING_IN_PROGRESS CHIP_CORE_ERROR(0xcb) +/** + * @def CHIP_ERROR_IM_MALFORMED_COMMAND_STATUS_IB + * + * @brief + * The CommandStatusCodeIB is malformed: it either does not contain + * the required elements + */ +#define CHIP_ERROR_IM_MALFORMED_COMMAND_STATUS_IB CHIP_CORE_ERROR(0xcb) + +/** + * @def CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_IB + * + * @brief + * The InvokeResponseIB is malformed: it either does not contain + * the required elements + */ +#define CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_IB CHIP_CORE_ERROR(0xcc) + +/** + * @def CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE + * + * @brief + * The InvokeResponseMessage is malformed: it either does not contain + * the required elements + */ +#define CHIP_ERROR_IM_MALFORMED_INVOKE_REQUEST_MESSAGE CHIP_CORE_ERROR(0xcd) + +/** + * @def CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE + * + * @brief + * The InvokeResponseMessage is malformed: it either does not contain + * the required elements + */ +#define CHIP_ERROR_IM_MALFORMED_INVOKE_RESPONSE_MESSAGE CHIP_CORE_ERROR(0xce) + /** * @} */