diff --git a/docs/cluster_and_device_type_dev/img/cluster_commands.png b/docs/cluster_and_device_type_dev/img/cluster_commands.png index 959774e071b717..c04dbe7279b28b 100644 Binary files a/docs/cluster_and_device_type_dev/img/cluster_commands.png and b/docs/cluster_and_device_type_dev/img/cluster_commands.png differ diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.matter b/examples/light-switch-app/light-switch-common/light-switch-app.matter index b96bf908f766ab..773644c116ecdb 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/light-switch-app.matter @@ -2628,6 +2628,7 @@ endpoint 0 { ram attribute clusterRevision default = 1; handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; } server cluster GeneralDiagnostics { diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.zap b/examples/light-switch-app/light-switch-common/light-switch-app.zap index 3d15cf009086d8..af0915b9ebd213 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.zap +++ b/examples/light-switch-app/light-switch-common/light-switch-app.zap @@ -1581,6 +1581,14 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 } ], "attributes": [ @@ -1803,10 +1811,10 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -1819,10 +1827,10 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0x0002", + "defaultValue": null, "reportable": 1, "minInterval": 0, "maxInterval": 65344, @@ -4605,6 +4613,24 @@ "define": "IDENTIFY_CLUSTER", "side": "client", "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + } + ], "attributes": [ { "name": "ClusterRevision", diff --git a/examples/lighting-app/silabs/data_model/lighting-thread-app.matter b/examples/lighting-app/silabs/data_model/lighting-thread-app.matter index 6803904ba5e560..f0859d26d90dca 100644 --- a/examples/lighting-app/silabs/data_model/lighting-thread-app.matter +++ b/examples/lighting-app/silabs/data_model/lighting-thread-app.matter @@ -2520,6 +2520,7 @@ endpoint 0 { ram attribute clusterRevision default = 1; handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; } server cluster GeneralDiagnostics { diff --git a/examples/lighting-app/silabs/data_model/lighting-thread-app.zap b/examples/lighting-app/silabs/data_model/lighting-thread-app.zap index eb3e958009ace5..b26d5eb1f5e0c2 100644 --- a/examples/lighting-app/silabs/data_model/lighting-thread-app.zap +++ b/examples/lighting-app/silabs/data_model/lighting-thread-app.zap @@ -1509,6 +1509,14 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 } ], "attributes": [ @@ -1731,10 +1739,10 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -1747,10 +1755,10 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0x0002", + "defaultValue": null, "reportable": 1, "minInterval": 0, "maxInterval": 65344, diff --git a/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter b/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter index 90083596d9cf24..2c37a0608699be 100644 --- a/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter +++ b/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter @@ -2430,6 +2430,7 @@ endpoint 0 { ram attribute clusterRevision default = 1; handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; } server cluster GeneralDiagnostics { diff --git a/examples/lighting-app/silabs/data_model/lighting-wifi-app.zap b/examples/lighting-app/silabs/data_model/lighting-wifi-app.zap index c99d5e4716fcc9..5c5e582f654265 100644 --- a/examples/lighting-app/silabs/data_model/lighting-wifi-app.zap +++ b/examples/lighting-app/silabs/data_model/lighting-wifi-app.zap @@ -1493,6 +1493,14 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 } ], "attributes": [ @@ -1715,10 +1723,10 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -1731,10 +1739,10 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0x0002", + "defaultValue": null, "reportable": 1, "minInterval": 0, "maxInterval": 65344, diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter index 1b34782e4ea180..ac0caa258d795d 100644 --- a/examples/lock-app/lock-common/lock-app.matter +++ b/examples/lock-app/lock-common/lock-app.matter @@ -2663,6 +2663,7 @@ endpoint 0 { ram attribute clusterRevision default = 1; handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; } server cluster GeneralDiagnostics { diff --git a/examples/lock-app/lock-common/lock-app.zap b/examples/lock-app/lock-common/lock-app.zap index 8ec233c5250e71..6b1e755967c75a 100644 --- a/examples/lock-app/lock-common/lock-app.zap +++ b/examples/lock-app/lock-common/lock-app.zap @@ -2126,6 +2126,14 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 } ], "attributes": [ @@ -4939,7 +4947,6 @@ "define": "ICD_MANAGEMENT_CLUSTER", "side": "server", "enabled": 1, - "commands": [], "attributes": [ { "name": "IdleModeDuration", diff --git a/examples/thermostat/thermostat-common/thermostat.matter b/examples/thermostat/thermostat-common/thermostat.matter index 301dbf6b94e1b3..ab7a21778cc3d6 100644 --- a/examples/thermostat/thermostat-common/thermostat.matter +++ b/examples/thermostat/thermostat-common/thermostat.matter @@ -2097,6 +2097,7 @@ endpoint 0 { server cluster Identify { ram attribute identifyTime default = 0x0000; + ram attribute identifyType default = 0x00; ram attribute featureMap default = 0; ram attribute clusterRevision default = 4; @@ -2240,6 +2241,7 @@ endpoint 0 { ram attribute clusterRevision default = 1; handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; } server cluster GeneralDiagnostics { diff --git a/examples/thermostat/thermostat-common/thermostat.zap b/examples/thermostat/thermostat-common/thermostat.zap index 651b0fd201a2f1..b8c7b0c24838c7 100644 --- a/examples/thermostat/thermostat-common/thermostat.zap +++ b/examples/thermostat/thermostat-common/thermostat.zap @@ -94,6 +94,22 @@ "maxInterval": 65344, "reportableChange": 0 }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "FeatureMap", "code": 65532, @@ -1707,6 +1723,14 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 } ], "attributes": [ @@ -1929,10 +1953,10 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -1945,10 +1969,10 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0x0002", + "defaultValue": null, "reportable": 1, "minInterval": 0, "maxInterval": 65344, diff --git a/src/app/tests/TestCommandInteraction.cpp b/src/app/tests/TestCommandInteraction.cpp index 6aab66ec8549c3..d917315f2a43ec 100644 --- a/src/app/tests/TestCommandInteraction.cpp +++ b/src/app/tests/TestCommandInteraction.cpp @@ -119,6 +119,12 @@ struct ForcedSizeBuffer } }; +enum class ForcedSizeBufferLengthHint +{ + kSizeBetween0and255, + kSizeGreaterThan255, +}; + InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aRequestCommandPath) { // Mock cluster catalog, only support commands on one cluster on one endpoint. @@ -379,6 +385,8 @@ class TestCommandInteraction static void AddInvokeResponseData(nlTestSuite * apSuite, void * apContext, CommandHandler * apCommandHandler, bool aNeedStatusCode, CommandId aResponseCommandId = kTestCommandIdWithData, CommandId aRequestCommandId = kTestCommandIdWithData); + static uint32_t GetAddResponseDataOverheadSizeForPath(nlTestSuite * apSuite, const ConcreteCommandPath & aRequestCommandPath, + ForcedSizeBufferLengthHint aBufferSizeHint); static void FillCurrentInvokeResponseBuffer(nlTestSuite * apSuite, CommandHandler * apCommandHandler, const ConcreteCommandPath & aRequestCommandPath, uint32_t aSizeToLeaveInBuffer); static void ValidateCommandHandlerEncodeInvokeResponseMessage(nlTestSuite * apSuite, void * apContext, bool aNeedStatusCode); @@ -577,6 +585,36 @@ void TestCommandInteraction::AddInvokeResponseData(nlTestSuite * apSuite, void * } } +uint32_t TestCommandInteraction::GetAddResponseDataOverheadSizeForPath(nlTestSuite * apSuite, + const ConcreteCommandPath & aRequestCommandPath, + ForcedSizeBufferLengthHint aBufferSizeHint) +{ + BasicCommandPathRegistry<4> mBasicCommandPathRegistry; + CommandHandler commandHandler(kCommandHandlerTestOnlyMarker, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); + commandHandler.mReserveSpaceForMoreChunkMessages = true; + ConcreteCommandPath requestCommandPath1 = { kTestEndpointId, kTestClusterId, kTestCommandIdFillResponseMessage }; + ConcreteCommandPath requestCommandPath2 = { kTestEndpointId, kTestClusterId, kTestCommandIdCommandSpecificResponse }; + + CHIP_ERROR err = mBasicCommandPathRegistry.Add(requestCommandPath1, MakeOptional(static_cast(1))); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + err = mBasicCommandPathRegistry.Add(requestCommandPath2, MakeOptional(static_cast(2))); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + err = commandHandler.AllocateBuffer(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + uint32_t remainingSizeBefore = commandHandler.mInvokeResponseBuilder.GetWriter()->GetRemainingFreeLength(); + + // When ForcedSizeBuffer exceeds 255, an extra byte is needed for length, affecting the overhead size required by + // AddResponseData. In order to have this accounted for in overhead calculation we set the length to be 256. + uint32_t sizeOfForcedSizeBuffer = aBufferSizeHint == ForcedSizeBufferLengthHint::kSizeGreaterThan255 ? 256 : 0; + err = commandHandler.AddResponseData(aRequestCommandPath, ForcedSizeBuffer(sizeOfForcedSizeBuffer)); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + uint32_t remainingSizeAfter = commandHandler.mInvokeResponseBuilder.GetWriter()->GetRemainingFreeLength(); + uint32_t delta = remainingSizeBefore - remainingSizeAfter - sizeOfForcedSizeBuffer; + + return delta; +} + void TestCommandInteraction::FillCurrentInvokeResponseBuffer(nlTestSuite * apSuite, CommandHandler * apCommandHandler, const ConcreteCommandPath & aRequestCommandPath, uint32_t aSizeToLeaveInBuffer) @@ -587,13 +625,17 @@ void TestCommandInteraction::FillCurrentInvokeResponseBuffer(nlTestSuite * apSui NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); uint32_t remainingSize = apCommandHandler->mInvokeResponseBuilder.GetWriter()->GetRemainingFreeLength(); - // TODO(#30453): Have this value derived from IM layer similar to GetSizeToEndInvokeResponseMessage() - // This number was derived by executing this method with aSizeToLeaveInBuffer = 100 and - // subsequently analyzing the remaining size to determine the overhead associated with calling - // AddResponseData with `ForcedSizeBuffer`. - uint32_t sizeNeededForAddingResponse = 27; - NL_TEST_ASSERT(apSuite, remainingSize > (aSizeToLeaveInBuffer + sizeNeededForAddingResponse)); - uint32_t sizeToFill = remainingSize - aSizeToLeaveInBuffer - sizeNeededForAddingResponse; + // AddResponseData's overhead calculation depends on the size of ForcedSizeBuffer. If the buffer exceeds 255 bytes, an extra + // length byte is required. Since tests using FillCurrentInvokeResponseBuffer currently end up with sizeToFill > 255, we + // inform the calculation of this expectation. Nonetheless, we also validate this assumption for correctness. + ForcedSizeBufferLengthHint bufferSizeHint = ForcedSizeBufferLengthHint::kSizeGreaterThan255; + uint32_t overheadSizeNeededForAddingResponse = + GetAddResponseDataOverheadSizeForPath(apSuite, aRequestCommandPath, bufferSizeHint); + NL_TEST_ASSERT(apSuite, remainingSize > (aSizeToLeaveInBuffer + overheadSizeNeededForAddingResponse)); + uint32_t sizeToFill = remainingSize - aSizeToLeaveInBuffer - overheadSizeNeededForAddingResponse; + + // Validating assumption. If this fails, it means overheadSizeNeededForAddingResponse is likely too large. + NL_TEST_ASSERT(apSuite, sizeToFill >= 256); err = apCommandHandler->AddResponseData(aRequestCommandPath, ForcedSizeBuffer(sizeToFill)); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1534,36 +1576,31 @@ void TestCommandInteraction::TestCommandHandlerRejectMultipleIdenticalCommands(n CHIP_ERROR err = CHIP_NO_ERROR; isCommandDispatched = false; - mockCommandSenderDelegate.ResetCounter(); - app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); + mockCommandSenderExtendedDelegate.ResetCounter(); + PendingResponseTrackerImpl pendingResponseTracker; + app::CommandSender commandSender(kCommandSenderTestOnlyMarker, &mockCommandSenderExtendedDelegate, &ctx.GetExchangeManager(), + &pendingResponseTracker); - { - // Command ID is not important here, since the command handler should reject the commands without handling it. - auto commandPathParams = MakeTestCommandPath(kTestCommandIdCommandSpecificResponse); + app::CommandSender::ConfigParameters configParameters; + configParameters.SetRemoteMaxPathsPerInvoke(2); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.SetCommandSenderConfig(configParameters)); - commandSender.AllocateBuffer(); + // Command ID is not important here, since the command handler should reject the commands without handling it. + auto commandPathParams = MakeTestCommandPath(kTestCommandIdCommandSpecificResponse); - // TODO(#30453): CommandSender does support sending multiple commands, update this test to use that. - for (int i = 0; i < 2; i++) - { - InvokeRequests::Builder & invokeRequests = commandSender.mInvokeRequestBuilder.GetInvokeRequests(); - CommandDataIB::Builder & invokeRequest = invokeRequests.CreateCommandData(); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequests.GetError()); - CommandPathIB::Builder & path = invokeRequest.CreatePath(); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.GetError()); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == path.Encode(commandPathParams)); - NL_TEST_ASSERT(apSuite, - CHIP_NO_ERROR == - invokeRequest.GetWriter()->StartContainer(TLV::ContextTag(CommandDataIB::Tag::kFields), - TLV::kTLVType_Structure, - commandSender.mDataElementContainerType)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.GetWriter()->PutBoolean(chip::TLV::ContextTag(1), true)); - NL_TEST_ASSERT(apSuite, - CHIP_NO_ERROR == invokeRequest.GetWriter()->EndContainer(commandSender.mDataElementContainerType)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.EndOfCommandDataIB()); - } + for (uint16_t i = 0; i < 2; i++) + { + app::CommandSender::PrepareCommandParameters prepareCommandParams; + prepareCommandParams.SetStartDataStruct(true); + prepareCommandParams.SetCommandRef(i); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.PrepareCommand(commandPathParams, prepareCommandParams)); + NL_TEST_ASSERT(apSuite, + CHIP_NO_ERROR == commandSender.GetCommandDataIBTLVWriter()->PutBoolean(chip::TLV::ContextTag(1), true)); - commandSender.MoveToState(app::CommandSender::State::AddedCommand); + app::CommandSender::FinishCommandParameters finishCommandParams; + finishCommandParams.SetEndDataStruct(true); + finishCommandParams.SetCommandRef(i); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.FinishCommand(finishCommandParams)); } err = commandSender.SendCommandRequest(ctx.GetSessionBobToAlice()); @@ -1573,14 +1610,17 @@ void TestCommandInteraction::TestCommandHandlerRejectMultipleIdenticalCommands(n ctx.DrainAndServiceIO(); NL_TEST_ASSERT(apSuite, - mockCommandSenderDelegate.onResponseCalledTimes == 0 && mockCommandSenderDelegate.onFinalCalledTimes == 1 && - mockCommandSenderDelegate.onErrorCalledTimes == 1); + mockCommandSenderExtendedDelegate.onResponseCalledTimes == 0 && + mockCommandSenderExtendedDelegate.onFinalCalledTimes == 1 && + mockCommandSenderExtendedDelegate.onErrorCalledTimes == 1); NL_TEST_ASSERT(apSuite, !chip::isCommandDispatched); NL_TEST_ASSERT(apSuite, GetNumActiveHandlerObjects() == 0); NL_TEST_ASSERT(apSuite, ctx.GetExchangeManager().GetNumActiveExchanges() == 0); } +#if CONFIG_BUILD_FOR_HOST_UNIT_TEST + void TestCommandInteraction::TestCommandHandlerRejectsMultipleCommandsWithIdenticalCommandRef(nlTestSuite * apSuite, void * apContext) { @@ -1588,45 +1628,44 @@ void TestCommandInteraction::TestCommandHandlerRejectsMultipleCommandsWithIdenti CHIP_ERROR err = CHIP_NO_ERROR; isCommandDispatched = false; - mockCommandSenderDelegate.ResetCounter(); + mockCommandSenderExtendedDelegate.ResetCounter(); + PendingResponseTrackerImpl pendingResponseTracker; + app::CommandSender commandSender(kCommandSenderTestOnlyMarker, &mockCommandSenderExtendedDelegate, &ctx.GetExchangeManager(), + &pendingResponseTracker); - // Using commandSender to help build afterward we take the buffer to feed into standalone CommandHandler - app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); + app::CommandSender::ConfigParameters configParameters; + configParameters.SetRemoteMaxPathsPerInvoke(2); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.SetCommandSenderConfig(configParameters)); - size_t numberOfCommandsToSend = 2; + uint16_t numberOfCommandsToSend = 2; { CommandPathParams requestCommandPaths[] = { MakeTestCommandPath(kTestCommandIdWithData), MakeTestCommandPath(kTestCommandIdCommandSpecificResponse), }; - commandSender.AllocateBuffer(); + uint16_t hardcodedCommandRef = 0; - // TODO(#30453): CommandSender does support sending multiple commands, update this test to use that. - for (size_t i = 0; i < numberOfCommandsToSend; i++) + for (uint16_t i = 0; i < numberOfCommandsToSend; i++) { - InvokeRequests::Builder & invokeRequests = commandSender.mInvokeRequestBuilder.GetInvokeRequests(); - CommandDataIB::Builder & invokeRequest = invokeRequests.CreateCommandData(); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequests.GetError()); - CommandPathIB::Builder & path = invokeRequest.CreatePath(); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.GetError()); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == path.Encode(requestCommandPaths[i])); + app::CommandSender::PrepareCommandParameters prepareCommandParams; + prepareCommandParams.SetStartDataStruct(true); + prepareCommandParams.SetCommandRef(i); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.PrepareCommand(requestCommandPaths[i], prepareCommandParams)); NL_TEST_ASSERT(apSuite, - CHIP_NO_ERROR == - invokeRequest.GetWriter()->StartContainer(TLV::ContextTag(CommandDataIB::Tag::kFields), - TLV::kTLVType_Structure, - commandSender.mDataElementContainerType)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.GetWriter()->PutBoolean(chip::TLV::ContextTag(1), true)); - NL_TEST_ASSERT(apSuite, - CHIP_NO_ERROR == invokeRequest.GetWriter()->EndContainer(commandSender.mDataElementContainerType)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.Ref(1)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.EndOfCommandDataIB()); + CHIP_NO_ERROR == commandSender.GetCommandDataIBTLVWriter()->PutBoolean(chip::TLV::ContextTag(1), true)); + // TODO fix this comment + // We are taking advantage of the fact that the commandRef was set into finishCommandParams during PrepareCommand + // But setting it to a different value here, we are overriding what it was supposed to be. + app::CommandSender::FinishCommandParameters finishCommandParams; + finishCommandParams.SetEndDataStruct(true); + finishCommandParams.SetCommandRef(hardcodedCommandRef); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.TestOnlyFinishCommand(finishCommandParams)); } - - commandSender.MoveToState(app::CommandSender::State::AddedCommand); } - CommandHandler commandHandler(&mockCommandHandlerDelegate); + BasicCommandPathRegistry<4> mBasicCommandPathRegistry; + CommandHandler commandHandler(kCommandHandlerTestOnlyMarker, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); TestExchangeDelegate delegate; auto exchange = ctx.NewExchangeToAlice(&delegate, false); commandHandler.mResponseSender.SetExchangeContext(exchange); @@ -1654,6 +1693,8 @@ void TestCommandInteraction::TestCommandHandlerRejectsMultipleCommandsWithIdenti exchange->Close(); } +#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST + void TestCommandInteraction::TestCommandHandlerRejectMultipleCommandsWhenHandlerOnlySupportsOne(nlTestSuite * apSuite, void * apContext) { @@ -1661,46 +1702,39 @@ void TestCommandInteraction::TestCommandHandlerRejectMultipleCommandsWhenHandler CHIP_ERROR err = CHIP_NO_ERROR; isCommandDispatched = false; - mockCommandSenderDelegate.ResetCounter(); - // Using commandSender to help build afterward we take the buffer to feed into standalone CommandHandler - app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); + mockCommandSenderExtendedDelegate.ResetCounter(); + PendingResponseTrackerImpl pendingResponseTracker; + app::CommandSender commandSender(kCommandSenderTestOnlyMarker, &mockCommandSenderExtendedDelegate, &ctx.GetExchangeManager(), + &pendingResponseTracker); + + app::CommandSender::ConfigParameters configParameters; + configParameters.SetRemoteMaxPathsPerInvoke(2); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.SetCommandSenderConfig(configParameters)); - size_t numberOfCommandsToSend = 2; + uint16_t numberOfCommandsToSend = 2; { CommandPathParams requestCommandPaths[] = { MakeTestCommandPath(kTestCommandIdWithData), MakeTestCommandPath(kTestCommandIdCommandSpecificResponse), }; - commandSender.AllocateBuffer(); - - // TODO(#30453): CommandSender does support sending multiple commands, update this test to use that. - for (size_t i = 0; i < numberOfCommandsToSend; i++) + for (uint16_t i = 0; i < numberOfCommandsToSend; i++) { - InvokeRequests::Builder & invokeRequests = commandSender.mInvokeRequestBuilder.GetInvokeRequests(); - CommandDataIB::Builder & invokeRequest = invokeRequests.CreateCommandData(); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequests.GetError()); - CommandPathIB::Builder & path = invokeRequest.CreatePath(); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.GetError()); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == path.Encode(requestCommandPaths[i])); - NL_TEST_ASSERT(apSuite, - CHIP_NO_ERROR == - invokeRequest.GetWriter()->StartContainer(TLV::ContextTag(CommandDataIB::Tag::kFields), - TLV::kTLVType_Structure, - commandSender.mDataElementContainerType)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.GetWriter()->PutBoolean(chip::TLV::ContextTag(1), true)); + app::CommandSender::PrepareCommandParameters prepareCommandParams; + prepareCommandParams.SetStartDataStruct(true); + prepareCommandParams.SetCommandRef(i); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.PrepareCommand(requestCommandPaths[i], prepareCommandParams)); NL_TEST_ASSERT(apSuite, - CHIP_NO_ERROR == invokeRequest.GetWriter()->EndContainer(commandSender.mDataElementContainerType)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.Ref(static_cast(i))); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.EndOfCommandDataIB()); + CHIP_NO_ERROR == commandSender.GetCommandDataIBTLVWriter()->PutBoolean(chip::TLV::ContextTag(1), true)); + app::CommandSender::FinishCommandParameters finishCommandParams; + finishCommandParams.SetEndDataStruct(true); + finishCommandParams.SetCommandRef(i); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.FinishCommand(finishCommandParams)); } - - commandSender.MoveToState(app::CommandSender::State::AddedCommand); } - BasicCommandPathRegistry<4> mBasicCommandPathRegistry; - CommandHandler commandHandler(kCommandHandlerTestOnlyMarker, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); + CommandHandler commandHandler(&mockCommandHandlerDelegate); TestExchangeDelegate delegate; auto exchange = ctx.NewExchangeToAlice(&delegate, false); commandHandler.mResponseSender.SetExchangeContext(exchange); @@ -1715,9 +1749,9 @@ void TestCommandInteraction::TestCommandHandlerRejectMultipleCommandsWhenHandler commandDispatchedCount = 0; InteractionModel::Status status = commandHandler.ProcessInvokeRequest(std::move(commandDatabuf), false); - NL_TEST_ASSERT(apSuite, status == InteractionModel::Status::Success); + NL_TEST_ASSERT(apSuite, status == InteractionModel::Status::InvalidAction); - NL_TEST_ASSERT(apSuite, commandDispatchedCount == 2); + NL_TEST_ASSERT(apSuite, commandDispatchedCount == 0); // // Ordinarily, the ExchangeContext will close itself on a responder exchange when unwinding back from an @@ -1735,39 +1769,35 @@ void TestCommandInteraction::TestCommandHandlerAcceptMultipleCommands(nlTestSuit CHIP_ERROR err = CHIP_NO_ERROR; isCommandDispatched = false; - mockCommandSenderDelegate.ResetCounter(); - // Using commandSender to help build afterward we take the buffer to feed into standalone CommandHandler - app::CommandSender commandSender(&mockCommandSenderDelegate, &ctx.GetExchangeManager()); + mockCommandSenderExtendedDelegate.ResetCounter(); + PendingResponseTrackerImpl pendingResponseTracker; + app::CommandSender commandSender(kCommandSenderTestOnlyMarker, &mockCommandSenderExtendedDelegate, &ctx.GetExchangeManager(), + &pendingResponseTracker); - size_t numberOfCommandsToSend = 2; + app::CommandSender::ConfigParameters configParameters; + configParameters.SetRemoteMaxPathsPerInvoke(2); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.SetCommandSenderConfig(configParameters)); + + uint16_t numberOfCommandsToSend = 2; { CommandPathParams requestCommandPaths[] = { MakeTestCommandPath(kTestCommandIdWithData), MakeTestCommandPath(kTestCommandIdCommandSpecificResponse), }; - commandSender.AllocateBuffer(); - - // TODO(#30453): CommandSender does support sending multiple commands, update this test to use that. - for (size_t i = 0; i < numberOfCommandsToSend; i++) + for (uint16_t i = 0; i < numberOfCommandsToSend; i++) { - InvokeRequests::Builder & invokeRequests = commandSender.mInvokeRequestBuilder.GetInvokeRequests(); - CommandDataIB::Builder & invokeRequest = invokeRequests.CreateCommandData(); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequests.GetError()); - CommandPathIB::Builder & path = invokeRequest.CreatePath(); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.GetError()); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == path.Encode(requestCommandPaths[i])); + app::CommandSender::PrepareCommandParameters prepareCommandParams; + prepareCommandParams.SetStartDataStruct(true); + prepareCommandParams.SetCommandRef(i); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.PrepareCommand(requestCommandPaths[i], prepareCommandParams)); NL_TEST_ASSERT(apSuite, - CHIP_NO_ERROR == - invokeRequest.GetWriter()->StartContainer(TLV::ContextTag(CommandDataIB::Tag::kFields), - TLV::kTLVType_Structure, - commandSender.mDataElementContainerType)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.GetWriter()->PutBoolean(chip::TLV::ContextTag(1), true)); - NL_TEST_ASSERT(apSuite, - CHIP_NO_ERROR == invokeRequest.GetWriter()->EndContainer(commandSender.mDataElementContainerType)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.Ref(static_cast(i))); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == invokeRequest.EndOfCommandDataIB()); + CHIP_NO_ERROR == commandSender.GetCommandDataIBTLVWriter()->PutBoolean(chip::TLV::ContextTag(1), true)); + app::CommandSender::FinishCommandParameters finishCommandParams; + finishCommandParams.SetEndDataStruct(true); + finishCommandParams.SetCommandRef(i); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == commandSender.FinishCommand(finishCommandParams)); } commandSender.MoveToState(app::CommandSender::State::AddedCommand); @@ -1784,6 +1814,7 @@ void TestCommandInteraction::TestCommandHandlerAcceptMultipleCommands(nlTestSuit err = commandSender.Finalize(commandDatabuf); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + sendResponse = true; mockCommandHandlerDelegate.ResetCounter(); commandDispatchedCount = 0; @@ -1810,11 +1841,11 @@ void TestCommandInteraction::TestCommandHandler_FillUpInvokeResponseMessageWhere commandHandler.mReserveSpaceForMoreChunkMessages = true; ConcreteCommandPath requestCommandPath1 = { kTestEndpointId, kTestClusterId, kTestCommandIdFillResponseMessage }; ConcreteCommandPath requestCommandPath2 = { kTestEndpointId, kTestClusterId, kTestCommandIdCommandSpecificResponse }; - Optional commandRef; - commandRef.SetValue(1); - mBasicCommandPathRegistry.Add(requestCommandPath1, commandRef); - commandRef.SetValue(2); - mBasicCommandPathRegistry.Add(requestCommandPath2, commandRef); + + CHIP_ERROR err = mBasicCommandPathRegistry.Add(requestCommandPath1, MakeOptional(static_cast(1))); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + err = mBasicCommandPathRegistry.Add(requestCommandPath2, MakeOptional(static_cast(2))); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); uint32_t sizeToLeave = 0; FillCurrentInvokeResponseBuffer(apSuite, &commandHandler, requestCommandPath1, sizeToLeave); @@ -1836,11 +1867,11 @@ void TestCommandInteraction::TestCommandHandler_FillUpInvokeResponseMessageWhere commandHandler.mReserveSpaceForMoreChunkMessages = true; ConcreteCommandPath requestCommandPath1 = { kTestEndpointId, kTestClusterId, kTestCommandIdFillResponseMessage }; ConcreteCommandPath requestCommandPath2 = { kTestEndpointId, kTestClusterId, kTestCommandIdCommandSpecificResponse }; - Optional commandRef; - commandRef.SetValue(1); - mBasicCommandPathRegistry.Add(requestCommandPath1, commandRef); - commandRef.SetValue(2); - mBasicCommandPathRegistry.Add(requestCommandPath2, commandRef); + + CHIP_ERROR err = mBasicCommandPathRegistry.Add(requestCommandPath1, MakeOptional(static_cast(1))); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + err = mBasicCommandPathRegistry.Add(requestCommandPath2, MakeOptional(static_cast(2))); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); uint32_t sizeToLeave = 0; FillCurrentInvokeResponseBuffer(apSuite, &commandHandler, requestCommandPath1, sizeToLeave); @@ -1862,11 +1893,11 @@ void TestCommandInteraction::TestCommandHandler_FillUpInvokeResponseMessageWhere commandHandler.mReserveSpaceForMoreChunkMessages = true; ConcreteCommandPath requestCommandPath1 = { kTestEndpointId, kTestClusterId, kTestCommandIdFillResponseMessage }; ConcreteCommandPath requestCommandPath2 = { kTestEndpointId, kTestClusterId, kTestCommandIdCommandSpecificResponse }; - Optional commandRef; - commandRef.SetValue(1); - mBasicCommandPathRegistry.Add(requestCommandPath1, commandRef); - commandRef.SetValue(2); - mBasicCommandPathRegistry.Add(requestCommandPath2, commandRef); + + CHIP_ERROR err = mBasicCommandPathRegistry.Add(requestCommandPath1, MakeOptional(static_cast(1))); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + err = mBasicCommandPathRegistry.Add(requestCommandPath2, MakeOptional(static_cast(2))); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); uint32_t sizeToLeave = 0; FillCurrentInvokeResponseBuffer(apSuite, &commandHandler, requestCommandPath1, sizeToLeave); @@ -1874,7 +1905,7 @@ void TestCommandInteraction::TestCommandHandler_FillUpInvokeResponseMessageWhere NL_TEST_ASSERT(apSuite, remainingSize == sizeToLeave); uint32_t sizeToFill = 50; - CHIP_ERROR err = commandHandler.AddResponseData(requestCommandPath2, ForcedSizeBuffer(sizeToFill)); + err = commandHandler.AddResponseData(requestCommandPath2, ForcedSizeBuffer(sizeToFill)); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); remainingSize = commandHandler.mInvokeResponseBuilder.GetWriter()->GetRemainingFreeLength(); @@ -1938,7 +1969,9 @@ const nlTest sTests[] = NL_TEST_DEF("TestCommandHandlerWithProcessReceivedNotExistCommand", chip::app::TestCommandInteraction::TestCommandHandlerWithProcessReceivedNotExistCommand), NL_TEST_DEF("TestCommandHandlerWithProcessReceivedEmptyDataMsg", chip::app::TestCommandInteraction::TestCommandHandlerWithProcessReceivedEmptyDataMsg), NL_TEST_DEF("TestCommandHandlerRejectMultipleIdenticalCommands", chip::app::TestCommandInteraction::TestCommandHandlerRejectMultipleIdenticalCommands), +#if CONFIG_BUILD_FOR_HOST_UNIT_TEST NL_TEST_DEF("TestCommandHandlerRejectsMultipleCommandsWithIdenticalCommandRef", chip::app::TestCommandInteraction::TestCommandHandlerRejectsMultipleCommandsWithIdenticalCommandRef), +#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST NL_TEST_DEF("TestCommandHandlerRejectMultipleCommandsWhenHandlerOnlySupportsOne", chip::app::TestCommandInteraction::TestCommandHandlerRejectMultipleCommandsWhenHandlerOnlySupportsOne), NL_TEST_DEF("TestCommandHandlerAcceptMultipleCommands", chip::app::TestCommandInteraction::TestCommandHandlerAcceptMultipleCommands), NL_TEST_DEF("TestCommandHandler_FillUpInvokeResponseMessageWhereSecondResponseIsStatusResponse", chip::app::TestCommandInteraction::TestCommandHandler_FillUpInvokeResponseMessageWhereSecondResponseIsStatusResponse), diff --git a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml index 259a59dae3ead5..ae39f69156ef86 100644 --- a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml +++ b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml @@ -74,10 +74,6 @@ limitations under the License. ACTIVE_LOCALE SUPPORTED_LOCALES - - HOUR_FORMAT - - UP_TIME @@ -1417,7 +1413,6 @@ limitations under the License. IDENTIFY_TYPE Identify IdentifyQuery - TriggerEffect DEVICE_TYPE_LIST @@ -1475,7 +1470,6 @@ limitations under the License. IDENTIFY_TYPE Identify IdentifyQuery - TriggerEffect DEVICE_TYPE_LIST