From 3502846bafc579857ccf92a98525bed2a7193f0e Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 26 Oct 2021 21:49:44 -0400 Subject: [PATCH] Add basic codegen and Encode/Decode support for nullable and optional struct/command/event fields (#10891) * Add basic support for nullable and optional fields. Affects command fields, event fields, struct fields. * Add some unit tests for nullable and optional encode/decode * Add simple optional/nullable end-to-end test. --- .../all-clusters-common/all-clusters-app.zap | 16 + examples/chip-tool/commands/common/Command.h | 30 ++ .../chip-tool/commands/tests/TestCommand.h | 12 + examples/chip-tool/templates/commands.zapt | 2 + .../templates/partials/test_cluster.zapt | 10 +- .../partials/test_cluster_command_value.zapt | 20 +- .../test-cluster-server.cpp | 24 ++ src/app/data-model/Decode.h | 33 ++ src/app/data-model/Encode.h | 33 ++ src/app/data-model/Nullable.h | 56 +++ src/app/tests/TestDataModelSerialization.cpp | 249 +++++++++++ .../tests/suites/TestClusterComplexTypes.yaml | 38 ++ .../common/ClusterTestGeneration.js | 5 +- .../templates/app/cluster-objects.zapt | 10 +- src/app/zap-templates/templates/app/helper.js | 14 + .../zcl/data-model/chip/test-cluster.xml | 103 +++++ .../data_model/controller-clusters.zap | 16 + .../java/zap-generated/CHIPClusters-JNI.cpp | 119 +++++ .../chip/devicecontroller/ChipClusters.java | 14 + .../python/chip/clusters/CHIPClusters.cpp | 9 + .../python/chip/clusters/CHIPClusters.py | 16 + .../python/chip/clusters/Objects.py | 225 ++++++++++ .../CHIP/zap-generated/CHIPCallbackBridge.mm | 10 + .../CHIPCallbackBridge_internal.h | 12 + .../CHIP/zap-generated/CHIPClustersObjc.h | 1 + .../CHIP/zap-generated/CHIPClustersObjc.mm | 8 + src/transport/FabricTable.h | 2 + .../zap-generated/IMClusterCommandHandler.cpp | 9 + .../app-common/zap-generated/af-structs.h | 17 + .../app-common/zap-generated/callback.h | 34 ++ .../zap-generated/cluster-objects.cpp | 408 ++++++++++++++++++ .../zap-generated/cluster-objects.h | 315 +++++++++++++- .../app-common/zap-generated/command-id.h | 4 + .../app-common/zap-generated/ids/Commands.h | 16 + .../zap-generated/cluster/Commands.h | 39 ++ .../chip-tool/zap-generated/test/Commands.h | 74 +++- .../zap-generated/CHIPClientCallbacks.cpp | 16 + .../zap-generated/CHIPClientCallbacks.h | 2 + .../zap-generated/CHIPClusters.cpp | 49 +++ .../zap-generated/CHIPClusters.h | 2 + .../zap-generated/IMClusterCommandHandler.cpp | 67 +++ 41 files changed, 2115 insertions(+), 24 deletions(-) create mode 100644 src/app/data-model/Nullable.h diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index 38335a2bbe64d9..b9264c3005b37f 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -14875,6 +14875,14 @@ "source": "client", "incoming": 1, "outgoing": 0 + }, + { + "name": "TestNullableOptionalRequest", + "code": 15, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 } ], "attributes": [ @@ -14934,6 +14942,14 @@ "source": "server", "incoming": 0, "outgoing": 1 + }, + { + "name": "TestNullableOptionalResponse", + "code": 6, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 } ], "attributes": [ diff --git a/examples/chip-tool/commands/common/Command.h b/examples/chip-tool/commands/common/Command.h index fa2de16f40fc7e..e3da77dd679108 100644 --- a/examples/chip-tool/commands/common/Command.h +++ b/examples/chip-tool/commands/common/Command.h @@ -19,8 +19,10 @@ #pragma once #include "controller/ExampleOperationalCredentialsIssuer.h" +#include #include #include +#include #include #include @@ -151,6 +153,34 @@ class Command return AddArgument(name, min, max, reinterpret_cast *>(out)); } + template + size_t AddArgument(const char * name, chip::Optional * value) + { + // We always require our args to be provided for the moment. + return AddArgument(name, &value->Emplace()); + } + + template + size_t AddArgument(const char * name, int64_t min, uint64_t max, chip::Optional * value) + { + // We always require our args to be provided for the moment. + return AddArgument(name, min, max, &value->Emplace()); + } + + template + size_t AddArgument(const char * name, chip::app::DataModel::Nullable * value) + { + // We always require our args to be provided for the moment. + return AddArgument(name, &value->SetNonNull()); + } + + template + size_t AddArgument(const char * name, int64_t min, uint64_t max, chip::app::DataModel::Nullable * value) + { + // We always require our args to be provided for the moment. + return AddArgument(name, min, max, &value->SetNonNull()); + } + virtual CHIP_ERROR Run() = 0; private: diff --git a/examples/chip-tool/commands/tests/TestCommand.h b/examples/chip-tool/commands/tests/TestCommand.h index ebc5194a9001a1..998f86bf965550 100644 --- a/examples/chip-tool/commands/tests/TestCommand.h +++ b/examples/chip-tool/commands/tests/TestCommand.h @@ -194,6 +194,18 @@ class TestCommand : public CHIPCommand bool CheckValueAsString(const char * itemName, chip::CharSpan current, const char * expected); + template + bool CheckValuePresent(const char * itemName, const chip::Optional & value) + { + if (value.HasValue()) + { + return true; + } + + Exit(std::string(itemName) + " expected to have value but doesn't"); + return false; + } + chip::Callback::Callback mOnDeviceConnectedCallback; chip::Callback::Callback mOnDeviceConnectionFailureCallback; diff --git a/examples/chip-tool/templates/commands.zapt b/examples/chip-tool/templates/commands.zapt index 65d66564f6ec0a..e1e814eb5b5590 100644 --- a/examples/chip-tool/templates/commands.zapt +++ b/examples/chip-tool/templates/commands.zapt @@ -192,6 +192,8 @@ static void On{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}Success(v {{~#*inline "field"}}data.{{asLowerCamelCase label}}{{/inline~}} {{#if isArray}} ChipLogProgress(Zcl, " {{label}}: Array printing is not implemented yet."); + {{else if isOptional}} + ChipLogProgress(Zcl, " {{label}}: Optional printing is not implemented yet."); {{else if (isOctetString type)}} ChipLogProgress(Zcl, " {{label}}: %zu", {{>field}}.size()); {{else if (isCharString type)}} diff --git a/examples/chip-tool/templates/partials/test_cluster.zapt b/examples/chip-tool/templates/partials/test_cluster.zapt index 80f0ed1a2084cf..3ff426f2a28923 100644 --- a/examples/chip-tool/templates/partials/test_cluster.zapt +++ b/examples/chip-tool/templates/partials/test_cluster.zapt @@ -171,8 +171,12 @@ class {{filename}}: public TestCommand VerifyOrReturn(mReceivedReport_{{waitForReport.index}}, Exit("Initial report not received!")); {{/if}} {{#chip_tests_item_response_parameters}} - {{~#*inline "item"}}{{asLowerCamelCase name}}{{/inline}} + {{~#*inline "item"}}{{asLowerCamelCase name}}{{#if isOptional}}.Value(){{/if}}{{/inline}} {{#if hasExpectedValue}} + {{#if isOptional}} + {{~#*inline "item"}}{{asLowerCamelCase name}}{{/inline}} + VerifyOrReturn(CheckValuePresent("{{> item}}", {{> item}})); + {{/if}} VerifyOrReturn(CheckValue {{~#if isList}}AsListLength("{{>item}}", {{>item}}, {{expectedValue.length}}) {{else if isArray}}AsList("{{>item}}", {{>item}}, {{expectedValue}}) @@ -182,6 +186,10 @@ class {{filename}}: public TestCommand ); {{/if}} {{#if hasExpectedConstraints}} + {{#if isOptional}} + {{~#*inline "item"}}{{asLowerCamelCase name}}{{/inline}} + VerifyOrReturn(CheckValuePresent("{{> item}}", {{> item}})); + {{/if}} {{#if expectedConstraints.type}}VerifyOrReturn(CheckConstraintType("{{>item}}", "", "{{expectedConstraints.type}}"));{{/if}} {{~#if expectedConstraints.format}}VerifyOrReturn(CheckConstraintFormat("{{>item}}", "", "{{expectedConstraints.format}}"));{{/if}} {{~#if expectedConstraints.minLength}}VerifyOrReturn(CheckConstraintMinLength("{{>item}}", {{>item}}.size(), {{expectedConstraints.minLength}}));{{/if}} diff --git a/examples/chip-tool/templates/partials/test_cluster_command_value.zapt b/examples/chip-tool/templates/partials/test_cluster_command_value.zapt index f9808323bf1cbf..de99a1553ae79d 100644 --- a/examples/chip-tool/templates/partials/test_cluster_command_value.zapt +++ b/examples/chip-tool/templates/partials/test_cluster_command_value.zapt @@ -1,7 +1,21 @@ -{{#if isArray}} +{{#if isOptional}} + {{#if ignore}} + {{>commandValue ns=ns container=(concat container ".Emplace()") definedValue=definedValue type=type isOptional=false ignore=true}} + {{else}} + {{>commandValue ns=ns container=(concat container "." label ".Emplace()") definedValue=definedValue type=type isOptional=false ignore=true}} + {{/if}} +{{else if isNullable}} + {{#if ignore}} + {{>commandValue ns=ns container=(concat container ".SetNonNull()") definedValue=definedValue type=type isNullable=false ignore=true}} + {{else}} + {{>commandValue ns=ns container=(concat container "." label ".SetNonNull()") definedValue=definedValue type=type isNullable=false ignore=true}} + {{/if}} +{{else if isArray}} - {{! forceNotList=true because we really want the type of a single item here }} - {{zapTypeToEncodableClusterObjectType type ns=ns forceNotList=true}} {{asLowerCamelCase label}}List[{{definedValue.length}}]; + {{! forceNotList=true because we really want the type of a single item here. + Similarly, forceNotOptional=true and forceNotNullable=true because we + have accounted for those already. }} + {{zapTypeToEncodableClusterObjectType type ns=ns forceNotList=true forceNotNullable=true forceNotOptional=true}} {{asLowerCamelCase label}}List[{{definedValue.length}}]; {{#each definedValue}} {{>commandValue ns=../ns container=(concat (asLowerCamelCase ../label) "List[" @index "]") definedValue=. type=../type ignore=true}} {{/each}} diff --git a/src/app/clusters/test-cluster-server/test-cluster-server.cpp b/src/app/clusters/test-cluster-server/test-cluster-server.cpp index d971c1b49eac4f..adad9add1e7ac7 100644 --- a/src/app/clusters/test-cluster-server/test-cluster-server.cpp +++ b/src/app/clusters/test-cluster-server/test-cluster-server.cpp @@ -430,6 +430,30 @@ bool emberAfTestClusterClusterTestEnumsRequestCallback(CommandHandler * commandO return true; } +bool emberAfTestClusterClusterTestNullableOptionalRequestCallback( + CommandHandler * commandObj, ConcreteCommandPath const & commandPath, + Commands::TestNullableOptionalRequest::DecodableType const & commandData) +{ + Commands::TestNullableOptionalResponse::Type response; + response.wasPresent = commandData.arg1.HasValue(); + if (response.wasPresent) + { + bool wasNull = commandData.arg1.Value().IsNull(); + response.wasNull.SetValue(wasNull); + if (!wasNull) + { + response.value.SetValue(commandData.arg1.Value().Value()); + } + } + + CHIP_ERROR err = commandObj->AddResponseData(commandPath, response); + if (err != CHIP_NO_ERROR) + { + emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_FAILURE); + } + return true; +} + // ----------------------------------------------------------------------------- // Plugin initialization diff --git a/src/app/data-model/Decode.h b/src/app/data-model/Decode.h index d4367ab1ea55b3..3131682f1f10cc 100644 --- a/src/app/data-model/Decode.h +++ b/src/app/data-model/Decode.h @@ -18,9 +18,11 @@ #pragma once +#include #include #include #include +#include namespace chip { namespace app { @@ -93,6 +95,37 @@ CHIP_ERROR Decode(TLV::TLVReader & reader, X & x) return x.Decode(reader); } +/* + * @brief + * + * Decodes an optional value (struct field, command field, event field). + */ +template +CHIP_ERROR Decode(TLV::TLVReader & reader, Optional & x) +{ + // If we are calling this, it means we found the right tag, so just decode + // the item. + return Decode(reader, x.Emplace()); +} + +/* + * @brief + * + * Decodes a nullable value. + */ +template +CHIP_ERROR Decode(TLV::TLVReader & reader, Nullable & x) +{ + if (reader.GetType() == TLV::kTLVType_Null) + { + x.SetNull(); + return CHIP_NO_ERROR; + } + + // We have a value; decode it. + return Decode(reader, x.SetNonNull()); +} + } // namespace DataModel } // namespace app } // namespace chip diff --git a/src/app/data-model/Encode.h b/src/app/data-model/Encode.h index 5630b10c9b08f5..d4556b0d43880e 100644 --- a/src/app/data-model/Encode.h +++ b/src/app/data-model/Encode.h @@ -18,7 +18,9 @@ #pragma once +#include #include +#include namespace chip { namespace app { @@ -78,6 +80,37 @@ CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, const X & x) return x.Encode(writer, tag); } +/* + * @brief + * + * Encodes an optional value (struct field, command field, event field). + */ +template +CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, const Optional & x) +{ + if (x.HasValue()) + { + return Encode(writer, tag, x.Value()); + } + // If no value, just do nothing. + return CHIP_NO_ERROR; +} + +/* + * @brief + * + * Encodes a nullable value. + */ +template +CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, const Nullable & x) +{ + if (x.IsNull()) + { + return writer.PutNull(tag); + } + return Encode(writer, tag, x.Value()); +} + } // namespace DataModel } // namespace app } // namespace chip diff --git a/src/app/data-model/Nullable.h b/src/app/data-model/Nullable.h new file mode 100644 index 00000000000000..50efceb7aa6f95 --- /dev/null +++ b/src/app/data-model/Nullable.h @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace chip { +namespace app { +namespace DataModel { + +/* + * Dedicated type for nullable things, to differentiate them from optional + * things. + */ +template +struct Nullable : protected Optional +{ + // + // The following 'using' statement is needed to make visible + // all constructors of the base class within this derived class. + // + using Optional::Optional; + + // Pull in APIs that make sense on Nullable with the same names as on + // Optional. + using Optional::Value; + + constexpr void SetNull() { Optional::ClearValue(); } + constexpr bool IsNull() const { return !Optional::HasValue(); } + + template + constexpr T & SetNonNull(Args &&... args) + { + return Optional::Emplace(std::forward(args)...); + } +}; + +} // namespace DataModel +} // namespace app +} // namespace chip diff --git a/src/app/tests/TestDataModelSerialization.cpp b/src/app/tests/TestDataModelSerialization.cpp index 9ad606016c76b1..f50ad5f7774ff3 100644 --- a/src/app/tests/TestDataModelSerialization.cpp +++ b/src/app/tests/TestDataModelSerialization.cpp @@ -23,6 +23,8 @@ */ #include +#include +#include #include #include #include @@ -50,8 +52,19 @@ class TestDataModelSerialization static void TestDataModelSerialization_InvalidSimpleFieldTypes(nlTestSuite * apSuite, void * apContext); static void TestDataModelSerialization_InvalidListType(nlTestSuite * apSuite, void * apContext); + static void NullablesOptionalsStruct(nlTestSuite * apSuite, void * apContext); + static void NullablesOptionalsCommand(nlTestSuite * apSuite, void * apContext); + void Shutdown(); +protected: + // Helper functions + template + static void NullablesOptionalsEncodeDecodeCheck(nlTestSuite * apSuite, void * apContext, bool encodeNulls, bool encodeValues); + + template + static void NullablesOptionalsEncodeDecodeCheck(nlTestSuite * apSuite, void * apContext); + private: void SetupBuf(); void DumpBuf(); @@ -847,6 +860,240 @@ void TestDataModelSerialization::TestDataModelSerialization_InvalidListType(nlTe } } +namespace { +bool SimpleStructsEqual(const TestCluster::Structs::SimpleStruct::Type & s1, const TestCluster::Structs::SimpleStruct::Type & s2) +{ + return s1.a == s2.a && s1.b == s2.b && s1.c == s2.c && s1.d.data_equal(s2.d) && s1.e.data_equal(s2.e) && s1.f == s2.f; +} + +template +bool ListsEqual(const DataModel::DecodableList & list1, const DataModel::List & list2) +{ + auto iter1 = list1.begin(); + auto iter2 = list2.begin(); + auto end2 = list2.end(); + while (iter1.Next()) + { + if (iter2 == end2) + { + // list2 too small + return false; + } + + if (iter1.GetValue() != *iter2) + { + return false; + } + ++iter2; + } + if (iter1.GetStatus() != CHIP_NO_ERROR) + { + // Failed to decode + return false; + } + if (iter2 != end2) + { + // list1 too small + return false; + } + return true; +} + +} // anonymous namespace + +template +void TestDataModelSerialization::NullablesOptionalsEncodeDecodeCheck(nlTestSuite * apSuite, void * apContext, bool encodeNulls, + bool encodeValues) +{ + auto * _this = static_cast(apContext); + + _this->mpSuite = apSuite; + _this->SetupBuf(); + + const char structStr[] = "something"; + const uint8_t structBytes[] = { 1, 8, 17 }; + TestCluster::Structs::SimpleStruct::Type myStruct; + myStruct.a = 17; + myStruct.b = true; +#ifdef CHIP_USE_ENUM_CLASS_FOR_IM_ENUM + myStruct.c = TestCluster::SimpleEnum::kValueB; +#else // CHIP_USE_ENUM_CLASS_FOR_IM_ENUM + myStruct.c = EMBER_ZCL_SIMPLE_ENUM_VALUE_B; +#endif // CHIP_USE_ENUM_CLASS_FOR_IM_ENUM + myStruct.d = ByteSpan(structBytes); + myStruct.e = CharSpan(structStr, strlen(structStr)); + myStruct.f = TestCluster::SimpleBitmap(2); + +#ifdef CHIP_USE_ENUM_CLASS_FOR_IM_ENUM + TestCluster::SimpleEnum enumListVals[] = { TestCluster::SimpleEnum::kValueA, TestCluster::SimpleEnum::kValueC }; +#else // CHIP_USE_ENUM_CLASS_FOR_IM_ENUM + TestCluster::SimpleEnum enumListVals[] = { EMBER_ZCL_SIMPLE_ENUM_VALUE_A, EMBER_ZCL_SIMPLE_ENUM_VALUE_C }; +#endif // CHIP_USE_ENUM_CLASS_FOR_IM_ENUM + DataModel::List enumList(enumListVals); + + // Encode + { + // str needs to live until we call DataModel::Encode. + const char str[] = "abc"; + CharSpan strSpan(str, strlen(str)); + Encodable encodable; + if (encodeNulls) + { + encodable.nullableInt.SetNull(); + encodable.nullableOptionalInt.Emplace().SetNull(); + + encodable.nullableString.SetNull(); + encodable.nullableOptionalString.Emplace().SetNull(); + + encodable.nullableStruct.SetNull(); + encodable.nullableOptionalStruct.Emplace().SetNull(); + + encodable.nullableList.SetNull(); + encodable.nullableOptionalList.Emplace().SetNull(); + } + else if (encodeValues) + { + encodable.nullableInt.SetNonNull(static_cast(5u)); + encodable.optionalInt.Emplace(static_cast(6u)); + encodable.nullableOptionalInt.Emplace().SetNonNull() = 7; + + encodable.nullableString.SetNonNull(strSpan); + encodable.optionalString.Emplace() = strSpan; + encodable.nullableOptionalString.Emplace().SetNonNull(strSpan); + + encodable.nullableStruct.SetNonNull(myStruct); + encodable.optionalStruct.Emplace(myStruct); + encodable.nullableOptionalStruct.Emplace().SetNonNull(myStruct); + + encodable.nullableList.SetNonNull() = enumList; + encodable.optionalList.Emplace(enumList); + encodable.nullableOptionalList.Emplace().SetNonNull(enumList); + } + else + { + // Just encode the non-optionals, as null. + encodable.nullableInt.SetNull(); + encodable.nullableString.SetNull(); + encodable.nullableStruct.SetNull(); + encodable.nullableList.SetNull(); + } + + CHIP_ERROR err = DataModel::Encode(_this->mWriter, TLV::AnonymousTag, encodable); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + err = _this->mWriter.Finalize(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + } + + // Decode + { + _this->SetupReader(); + + Decodable decodable; + CHIP_ERROR err = DataModel::Decode(_this->mReader, decodable); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + if (encodeNulls) + { + NL_TEST_ASSERT(apSuite, decodable.nullableInt.IsNull()); + NL_TEST_ASSERT(apSuite, !decodable.optionalInt.HasValue()); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalInt.HasValue()); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalInt.Value().IsNull()); + + NL_TEST_ASSERT(apSuite, decodable.nullableString.IsNull()); + NL_TEST_ASSERT(apSuite, !decodable.optionalString.HasValue()); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalString.HasValue()); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalString.Value().IsNull()); + + NL_TEST_ASSERT(apSuite, decodable.nullableStruct.IsNull()); + NL_TEST_ASSERT(apSuite, !decodable.optionalStruct.HasValue()); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalStruct.HasValue()); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalStruct.Value().IsNull()); + + NL_TEST_ASSERT(apSuite, decodable.nullableList.IsNull()); + NL_TEST_ASSERT(apSuite, !decodable.optionalList.HasValue()); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalList.HasValue()); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalList.Value().IsNull()); + } + else if (encodeValues) + { + const char str[] = "abc"; + CharSpan strSpan(str, strlen(str)); + + NL_TEST_ASSERT(apSuite, !decodable.nullableInt.IsNull()); + NL_TEST_ASSERT(apSuite, decodable.nullableInt.Value() == 5); + NL_TEST_ASSERT(apSuite, decodable.optionalInt.HasValue()); + NL_TEST_ASSERT(apSuite, decodable.optionalInt.Value() == 6); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalInt.HasValue()); + NL_TEST_ASSERT(apSuite, !decodable.nullableOptionalInt.Value().IsNull()); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalInt.Value().Value() == 7); + + NL_TEST_ASSERT(apSuite, !decodable.nullableString.IsNull()); + NL_TEST_ASSERT(apSuite, decodable.nullableString.Value().data_equal(strSpan)); + NL_TEST_ASSERT(apSuite, decodable.optionalString.HasValue()); + NL_TEST_ASSERT(apSuite, decodable.optionalString.Value().data_equal(strSpan)); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalString.HasValue()); + NL_TEST_ASSERT(apSuite, !decodable.nullableOptionalString.Value().IsNull()); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalString.Value().Value().data_equal(strSpan)); + + NL_TEST_ASSERT(apSuite, !decodable.nullableStruct.IsNull()); + NL_TEST_ASSERT(apSuite, SimpleStructsEqual(decodable.nullableStruct.Value(), myStruct)); + NL_TEST_ASSERT(apSuite, decodable.optionalStruct.HasValue()); + NL_TEST_ASSERT(apSuite, SimpleStructsEqual(decodable.optionalStruct.Value(), myStruct)); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalStruct.HasValue()); + NL_TEST_ASSERT(apSuite, !decodable.nullableOptionalStruct.Value().IsNull()); + NL_TEST_ASSERT(apSuite, SimpleStructsEqual(decodable.nullableOptionalStruct.Value().Value(), myStruct)); + + NL_TEST_ASSERT(apSuite, !decodable.nullableList.IsNull()); + NL_TEST_ASSERT(apSuite, ListsEqual(decodable.nullableList.Value(), enumList)); + NL_TEST_ASSERT(apSuite, decodable.optionalList.HasValue()); + NL_TEST_ASSERT(apSuite, ListsEqual(decodable.optionalList.Value(), enumList)); + NL_TEST_ASSERT(apSuite, decodable.nullableOptionalList.HasValue()); + NL_TEST_ASSERT(apSuite, !decodable.nullableOptionalList.Value().IsNull()); + NL_TEST_ASSERT(apSuite, ListsEqual(decodable.nullableOptionalList.Value().Value(), enumList)); + } + else + { + NL_TEST_ASSERT(apSuite, decodable.nullableInt.IsNull()); + NL_TEST_ASSERT(apSuite, !decodable.optionalInt.HasValue()); + NL_TEST_ASSERT(apSuite, !decodable.nullableOptionalInt.HasValue()); + + NL_TEST_ASSERT(apSuite, decodable.nullableString.IsNull()); + NL_TEST_ASSERT(apSuite, !decodable.optionalString.HasValue()); + NL_TEST_ASSERT(apSuite, !decodable.nullableOptionalString.HasValue()); + + NL_TEST_ASSERT(apSuite, decodable.nullableStruct.IsNull()); + NL_TEST_ASSERT(apSuite, !decodable.optionalStruct.HasValue()); + NL_TEST_ASSERT(apSuite, !decodable.nullableOptionalStruct.HasValue()); + + NL_TEST_ASSERT(apSuite, decodable.nullableList.IsNull()); + NL_TEST_ASSERT(apSuite, !decodable.optionalList.HasValue()); + NL_TEST_ASSERT(apSuite, !decodable.nullableOptionalList.HasValue()); + } + } +} + +template +void TestDataModelSerialization::NullablesOptionalsEncodeDecodeCheck(nlTestSuite * apSuite, void * apContext) +{ + NullablesOptionalsEncodeDecodeCheck(apSuite, apContext, false, false); + NullablesOptionalsEncodeDecodeCheck(apSuite, apContext, true, false); + NullablesOptionalsEncodeDecodeCheck(apSuite, apContext, false, true); +} + +void TestDataModelSerialization::NullablesOptionalsStruct(nlTestSuite * apSuite, void * apContext) +{ + using EncType = TestCluster::Structs::NullablesAndOptionalsStruct::Type; + using DecType = TestCluster::Structs::NullablesAndOptionalsStruct::DecodableType; + NullablesOptionalsEncodeDecodeCheck(apSuite, apContext); +} + +void TestDataModelSerialization::NullablesOptionalsCommand(nlTestSuite * apSuite, void * apContext) +{ + using EncType = TestCluster::Commands::TestComplexNullableOptionalRequest::Type; + using DecType = TestCluster::Commands::TestComplexNullableOptionalRequest::DecodableType; + NullablesOptionalsEncodeDecodeCheck(apSuite, apContext); +} + int Initialize(void * apSuite) { VerifyOrReturnError(chip::Platform::MemoryInit() == CHIP_NO_ERROR, FAILURE); @@ -873,6 +1120,8 @@ const nlTest sTests[] = NL_TEST_DEF("TestDataModelSerialization_ExtraField", TestDataModelSerialization::TestDataModelSerialization_ExtraField), NL_TEST_DEF("TestDataModelSerialization_InvalidSimpleFieldTypes", TestDataModelSerialization::TestDataModelSerialization_InvalidSimpleFieldTypes), NL_TEST_DEF("TestDataModelSerialization_InvalidListType", TestDataModelSerialization::TestDataModelSerialization_InvalidListType), + NL_TEST_DEF("TestDataModelSerialization_NullablesOptionalsStruct", TestDataModelSerialization::NullablesOptionalsStruct), + NL_TEST_DEF("TestDataModelSerialization_NullablesOptionalsCommand", TestDataModelSerialization::NullablesOptionalsCommand), NL_TEST_SENTINEL() }; // clang-format on diff --git a/src/app/tests/suites/TestClusterComplexTypes.yaml b/src/app/tests/suites/TestClusterComplexTypes.yaml index 4155a85e88d1a0..577fc1fa1fde6c 100644 --- a/src/app/tests/suites/TestClusterComplexTypes.yaml +++ b/src/app/tests/suites/TestClusterComplexTypes.yaml @@ -390,3 +390,41 @@ tests: ] response: error: 1 + + # Tests for Nullables and Optionals + + - label: "Send Test Command with optional arg set." + command: "testNullableOptionalRequest" + arguments: + values: + - name: "arg1" + value: 5 + response: + values: + - name: "wasPresent" + value: true + - name: "wasNull" + value: false + - name: "value" + value: 5 + + - label: "Send Test Command without its optional arg." + command: "testNullableOptionalRequest" + response: + values: + - name: "wasPresent" + value: false + + - label: "Send Test Command with optional arg set to null." + disabled: true + command: "testNullableOptionalRequest" + arguments: + values: + - name: "arg1" + value: null + response: + values: + - name: "wasPresent" + value: true + - name: "wasNull" + value: false diff --git a/src/app/zap-templates/common/ClusterTestGeneration.js b/src/app/zap-templates/common/ClusterTestGeneration.js index a49f9484d53f81..de8b509440299a 100644 --- a/src/app/zap-templates/common/ClusterTestGeneration.js +++ b/src/app/zap-templates/common/ClusterTestGeneration.js @@ -396,6 +396,9 @@ function chip_tests_item_parameters(options) const expected = commandValues.find(value => value.name.toLowerCase() == commandArg.name.toLowerCase()); if (!expected) { + if (commandArg.isOptional) { + return undefined; + } printErrorAndExit(this, 'Missing "' + commandArg.name + '" in arguments list: \n\t* ' + commandValues.map(command => command.name).join('\n\t* ')); @@ -438,7 +441,7 @@ function chip_tests_item_parameters(options) return commandArg; }); - return commands; + return commands.filter(item => item !== undefined); }); return asBlocks.call(this, promise, options); diff --git a/src/app/zap-templates/templates/app/cluster-objects.zapt b/src/app/zap-templates/templates/app/cluster-objects.zapt index 3a3aa52c7fcc41..ee3e63634b3d32 100644 --- a/src/app/zap-templates/templates/app/cluster-objects.zapt +++ b/src/app/zap-templates/templates/app/cluster-objects.zapt @@ -134,12 +134,14 @@ namespace Attributes { {{/first}} namespace {{asUpperCamelCase label}} { struct TypeInfo { + {{! forceNotOptional=true because the optionality is on the attribute + itself, but we want just the type of the attribute. }} {{#if entryType}} - using Type = {{zapTypeToEncodableClusterObjectType entryType}}; - using DecodableType = {{zapTypeToDecodableClusterObjectType entryType}}; + using Type = {{zapTypeToEncodableClusterObjectType entryType forceNotOptional=true}}; + using DecodableType = {{zapTypeToDecodableClusterObjectType entryType forceNotOptional=true}}; {{else}} - using Type = {{zapTypeToEncodableClusterObjectType type}}; - using DecodableType = {{zapTypeToDecodableClusterObjectType type}}; + using Type = {{zapTypeToEncodableClusterObjectType type forceNotOptional=true}}; + using DecodableType = {{zapTypeToDecodableClusterObjectType type forceNotOptional=true}}; {{/if}} static constexpr ClusterId GetClusterId() { return Clusters::{{asUpperCamelCase parent.name}}::Id; } diff --git a/src/app/zap-templates/templates/app/helper.js b/src/app/zap-templates/templates/app/helper.js index 4e751e771cdabc..a7f66d00b27d0b 100644 --- a/src/app/zap-templates/templates/app/helper.js +++ b/src/app/zap-templates/templates/app/helper.js @@ -381,6 +381,20 @@ async function zapTypeToClusterObjectType(type, isDecodable, options) let listNamespace = options.hash.ns ? "chip::app::" : "" promise = promise.then(typeStr => `${listNamespace}DataModel::${listType}<${typeStr}>`); } + if (this.isNullable && !options.hash.forceNotNullable) { + passByReference = true; + // If we did not have a namespace provided, we can assume we're inside + // chip::app::. + let ns = options.hash.ns ? "chip::app::" : "" + promise = promise.then(typeStr => `${ns}DataModel::Nullable<${typeStr}>`); + } + if (this.isOptional && !options.hash.forceNotOptional) { + passByReference = true; + // If we did not have a namespace provided, we can assume we're inside + // chip::. + let ns = options.hash.ns ? "chip::" : "" + promise = promise.then(typeStr => `${ns}Optional<${typeStr}>`); + } if (options.hash.isArgument && passByReference) { promise = promise.then(typeStr => `const ${typeStr} &`); } diff --git a/src/app/zap-templates/zcl/data-model/chip/test-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/test-cluster.xml index 4696d6b25783ae..4e5abf22ee027c 100644 --- a/src/app/zap-templates/zcl/data-model/chip/test-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/test-cluster.xml @@ -70,6 +70,27 @@ limitations under the License. + + + + + + + + + + + + + + + + + CHIP Test Cluster @@ -260,6 +281,42 @@ limitations under the License. + + + Command that takes an argument which is nullable and optional. The + response returns a boolean indicating whether the argument was present, + if that's true a boolean indicating whether the argument was null, and + if that' false the argument it received. + + + + + + + Command that takes various arguments which can be nullable and/or optional. The + response returns information about which things were received and what + their state was. + + + + + + + + + + + + + + + Simple response for TestWithResponse with a simple return value @@ -308,6 +365,52 @@ limitations under the License. + + + Delivers information about the argument TestNullableOptionalRequest had. + + + + + + + + + Delivers information about the arguments TestComplexNullableOptionalRequest had. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Example test event diff --git a/src/controller/data_model/controller-clusters.zap b/src/controller/data_model/controller-clusters.zap index 569a7c54a82022..96bb84382a9916 100644 --- a/src/controller/data_model/controller-clusters.zap +++ b/src/controller/data_model/controller-clusters.zap @@ -11007,6 +11007,14 @@ "source": "client", "incoming": 0, "outgoing": 1 + }, + { + "name": "TestNullableOptionalRequest", + "code": 15, + "mfgCode": null, + "source": "client", + "incoming": 0, + "outgoing": 1 } ], "attributes": [ @@ -11066,6 +11074,14 @@ "source": "server", "incoming": 1, "outgoing": 0 + }, + { + "name": "TestNullableOptionalResponse", + "code": 6, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 0 } ], "attributes": [ diff --git a/src/controller/java/zap-generated/CHIPClusters-JNI.cpp b/src/controller/java/zap-generated/CHIPClusters-JNI.cpp index df3c922d48cb6b..e1920f5fcae144 100644 --- a/src/controller/java/zap-generated/CHIPClusters-JNI.cpp +++ b/src/controller/java/zap-generated/CHIPClusters-JNI.cpp @@ -6039,6 +6039,76 @@ class CHIPTestClusterClusterTestListInt8UReverseResponseCallback jobject javaCallbackRef; }; +class CHIPTestClusterClusterTestNullableOptionalResponseCallback + : public Callback::Callback +{ +public: + CHIPTestClusterClusterTestNullableOptionalResponseCallback(jobject javaCallback) : + Callback::Callback(CallbackFn, this) + { + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + if (env == nullptr) + { + ChipLogError(Zcl, "Could not create global reference for Java callback"); + return; + } + + javaCallbackRef = env->NewGlobalRef(javaCallback); + if (javaCallbackRef == nullptr) + { + ChipLogError(Zcl, "Could not create global reference for Java callback"); + } + } + ~CHIPTestClusterClusterTestNullableOptionalResponseCallback() + { + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + if (env == nullptr) + { + ChipLogError(Zcl, "Could not create global reference for Java callback"); + return; + } + env->DeleteGlobalRef(javaCallbackRef); + }; + + static void CallbackFn(void * context, bool wasPresent, bool wasNull, uint8_t value) + { + chip::DeviceLayer::StackUnlock unlock; + CHIP_ERROR err = CHIP_NO_ERROR; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + jobject javaCallbackRef; + jmethodID javaMethod; + CHIPTestClusterClusterTestNullableOptionalResponseCallback * cppCallback = nullptr; + + VerifyOrExit(env != nullptr, err = CHIP_JNI_ERROR_NO_ENV); + + cppCallback = reinterpret_cast(context); + VerifyOrExit(cppCallback != nullptr, err = CHIP_JNI_ERROR_NULL_OBJECT); + + javaCallbackRef = cppCallback->javaCallbackRef; + VerifyOrExit(javaCallbackRef != nullptr, err = CHIP_NO_ERROR); + + err = JniReferences::GetInstance().FindMethod(env, javaCallbackRef, "onSuccess", "(ZZI)V", &javaMethod); + SuccessOrExit(err); + + env->CallVoidMethod(javaCallbackRef, javaMethod, static_cast(wasPresent), static_cast(wasNull), + static_cast(value)); + + exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Error invoking Java callback: %" CHIP_ERROR_FORMAT, err.Format()); + } + if (cppCallback != nullptr) + { + cppCallback->Cancel(); + delete cppCallback; + } + } + +private: + jobject javaCallbackRef; +}; + class CHIPTestClusterClusterTestSpecificResponseCallback : public Callback::Callback { public: @@ -25397,6 +25467,55 @@ JNI_METHOD(void, TestClusterCluster, testNotHandled)(JNIEnv * env, jobject self, err = cppCluster->TestNotHandled(onSuccess->Cancel(), onFailure->Cancel()); SuccessOrExit(err); +exit: + if (err != CHIP_NO_ERROR) + { + jthrowable exception; + jmethodID method; + + err = JniReferences::GetInstance().FindMethod(env, callback, "onError", "(Ljava/lang/Exception;)V", &method); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Error throwing IllegalStateException %" CHIP_ERROR_FORMAT, err.Format()); + return; + } + + err = CreateIllegalStateException(env, "Error invoking cluster", err, exception); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Error throwing IllegalStateException %" CHIP_ERROR_FORMAT, err.Format()); + return; + } + env->CallVoidMethod(callback, method, exception); + } + else + { + onSuccess.release(); + onFailure.release(); + } +} +JNI_METHOD(void, TestClusterCluster, testNullableOptionalRequest) +(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, jint arg1) +{ + chip::DeviceLayer::StackLock lock; + CHIP_ERROR err = CHIP_NO_ERROR; + TestClusterCluster * cppCluster; + + std::unique_ptr + onSuccess(Platform::New(callback), + Platform::Delete); + std::unique_ptr onFailure( + Platform::New(callback), Platform::Delete); + VerifyOrExit(onSuccess.get() != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(onFailure.get() != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + cppCluster = reinterpret_cast(clusterPtr); + VerifyOrExit(cppCluster != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + err = cppCluster->TestNullableOptionalRequest(onSuccess->Cancel(), onFailure->Cancel(), arg1); + SuccessOrExit(err); + exit: if (err != CHIP_NO_ERROR) { diff --git a/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java b/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java index 8c8d987eccc811..c18ecc64085e13 100644 --- a/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java @@ -5708,6 +5708,11 @@ public void testNotHandled(DefaultClusterCallback callback) { testNotHandled(chipClusterPtr, callback); } + public void testNullableOptionalRequest( + TestNullableOptionalResponseCallback callback, int arg1) { + testNullableOptionalRequest(chipClusterPtr, callback, arg1); + } + public void testSpecific(TestSpecificResponseCallback callback) { testSpecific(chipClusterPtr, callback); } @@ -5747,6 +5752,9 @@ private native void testListStructArgumentRequest( private native void testNotHandled(long chipClusterPtr, DefaultClusterCallback callback); + private native void testNullableOptionalRequest( + long chipClusterPtr, TestNullableOptionalResponseCallback callback, int arg1); + private native void testSpecific(long chipClusterPtr, TestSpecificResponseCallback callback); private native void testStructArgumentRequest( @@ -5782,6 +5790,12 @@ void onSuccess( void onError(Exception error); } + public interface TestNullableOptionalResponseCallback { + void onSuccess(boolean wasPresent, boolean wasNull, int value); + + void onError(Exception error); + } + public interface TestSpecificResponseCallback { void onSuccess(int returnValue); diff --git a/src/controller/python/chip/clusters/CHIPClusters.cpp b/src/controller/python/chip/clusters/CHIPClusters.cpp index ae4439ca46155c..63d5820816204b 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.cpp +++ b/src/controller/python/chip/clusters/CHIPClusters.cpp @@ -6684,6 +6684,15 @@ chip::ChipError::StorageType chip_ime_AppendCommand_TestCluster_TestNotHandled(c cluster.Associate(device, ZCLendpointId); return cluster.TestNotHandled(nullptr, nullptr).AsInteger(); } +chip::ChipError::StorageType chip_ime_AppendCommand_TestCluster_TestNullableOptionalRequest(chip::Controller::Device * device, + chip::EndpointId ZCLendpointId, + chip::GroupId, uint8_t arg1) +{ + VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT.AsInteger()); + chip::Controller::TestClusterCluster cluster; + cluster.Associate(device, ZCLendpointId); + return cluster.TestNullableOptionalRequest(nullptr, nullptr, arg1).AsInteger(); +} chip::ChipError::StorageType chip_ime_AppendCommand_TestCluster_TestSpecific(chip::Controller::Device * device, chip::EndpointId ZCLendpointId, chip::GroupId) { diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index ef7ac88c515259..e7fb06e4e8d89d 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -3145,6 +3145,13 @@ class ChipClusters: "args": { }, }, + 0x0000000F: { + "commandId": 0x0000000F, + "commandName": "TestNullableOptionalRequest", + "args": { + "arg1": "int", + }, + }, 0x00000002: { "commandId": 0x00000002, "commandName": "TestSpecific", @@ -5054,6 +5061,11 @@ def ClusterTestCluster_CommandTestNotHandled(self, device: ctypes.c_void_p, ZCLe device, ZCLendpoint, ZCLgroupid ) + def ClusterTestCluster_CommandTestNullableOptionalRequest(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int, arg1: int): + return self._chipLib.chip_ime_AppendCommand_TestCluster_TestNullableOptionalRequest( + device, ZCLendpoint, ZCLgroupid, arg1 + ) + def ClusterTestCluster_CommandTestSpecific(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int): return self._chipLib.chip_ime_AppendCommand_TestCluster_TestSpecific( device, ZCLendpoint, ZCLgroupid @@ -8836,6 +8848,10 @@ def InitLib(self, chipLib): self._chipLib.chip_ime_AppendCommand_TestCluster_TestNotHandled.argtypes = [ ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16] self._chipLib.chip_ime_AppendCommand_TestCluster_TestNotHandled.restype = ctypes.c_uint32 + # Cluster TestCluster Command TestNullableOptionalRequest + self._chipLib.chip_ime_AppendCommand_TestCluster_TestNullableOptionalRequest.argtypes = [ + ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16, ctypes.c_uint8] + self._chipLib.chip_ime_AppendCommand_TestCluster_TestNullableOptionalRequest.restype = ctypes.c_uint32 # Cluster TestCluster Command TestSpecific self._chipLib.chip_ime_AppendCommand_TestCluster_TestSpecific.argtypes = [ ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16] diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 39c4299412bcc7..2e63dfae23dd23 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -19843,6 +19843,51 @@ def descriptor(cls) -> ClusterObjectDescriptor: E: 'str' = None F: 'int' = None + @dataclass + class NullablesAndOptionalsStruct(ClusterObject): + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor( + Label="NullableInt", Tag=0, Type=uint), + ClusterObjectFieldDescriptor( + Label="OptionalInt", Tag=1, Type=uint), + ClusterObjectFieldDescriptor( + Label="NullableOptionalInt", Tag=2, Type=uint), + ClusterObjectFieldDescriptor( + Label="NullableString", Tag=3, Type=str), + ClusterObjectFieldDescriptor( + Label="OptionalString", Tag=4, Type=str), + ClusterObjectFieldDescriptor( + Label="NullableOptionalString", Tag=5, Type=str), + ClusterObjectFieldDescriptor( + Label="NullableStruct", Tag=6, Type=TestCluster.Structs.SimpleStruct), + ClusterObjectFieldDescriptor( + Label="OptionalStruct", Tag=7, Type=TestCluster.Structs.SimpleStruct), + ClusterObjectFieldDescriptor( + Label="NullableOptionalStruct", Tag=8, Type=TestCluster.Structs.SimpleStruct), + ClusterObjectFieldDescriptor( + Label="NullableList", Tag=9, Type=TestCluster.Enums.SimpleEnum, IsArray=True), + ClusterObjectFieldDescriptor( + Label="OptionalList", Tag=10, Type=TestCluster.Enums.SimpleEnum, IsArray=True), + ClusterObjectFieldDescriptor( + Label="NullableOptionalList", Tag=11, Type=TestCluster.Enums.SimpleEnum, IsArray=True), + ]) + + NullableInt: 'uint' = None + OptionalInt: 'uint' = None + NullableOptionalInt: 'uint' = None + NullableString: 'str' = None + OptionalString: 'str' = None + NullableOptionalString: 'str' = None + NullableStruct: 'TestCluster.Structs.SimpleStruct' = None + OptionalStruct: 'TestCluster.Structs.SimpleStruct' = None + NullableOptionalStruct: 'TestCluster.Structs.SimpleStruct' = None + NullableList: typing.List['TestCluster.Enums.SimpleEnum'] = None + OptionalList: typing.List['TestCluster.Enums.SimpleEnum'] = None + NullableOptionalList: typing.List['TestCluster.Enums.SimpleEnum'] = None + @dataclass class NestedStruct(ClusterObject): @ChipUtility.classproperty @@ -20134,6 +20179,27 @@ def descriptor(cls) -> ClusterObjectDescriptor: Arg5: 'TestCluster.Enums.SimpleEnum' = None Arg6: 'bool' = None + @dataclass + class TestNullableOptionalResponse(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x050F + command_id: typing.ClassVar[int] = 0x0006 + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor( + Label="WasPresent", Tag=0, Type=bool), + ClusterObjectFieldDescriptor( + Label="WasNull", Tag=1, Type=bool), + ClusterObjectFieldDescriptor( + Label="Value", Tag=2, Type=uint), + ]) + + WasPresent: 'bool' = None + WasNull: 'bool' = None + Value: 'uint' = None + @dataclass class TestStructArgumentRequest(ClusterCommand): cluster_id: typing.ClassVar[int] = 0x050F @@ -20149,6 +20215,102 @@ def descriptor(cls) -> ClusterObjectDescriptor: Arg1: 'TestCluster.Structs.SimpleStruct' = None + @dataclass + class TestComplexNullableOptionalResponse(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x050F + command_id: typing.ClassVar[int] = 0x0007 + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor( + Label="NullableIntWasNull", Tag=0, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableIntValue", Tag=1, Type=uint), + ClusterObjectFieldDescriptor( + Label="OptionalIntWasPresent", Tag=2, Type=bool), + ClusterObjectFieldDescriptor( + Label="OptionalIntValue", Tag=3, Type=uint), + ClusterObjectFieldDescriptor( + Label="NullableOptionalIntWasPresent", Tag=4, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableOptionalIntWasNull", Tag=5, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableOptionalIntValue", Tag=6, Type=uint), + ClusterObjectFieldDescriptor( + Label="NullableStringWasNull", Tag=7, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableStringValue", Tag=8, Type=str), + ClusterObjectFieldDescriptor( + Label="OptionalStringWasPresent", Tag=9, Type=bool), + ClusterObjectFieldDescriptor( + Label="OptionalStringValue", Tag=10, Type=str), + ClusterObjectFieldDescriptor( + Label="NullableOptionalStringWasPresent", Tag=11, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableOptionalStringWasNull", Tag=12, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableOptionalStringValue", Tag=13, Type=str), + ClusterObjectFieldDescriptor( + Label="NullableStructWasNull", Tag=14, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableStructValue", Tag=15, Type=TestCluster.Structs.SimpleStruct), + ClusterObjectFieldDescriptor( + Label="OptionalStructWasPresent", Tag=16, Type=bool), + ClusterObjectFieldDescriptor( + Label="OptionalStructValue", Tag=17, Type=TestCluster.Structs.SimpleStruct), + ClusterObjectFieldDescriptor( + Label="NullableOptionalStructWasPresent", Tag=18, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableOptionalStructWasNull", Tag=19, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableOptionalStructValue", Tag=20, Type=TestCluster.Structs.SimpleStruct), + ClusterObjectFieldDescriptor( + Label="NullableListWasNull", Tag=21, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableListValue", Tag=22, Type=TestCluster.Enums.SimpleEnum, IsArray=True), + ClusterObjectFieldDescriptor( + Label="OptionalListWasPresent", Tag=23, Type=bool), + ClusterObjectFieldDescriptor( + Label="OptionalListValue", Tag=24, Type=TestCluster.Enums.SimpleEnum, IsArray=True), + ClusterObjectFieldDescriptor( + Label="NullableOptionalListWasPresent", Tag=25, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableOptionalListWasNull", Tag=26, Type=bool), + ClusterObjectFieldDescriptor( + Label="NullableOptionalListValue", Tag=27, Type=TestCluster.Enums.SimpleEnum, IsArray=True), + ]) + + NullableIntWasNull: 'bool' = None + NullableIntValue: 'uint' = None + OptionalIntWasPresent: 'bool' = None + OptionalIntValue: 'uint' = None + NullableOptionalIntWasPresent: 'bool' = None + NullableOptionalIntWasNull: 'bool' = None + NullableOptionalIntValue: 'uint' = None + NullableStringWasNull: 'bool' = None + NullableStringValue: 'str' = None + OptionalStringWasPresent: 'bool' = None + OptionalStringValue: 'str' = None + NullableOptionalStringWasPresent: 'bool' = None + NullableOptionalStringWasNull: 'bool' = None + NullableOptionalStringValue: 'str' = None + NullableStructWasNull: 'bool' = None + NullableStructValue: 'TestCluster.Structs.SimpleStruct' = None + OptionalStructWasPresent: 'bool' = None + OptionalStructValue: 'TestCluster.Structs.SimpleStruct' = None + NullableOptionalStructWasPresent: 'bool' = None + NullableOptionalStructWasNull: 'bool' = None + NullableOptionalStructValue: 'TestCluster.Structs.SimpleStruct' = None + NullableListWasNull: 'bool' = None + NullableListValue: typing.List['TestCluster.Enums.SimpleEnum'] = None + OptionalListWasPresent: 'bool' = None + OptionalListValue: typing.List['TestCluster.Enums.SimpleEnum'] = None + NullableOptionalListWasPresent: 'bool' = None + NullableOptionalListWasNull: 'bool' = None + NullableOptionalListValue: typing.List['TestCluster.Enums.SimpleEnum'] = None + @dataclass class TestNestedStructArgumentRequest(ClusterCommand): cluster_id: typing.ClassVar[int] = 0x050F @@ -20257,6 +20419,69 @@ def descriptor(cls) -> ClusterObjectDescriptor: Arg1: 'uint' = None Arg2: 'TestCluster.Enums.SimpleEnum' = None + @dataclass + class TestNullableOptionalRequest(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x050F + command_id: typing.ClassVar[int] = 0x000F + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor( + Label="Arg1", Tag=0, Type=uint), + ]) + + Arg1: 'uint' = None + + @dataclass + class TestComplexNullableOptionalRequest(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x050F + command_id: typing.ClassVar[int] = 0x0010 + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor( + Label="NullableInt", Tag=0, Type=uint), + ClusterObjectFieldDescriptor( + Label="OptionalInt", Tag=1, Type=uint), + ClusterObjectFieldDescriptor( + Label="NullableOptionalInt", Tag=2, Type=uint), + ClusterObjectFieldDescriptor( + Label="NullableString", Tag=3, Type=str), + ClusterObjectFieldDescriptor( + Label="OptionalString", Tag=4, Type=str), + ClusterObjectFieldDescriptor( + Label="NullableOptionalString", Tag=5, Type=str), + ClusterObjectFieldDescriptor( + Label="NullableStruct", Tag=6, Type=TestCluster.Structs.SimpleStruct), + ClusterObjectFieldDescriptor( + Label="OptionalStruct", Tag=7, Type=TestCluster.Structs.SimpleStruct), + ClusterObjectFieldDescriptor( + Label="NullableOptionalStruct", Tag=8, Type=TestCluster.Structs.SimpleStruct), + ClusterObjectFieldDescriptor( + Label="NullableList", Tag=9, Type=TestCluster.Enums.SimpleEnum, IsArray=True), + ClusterObjectFieldDescriptor( + Label="OptionalList", Tag=10, Type=TestCluster.Enums.SimpleEnum, IsArray=True), + ClusterObjectFieldDescriptor( + Label="NullableOptionalList", Tag=11, Type=TestCluster.Enums.SimpleEnum, IsArray=True), + ]) + + NullableInt: 'uint' = None + OptionalInt: 'uint' = None + NullableOptionalInt: 'uint' = None + NullableString: 'str' = None + OptionalString: 'str' = None + NullableOptionalString: 'str' = None + NullableStruct: 'TestCluster.Structs.SimpleStruct' = None + OptionalStruct: 'TestCluster.Structs.SimpleStruct' = None + NullableOptionalStruct: 'TestCluster.Structs.SimpleStruct' = None + NullableList: typing.List['TestCluster.Enums.SimpleEnum'] = None + OptionalList: typing.List['TestCluster.Enums.SimpleEnum'] = None + NullableOptionalList: typing.List['TestCluster.Enums.SimpleEnum'] = None + class Attributes: class Boolean(ClusterAttributeDescriptor): @ChipUtility.classproperty diff --git a/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge.mm b/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge.mm index 8e078a71b903d1..830cee257ffc73 100644 --- a/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge.mm +++ b/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge.mm @@ -1288,6 +1288,16 @@ }); }; +void CHIPTestClusterClusterTestNullableOptionalResponseCallbackBridge::OnSuccessFn( + void * context, bool wasPresent, bool wasNull, uint8_t value) +{ + DispatchSuccess(context, @ { + @"wasPresent" : [NSNumber numberWithBool:wasPresent], + @"wasNull" : [NSNumber numberWithBool:wasNull], + @"value" : [NSNumber numberWithUnsignedChar:value], + }); +}; + void CHIPTestClusterClusterTestSpecificResponseCallbackBridge::OnSuccessFn(void * context, uint8_t returnValue) { DispatchSuccess(context, @ { diff --git a/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge_internal.h b/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge_internal.h index e7185ee87c0a23..4417fad4c5b6c3 100644 --- a/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge_internal.h +++ b/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge_internal.h @@ -1298,6 +1298,18 @@ class CHIPTestClusterClusterTestListInt8UReverseResponseCallbackBridge static void OnSuccessFn(void * context, /* TYPE WARNING: array array defaults to */ uint8_t * arg1); }; +class CHIPTestClusterClusterTestNullableOptionalResponseCallbackBridge + : public CHIPCallbackBridge +{ +public: + CHIPTestClusterClusterTestNullableOptionalResponseCallbackBridge(dispatch_queue_t queue, ResponseHandler handler, + CHIPActionBlock action, bool keepAlive = false) : + CHIPCallbackBridge(queue, handler, action, OnSuccessFn, + keepAlive){}; + + static void OnSuccessFn(void * context, bool wasPresent, bool wasNull, uint8_t value); +}; + class CHIPTestClusterClusterTestSpecificResponseCallbackBridge : public CHIPCallbackBridge { diff --git a/src/darwin/Framework/CHIP/zap-generated/CHIPClustersObjc.h b/src/darwin/Framework/CHIP/zap-generated/CHIPClustersObjc.h index 41a737061619df..ef37af7fb2b0d5 100644 --- a/src/darwin/Framework/CHIP/zap-generated/CHIPClustersObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/CHIPClustersObjc.h @@ -1526,6 +1526,7 @@ NS_ASSUME_NONNULL_BEGIN f:(uint8_t)f responseHandler:(ResponseHandler)responseHandler; - (void)testNotHandled:(ResponseHandler)responseHandler; +- (void)testNullableOptionalRequest:(uint8_t)arg1 responseHandler:(ResponseHandler)responseHandler; - (void)testSpecific:(ResponseHandler)responseHandler; - (void)testStructArgumentRequest:(uint8_t)a b:(bool)b diff --git a/src/darwin/Framework/CHIP/zap-generated/CHIPClustersObjc.mm b/src/darwin/Framework/CHIP/zap-generated/CHIPClustersObjc.mm index d85ad132704ad2..b25111e609f6e0 100644 --- a/src/darwin/Framework/CHIP/zap-generated/CHIPClustersObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/CHIPClustersObjc.mm @@ -4523,6 +4523,14 @@ new CHIPDefaultSuccessCallbackBridge(self.callbackQueue, responseHandler, ^(Canc }); } +- (void)testNullableOptionalRequest:(uint8_t)arg1 responseHandler:(ResponseHandler)responseHandler +{ + new CHIPTestClusterClusterTestNullableOptionalResponseCallbackBridge( + self.callbackQueue, responseHandler, ^(Cancelable * success, Cancelable * failure) { + return self.cppCluster.TestNullableOptionalRequest(success, failure, arg1); + }); +} + - (void)testSpecific:(ResponseHandler)responseHandler { new CHIPTestClusterClusterTestSpecificResponseCallbackBridge( diff --git a/src/transport/FabricTable.h b/src/transport/FabricTable.h index 47a4ec3fce353d..face499507387f 100644 --- a/src/transport/FabricTable.h +++ b/src/transport/FabricTable.h @@ -29,6 +29,7 @@ #include #endif #include +#include #include #include #include @@ -110,6 +111,7 @@ class DLL_EXPORT FabricInfo // TODO - Optimize persistent storage of NOC and Root Cert in FabricInfo. CHIP_ERROR SetRootCert(const chip::ByteSpan & cert) { return SetCert(mRootCert, cert); } CHIP_ERROR SetICACert(const chip::ByteSpan & cert) { return SetCert(mICACert, cert); } + CHIP_ERROR SetICACert(const Optional & cert) { return SetICACert(cert.ValueOr(ByteSpan())); } CHIP_ERROR SetNOCCert(const chip::ByteSpan & cert) { return SetCert(mNOCCert, cert); } bool IsInitialized() const { return IsOperationalNodeId(mOperationalId.GetNodeId()); } diff --git a/zzz_generated/all-clusters-app/zap-generated/IMClusterCommandHandler.cpp b/zzz_generated/all-clusters-app/zap-generated/IMClusterCommandHandler.cpp index eb357f056e246e..59dd1cf6f4b89e 100644 --- a/zzz_generated/all-clusters-app/zap-generated/IMClusterCommandHandler.cpp +++ b/zzz_generated/all-clusters-app/zap-generated/IMClusterCommandHandler.cpp @@ -1683,6 +1683,15 @@ void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandP } break; } + case Commands::TestNullableOptionalRequest::Id: { + Commands::TestNullableOptionalRequest::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfTestClusterClusterTestNullableOptionalRequestCallback(apCommandObj, aCommandPath, commandData); + } + break; + } case Commands::TestSpecific::Id: { Commands::TestSpecific::DecodableType commandData; TLVError = DataModel::Decode(aDataTlv, commandData); diff --git a/zzz_generated/app-common/app-common/zap-generated/af-structs.h b/zzz_generated/app-common/app-common/zap-generated/af-structs.h index c8fe0aec8c193e..9f16baeb22134f 100644 --- a/zzz_generated/app-common/app-common/zap-generated/af-structs.h +++ b/zzz_generated/app-common/app-common/zap-generated/af-structs.h @@ -39,6 +39,23 @@ typedef struct _SimpleStruct uint8_t f; } SimpleStruct; +// Struct for NullablesAndOptionalsStruct +typedef struct _NullablesAndOptionalsStruct +{ + uint16_t NullableInt; + uint16_t OptionalInt; + uint16_t NullableOptionalInt; + chip::CharSpan NullableString; + chip::CharSpan OptionalString; + chip::CharSpan NullableOptionalString; + SimpleStruct NullableStruct; + SimpleStruct OptionalStruct; + SimpleStruct NullableOptionalStruct; + /* TYPE WARNING: array array defaults to */ uint8_t * NullableList; + /* TYPE WARNING: array array defaults to */ uint8_t * OptionalList; + /* TYPE WARNING: array array defaults to */ uint8_t * NullableOptionalList; +} NullablesAndOptionalsStruct; + // Struct for NestedStruct typedef struct _NestedStruct { diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index 4548ae7c8d6a8a..165084b9c3b120 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -13903,12 +13903,34 @@ bool emberAfTestClusterClusterTestEnumsResponseCallback(chip::EndpointId endpoin bool emberAfTestClusterClusterTestStructArrayArgumentRequestCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::TestCluster::Commands::TestStructArrayArgumentRequest::DecodableType & commandData); +/** + * @brief Test Cluster Cluster TestNullableOptionalResponse Command callback (from server) + */ +bool emberAfTestClusterClusterTestNullableOptionalResponseCallback(chip::EndpointId endpoint, chip::app::CommandSender * commandObj, + bool wasPresent, bool wasNull, uint8_t value); /** * @brief Test Cluster Cluster TestStructArgumentRequest Command callback (from client) */ bool emberAfTestClusterClusterTestStructArgumentRequestCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::TestCluster::Commands::TestStructArgumentRequest::DecodableType & commandData); +/** + * @brief Test Cluster Cluster TestComplexNullableOptionalResponse Command callback (from server) + */ +bool emberAfTestClusterClusterTestComplexNullableOptionalResponseCallback( + chip::EndpointId endpoint, chip::app::CommandSender * commandObj, bool NullableIntWasNull, uint16_t NullableIntValue, + bool OptionalIntWasPresent, uint16_t OptionalIntValue, bool NullableOptionalIntWasPresent, bool NullableOptionalIntWasNull, + uint16_t NullableOptionalIntValue, bool NullableStringWasNull, chip::CharSpan NullableStringValue, + bool OptionalStringWasPresent, chip::CharSpan OptionalStringValue, bool NullableOptionalStringWasPresent, + bool NullableOptionalStringWasNull, chip::CharSpan NullableOptionalStringValue, bool NullableStructWasNull, + chip::Optional NullableStructValue, + bool OptionalStructWasPresent, + chip::Optional OptionalStructValue, + bool NullableOptionalStructWasPresent, bool NullableOptionalStructWasNull, + chip::Optional NullableOptionalStructValue, + bool NullableListWasNull, /* TYPE WARNING: array array defaults to */ uint8_t * NullableListValue, bool OptionalListWasPresent, + /* TYPE WARNING: array array defaults to */ uint8_t * OptionalListValue, bool NullableOptionalListWasPresent, + bool NullableOptionalListWasNull, /* TYPE WARNING: array array defaults to */ uint8_t * NullableOptionalListValue); /** * @brief Test Cluster Cluster TestNestedStructArgumentRequest Command callback (from client) */ @@ -13951,6 +13973,18 @@ bool emberAfTestClusterClusterTestListInt8UReverseRequestCallback( bool emberAfTestClusterClusterTestEnumsRequestCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::TestCluster::Commands::TestEnumsRequest::DecodableType & commandData); +/** + * @brief Test Cluster Cluster TestNullableOptionalRequest Command callback (from client) + */ +bool emberAfTestClusterClusterTestNullableOptionalRequestCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::TestCluster::Commands::TestNullableOptionalRequest::DecodableType & commandData); +/** + * @brief Test Cluster Cluster TestComplexNullableOptionalRequest Command callback (from client) + */ +bool emberAfTestClusterClusterTestComplexNullableOptionalRequestCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::TestCluster::Commands::TestComplexNullableOptionalRequest::DecodableType & commandData); /** * @brief Messaging Cluster DisplayMessage Command callback (from server) */ diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index 6782e18166dc0f..3f262128adf0ae 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -15121,6 +15121,90 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) } } // namespace SimpleStruct +namespace NullablesAndOptionalsStruct { +CHIP_ERROR Type::Encode(TLV::TLVWriter & writer, TLV::Tag tag) const +{ + TLV::TLVType outer; + ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableInt)), nullableInt)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalInt)), optionalInt)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalInt)), nullableOptionalInt)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableString)), nullableString)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalString)), optionalString)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalString)), nullableOptionalString)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableStruct)), nullableStruct)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalStruct)), optionalStruct)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalStruct)), nullableOptionalStruct)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableList)), nullableList)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalList)), optionalList)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalList)), nullableOptionalList)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVType outer; + VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + err = reader.EnterContainer(outer); + ReturnErrorOnFailure(err); + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + switch (TLV::TagNumFromTag(reader.GetTag())) + { + case to_underlying(Fields::kNullableInt): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableInt)); + break; + case to_underlying(Fields::kOptionalInt): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalInt)); + break; + case to_underlying(Fields::kNullableOptionalInt): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalInt)); + break; + case to_underlying(Fields::kNullableString): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableString)); + break; + case to_underlying(Fields::kOptionalString): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalString)); + break; + case to_underlying(Fields::kNullableOptionalString): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalString)); + break; + case to_underlying(Fields::kNullableStruct): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableStruct)); + break; + case to_underlying(Fields::kOptionalStruct): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalStruct)); + break; + case to_underlying(Fields::kNullableOptionalStruct): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalStruct)); + break; + case to_underlying(Fields::kNullableList): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableList)); + break; + case to_underlying(Fields::kOptionalList): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalList)); + break; + case to_underlying(Fields::kNullableOptionalList): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalList)); + break; + default: + break; + } + } + + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + return CHIP_NO_ERROR; +} + +} // namespace NullablesAndOptionalsStruct namespace NestedStruct { CHIP_ERROR Type::Encode(TLV::TLVWriter & writer, TLV::Tag tag) const { @@ -15778,6 +15862,48 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) return CHIP_NO_ERROR; } } // namespace TestStructArrayArgumentRequest. +namespace TestNullableOptionalResponse { +CHIP_ERROR Type::Encode(TLV::TLVWriter & writer, TLV::Tag tag) const +{ + TLV::TLVType outer; + ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kWasPresent)), wasPresent)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kWasNull)), wasNull)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kValue)), value)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVType outer; + VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(reader.EnterContainer(outer)); + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + switch (TLV::TagNumFromTag(reader.GetTag())) + { + case to_underlying(Fields::kWasPresent): + ReturnErrorOnFailure(DataModel::Decode(reader, wasPresent)); + break; + case to_underlying(Fields::kWasNull): + ReturnErrorOnFailure(DataModel::Decode(reader, wasNull)); + break; + case to_underlying(Fields::kValue): + ReturnErrorOnFailure(DataModel::Decode(reader, value)); + break; + default: + break; + } + } + + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + return CHIP_NO_ERROR; +} +} // namespace TestNullableOptionalResponse. namespace TestStructArgumentRequest { CHIP_ERROR Type::Encode(TLV::TLVWriter & writer, TLV::Tag tag) const { @@ -15812,6 +15938,172 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) return CHIP_NO_ERROR; } } // namespace TestStructArgumentRequest. +namespace TestComplexNullableOptionalResponse { +CHIP_ERROR Type::Encode(TLV::TLVWriter & writer, TLV::Tag tag) const +{ + TLV::TLVType outer; + ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableIntWasNull)), nullableIntWasNull)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableIntValue)), nullableIntValue)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalIntWasPresent)), optionalIntWasPresent)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalIntValue)), optionalIntValue)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalIntWasPresent)), + nullableOptionalIntWasPresent)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalIntWasNull)), nullableOptionalIntWasNull)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalIntValue)), nullableOptionalIntValue)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableStringWasNull)), nullableStringWasNull)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableStringValue)), nullableStringValue)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalStringWasPresent)), optionalStringWasPresent)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalStringValue)), optionalStringValue)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalStringWasPresent)), + nullableOptionalStringWasPresent)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalStringWasNull)), + nullableOptionalStringWasNull)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalStringValue)), + nullableOptionalStringValue)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableStructWasNull)), nullableStructWasNull)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableStructValue)), nullableStructValue)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalStructWasPresent)), optionalStructWasPresent)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalStructValue)), optionalStructValue)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalStructWasPresent)), + nullableOptionalStructWasPresent)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalStructWasNull)), + nullableOptionalStructWasNull)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalStructValue)), + nullableOptionalStructValue)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableListWasNull)), nullableListWasNull)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableListValue)), nullableListValue)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalListWasPresent)), optionalListWasPresent)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalListValue)), optionalListValue)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalListWasPresent)), + nullableOptionalListWasPresent)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalListWasNull)), + nullableOptionalListWasNull)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalListValue)), nullableOptionalListValue)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVType outer; + VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(reader.EnterContainer(outer)); + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + switch (TLV::TagNumFromTag(reader.GetTag())) + { + case to_underlying(Fields::kNullableIntWasNull): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableIntWasNull)); + break; + case to_underlying(Fields::kNullableIntValue): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableIntValue)); + break; + case to_underlying(Fields::kOptionalIntWasPresent): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalIntWasPresent)); + break; + case to_underlying(Fields::kOptionalIntValue): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalIntValue)); + break; + case to_underlying(Fields::kNullableOptionalIntWasPresent): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalIntWasPresent)); + break; + case to_underlying(Fields::kNullableOptionalIntWasNull): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalIntWasNull)); + break; + case to_underlying(Fields::kNullableOptionalIntValue): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalIntValue)); + break; + case to_underlying(Fields::kNullableStringWasNull): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableStringWasNull)); + break; + case to_underlying(Fields::kNullableStringValue): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableStringValue)); + break; + case to_underlying(Fields::kOptionalStringWasPresent): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalStringWasPresent)); + break; + case to_underlying(Fields::kOptionalStringValue): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalStringValue)); + break; + case to_underlying(Fields::kNullableOptionalStringWasPresent): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalStringWasPresent)); + break; + case to_underlying(Fields::kNullableOptionalStringWasNull): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalStringWasNull)); + break; + case to_underlying(Fields::kNullableOptionalStringValue): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalStringValue)); + break; + case to_underlying(Fields::kNullableStructWasNull): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableStructWasNull)); + break; + case to_underlying(Fields::kNullableStructValue): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableStructValue)); + break; + case to_underlying(Fields::kOptionalStructWasPresent): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalStructWasPresent)); + break; + case to_underlying(Fields::kOptionalStructValue): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalStructValue)); + break; + case to_underlying(Fields::kNullableOptionalStructWasPresent): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalStructWasPresent)); + break; + case to_underlying(Fields::kNullableOptionalStructWasNull): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalStructWasNull)); + break; + case to_underlying(Fields::kNullableOptionalStructValue): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalStructValue)); + break; + case to_underlying(Fields::kNullableListWasNull): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableListWasNull)); + break; + case to_underlying(Fields::kNullableListValue): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableListValue)); + break; + case to_underlying(Fields::kOptionalListWasPresent): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalListWasPresent)); + break; + case to_underlying(Fields::kOptionalListValue): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalListValue)); + break; + case to_underlying(Fields::kNullableOptionalListWasPresent): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalListWasPresent)); + break; + case to_underlying(Fields::kNullableOptionalListWasNull): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalListWasNull)); + break; + case to_underlying(Fields::kNullableOptionalListValue): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalListValue)); + break; + default: + break; + } + } + + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + return CHIP_NO_ERROR; +} +} // namespace TestComplexNullableOptionalResponse. namespace TestNestedStructArgumentRequest { CHIP_ERROR Type::Encode(TLV::TLVWriter & writer, TLV::Tag tag) const { @@ -16054,6 +16346,122 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) return CHIP_NO_ERROR; } } // namespace TestEnumsRequest. +namespace TestNullableOptionalRequest { +CHIP_ERROR Type::Encode(TLV::TLVWriter & writer, TLV::Tag tag) const +{ + TLV::TLVType outer; + ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kArg1)), arg1)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVType outer; + VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(reader.EnterContainer(outer)); + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + switch (TLV::TagNumFromTag(reader.GetTag())) + { + case to_underlying(Fields::kArg1): + ReturnErrorOnFailure(DataModel::Decode(reader, arg1)); + break; + default: + break; + } + } + + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + return CHIP_NO_ERROR; +} +} // namespace TestNullableOptionalRequest. +namespace TestComplexNullableOptionalRequest { +CHIP_ERROR Type::Encode(TLV::TLVWriter & writer, TLV::Tag tag) const +{ + TLV::TLVType outer; + ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableInt)), nullableInt)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalInt)), optionalInt)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalInt)), nullableOptionalInt)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableString)), nullableString)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalString)), optionalString)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalString)), nullableOptionalString)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableStruct)), nullableStruct)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalStruct)), optionalStruct)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalStruct)), nullableOptionalStruct)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableList)), nullableList)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kOptionalList)), optionalList)); + ReturnErrorOnFailure( + DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kNullableOptionalList)), nullableOptionalList)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVType outer; + VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(reader.EnterContainer(outer)); + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + switch (TLV::TagNumFromTag(reader.GetTag())) + { + case to_underlying(Fields::kNullableInt): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableInt)); + break; + case to_underlying(Fields::kOptionalInt): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalInt)); + break; + case to_underlying(Fields::kNullableOptionalInt): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalInt)); + break; + case to_underlying(Fields::kNullableString): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableString)); + break; + case to_underlying(Fields::kOptionalString): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalString)); + break; + case to_underlying(Fields::kNullableOptionalString): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalString)); + break; + case to_underlying(Fields::kNullableStruct): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableStruct)); + break; + case to_underlying(Fields::kOptionalStruct): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalStruct)); + break; + case to_underlying(Fields::kNullableOptionalStruct): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalStruct)); + break; + case to_underlying(Fields::kNullableList): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableList)); + break; + case to_underlying(Fields::kOptionalList): + ReturnErrorOnFailure(DataModel::Decode(reader, optionalList)); + break; + case to_underlying(Fields::kNullableOptionalList): + ReturnErrorOnFailure(DataModel::Decode(reader, nullableOptionalList)); + break; + default: + break; + } + } + + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + return CHIP_NO_ERROR; +} +} // namespace TestComplexNullableOptionalRequest. } // namespace Commands namespace Events { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index 7b27f3a1695343..be06eac4e74a4f 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -5559,7 +5559,7 @@ struct Type chip::NodeId providerLocation; chip::VendorId vendorId; OTAAnnouncementReason announcementReason; - chip::ByteSpan metadataForNode; + Optional metadataForNode; CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag) const; }; @@ -5573,7 +5573,7 @@ struct DecodableType chip::NodeId providerLocation; chip::VendorId vendorId; OTAAnnouncementReason announcementReason; - chip::ByteSpan metadataForNode; + Optional metadataForNode; CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace AnnounceOtaProvider @@ -9358,7 +9358,7 @@ struct Type static constexpr ClusterId GetClusterId() { return OperationalCredentials::Id; } chip::ByteSpan NOCValue; - chip::ByteSpan ICACValue; + Optional ICACValue; chip::ByteSpan IPKValue; chip::NodeId caseAdminNode; uint16_t adminVendorId; @@ -9373,7 +9373,7 @@ struct DecodableType static constexpr ClusterId GetClusterId() { return OperationalCredentials::Id; } chip::ByteSpan NOCValue; - chip::ByteSpan ICACValue; + Optional ICACValue; chip::ByteSpan IPKValue; chip::NodeId caseAdminNode; uint16_t adminVendorId; @@ -9395,7 +9395,7 @@ struct Type static constexpr ClusterId GetClusterId() { return OperationalCredentials::Id; } chip::ByteSpan NOCValue; - chip::ByteSpan ICACValue; + Optional ICACValue; CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag) const; }; @@ -9407,7 +9407,7 @@ struct DecodableType static constexpr ClusterId GetClusterId() { return OperationalCredentials::Id; } chip::ByteSpan NOCValue; - chip::ByteSpan ICACValue; + Optional ICACValue; CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace UpdateNOC @@ -16183,8 +16183,8 @@ namespace Attributes { namespace MeasuredValue { struct TypeInfo { - using Type = uint16_t; - using DecodableType = uint16_t; + using Type = DataModel::Nullable; + using DecodableType = DataModel::Nullable; static constexpr ClusterId GetClusterId() { return Clusters::IlluminanceMeasurement::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::MeasuredValue::Id; } @@ -16193,8 +16193,8 @@ struct TypeInfo namespace MinMeasuredValue { struct TypeInfo { - using Type = uint16_t; - using DecodableType = uint16_t; + using Type = DataModel::Nullable; + using DecodableType = DataModel::Nullable; static constexpr ClusterId GetClusterId() { return Clusters::IlluminanceMeasurement::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::MinMeasuredValue::Id; } @@ -16203,8 +16203,8 @@ struct TypeInfo namespace MaxMeasuredValue { struct TypeInfo { - using Type = uint16_t; - using DecodableType = uint16_t; + using Type = DataModel::Nullable; + using DecodableType = DataModel::Nullable; static constexpr ClusterId GetClusterId() { return Clusters::IlluminanceMeasurement::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::MaxMeasuredValue::Id; } @@ -16223,8 +16223,8 @@ struct TypeInfo namespace LightSensorType { struct TypeInfo { - using Type = uint8_t; - using DecodableType = uint8_t; + using Type = DataModel::Nullable; + using DecodableType = DataModel::Nullable; static constexpr ClusterId GetClusterId() { return Clusters::IlluminanceMeasurement::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::LightSensorType::Id; } @@ -22537,6 +22537,61 @@ struct Type using DecodableType = Type; } // namespace SimpleStruct +namespace NullablesAndOptionalsStruct { +enum class Fields +{ + kNullableInt = 0, + kOptionalInt = 1, + kNullableOptionalInt = 2, + kNullableString = 3, + kOptionalString = 4, + kNullableOptionalString = 5, + kNullableStruct = 6, + kOptionalStruct = 7, + kNullableOptionalStruct = 8, + kNullableList = 9, + kOptionalList = 10, + kNullableOptionalList = 11, +}; + +struct Type +{ +public: + DataModel::Nullable nullableInt; + Optional optionalInt; + Optional> nullableOptionalInt; + DataModel::Nullable nullableString; + Optional optionalString; + Optional> nullableOptionalString; + DataModel::Nullable nullableStruct; + Optional optionalStruct; + Optional> nullableOptionalStruct; + DataModel::Nullable> nullableList; + Optional> optionalList; + Optional>> nullableOptionalList; + + CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag) const; +}; + +struct DecodableType +{ +public: + DataModel::Nullable nullableInt; + Optional optionalInt; + Optional> nullableOptionalInt; + DataModel::Nullable nullableString; + Optional optionalString; + Optional> nullableOptionalString; + DataModel::Nullable nullableStruct; + Optional optionalStruct; + Optional> nullableOptionalStruct; + DataModel::Nullable> nullableList; + Optional> optionalList; + Optional>> nullableOptionalList; + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; + +} // namespace NullablesAndOptionalsStruct namespace NestedStruct { enum class Fields { @@ -23028,6 +23083,40 @@ struct DecodableType CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace TestStructArrayArgumentRequest +namespace TestNullableOptionalResponse { +enum class Fields +{ + kWasPresent = 0, + kWasNull = 1, + kValue = 2, +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return TestNullableOptionalResponse::Id; } + static constexpr ClusterId GetClusterId() { return TestCluster::Id; } + + bool wasPresent; + Optional wasNull; + Optional value; + + CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag) const; +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return TestNullableOptionalResponse::Id; } + static constexpr ClusterId GetClusterId() { return TestCluster::Id; } + + bool wasPresent; + Optional wasNull; + Optional value; + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace TestNullableOptionalResponse namespace TestStructArgumentRequest { enum class Fields { @@ -23056,6 +23145,115 @@ struct DecodableType CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace TestStructArgumentRequest +namespace TestComplexNullableOptionalResponse { +enum class Fields +{ + kNullableIntWasNull = 0, + kNullableIntValue = 1, + kOptionalIntWasPresent = 2, + kOptionalIntValue = 3, + kNullableOptionalIntWasPresent = 4, + kNullableOptionalIntWasNull = 5, + kNullableOptionalIntValue = 6, + kNullableStringWasNull = 7, + kNullableStringValue = 8, + kOptionalStringWasPresent = 9, + kOptionalStringValue = 10, + kNullableOptionalStringWasPresent = 11, + kNullableOptionalStringWasNull = 12, + kNullableOptionalStringValue = 13, + kNullableStructWasNull = 14, + kNullableStructValue = 15, + kOptionalStructWasPresent = 16, + kOptionalStructValue = 17, + kNullableOptionalStructWasPresent = 18, + kNullableOptionalStructWasNull = 19, + kNullableOptionalStructValue = 20, + kNullableListWasNull = 21, + kNullableListValue = 22, + kOptionalListWasPresent = 23, + kOptionalListValue = 24, + kNullableOptionalListWasPresent = 25, + kNullableOptionalListWasNull = 26, + kNullableOptionalListValue = 27, +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return TestComplexNullableOptionalResponse::Id; } + static constexpr ClusterId GetClusterId() { return TestCluster::Id; } + + bool nullableIntWasNull; + Optional nullableIntValue; + bool optionalIntWasPresent; + Optional optionalIntValue; + bool nullableOptionalIntWasPresent; + Optional nullableOptionalIntWasNull; + Optional nullableOptionalIntValue; + bool nullableStringWasNull; + Optional nullableStringValue; + bool optionalStringWasPresent; + Optional optionalStringValue; + bool nullableOptionalStringWasPresent; + Optional nullableOptionalStringWasNull; + Optional nullableOptionalStringValue; + bool nullableStructWasNull; + Optional nullableStructValue; + bool optionalStructWasPresent; + Optional optionalStructValue; + bool nullableOptionalStructWasPresent; + Optional nullableOptionalStructWasNull; + Optional nullableOptionalStructValue; + bool nullableListWasNull; + Optional> nullableListValue; + bool optionalListWasPresent; + Optional> optionalListValue; + bool nullableOptionalListWasPresent; + Optional nullableOptionalListWasNull; + Optional> nullableOptionalListValue; + + CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag) const; +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return TestComplexNullableOptionalResponse::Id; } + static constexpr ClusterId GetClusterId() { return TestCluster::Id; } + + bool nullableIntWasNull; + Optional nullableIntValue; + bool optionalIntWasPresent; + Optional optionalIntValue; + bool nullableOptionalIntWasPresent; + Optional nullableOptionalIntWasNull; + Optional nullableOptionalIntValue; + bool nullableStringWasNull; + Optional nullableStringValue; + bool optionalStringWasPresent; + Optional optionalStringValue; + bool nullableOptionalStringWasPresent; + Optional nullableOptionalStringWasNull; + Optional nullableOptionalStringValue; + bool nullableStructWasNull; + Optional nullableStructValue; + bool optionalStructWasPresent; + Optional optionalStructValue; + bool nullableOptionalStructWasPresent; + Optional nullableOptionalStructWasNull; + Optional nullableOptionalStructValue; + bool nullableListWasNull; + Optional> nullableListValue; + bool optionalListWasPresent; + Optional> optionalListValue; + bool nullableOptionalListWasPresent; + Optional nullableOptionalListWasNull; + Optional> nullableOptionalListValue; + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace TestComplexNullableOptionalResponse namespace TestNestedStructArgumentRequest { enum class Fields { @@ -23255,6 +23453,95 @@ struct DecodableType CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace TestEnumsRequest +namespace TestNullableOptionalRequest { +enum class Fields +{ + kArg1 = 0, +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return TestNullableOptionalRequest::Id; } + static constexpr ClusterId GetClusterId() { return TestCluster::Id; } + + Optional> arg1; + + CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag) const; +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return TestNullableOptionalRequest::Id; } + static constexpr ClusterId GetClusterId() { return TestCluster::Id; } + + Optional> arg1; + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace TestNullableOptionalRequest +namespace TestComplexNullableOptionalRequest { +enum class Fields +{ + kNullableInt = 0, + kOptionalInt = 1, + kNullableOptionalInt = 2, + kNullableString = 3, + kOptionalString = 4, + kNullableOptionalString = 5, + kNullableStruct = 6, + kOptionalStruct = 7, + kNullableOptionalStruct = 8, + kNullableList = 9, + kOptionalList = 10, + kNullableOptionalList = 11, +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return TestComplexNullableOptionalRequest::Id; } + static constexpr ClusterId GetClusterId() { return TestCluster::Id; } + + DataModel::Nullable nullableInt; + Optional optionalInt; + Optional> nullableOptionalInt; + DataModel::Nullable nullableString; + Optional optionalString; + Optional> nullableOptionalString; + DataModel::Nullable nullableStruct; + Optional optionalStruct; + Optional> nullableOptionalStruct; + DataModel::Nullable> nullableList; + Optional> optionalList; + Optional>> nullableOptionalList; + + CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag) const; +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return TestComplexNullableOptionalRequest::Id; } + static constexpr ClusterId GetClusterId() { return TestCluster::Id; } + + DataModel::Nullable nullableInt; + Optional optionalInt; + Optional> nullableOptionalInt; + DataModel::Nullable nullableString; + Optional optionalString; + Optional> nullableOptionalString; + DataModel::Nullable nullableStruct; + Optional optionalStruct; + Optional> nullableOptionalStruct; + DataModel::Nullable> nullableList; + Optional> optionalList; + Optional>> nullableOptionalList; + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace TestComplexNullableOptionalRequest } // namespace Commands namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/command-id.h b/zzz_generated/app-common/app-common/zap-generated/command-id.h index 9b06034094b782..c7ca035095d600 100644 --- a/zzz_generated/app-common/app-common/zap-generated/command-id.h +++ b/zzz_generated/app-common/app-common/zap-generated/command-id.h @@ -443,7 +443,9 @@ #define ZCL_TEST_SIMPLE_ARGUMENT_REQUEST_COMMAND_ID (0x05) #define ZCL_TEST_ENUMS_RESPONSE_COMMAND_ID (0x05) #define ZCL_TEST_STRUCT_ARRAY_ARGUMENT_REQUEST_COMMAND_ID (0x06) +#define ZCL_TEST_NULLABLE_OPTIONAL_RESPONSE_COMMAND_ID (0x06) #define ZCL_TEST_STRUCT_ARGUMENT_REQUEST_COMMAND_ID (0x07) +#define ZCL_TEST_COMPLEX_NULLABLE_OPTIONAL_RESPONSE_COMMAND_ID (0x07) #define ZCL_TEST_NESTED_STRUCT_ARGUMENT_REQUEST_COMMAND_ID (0x08) #define ZCL_TEST_LIST_STRUCT_ARGUMENT_REQUEST_COMMAND_ID (0x09) #define ZCL_TEST_LIST_INT8_U_ARGUMENT_REQUEST_COMMAND_ID (0x0A) @@ -451,6 +453,8 @@ #define ZCL_TEST_LIST_NESTED_STRUCT_LIST_ARGUMENT_REQUEST_COMMAND_ID (0x0C) #define ZCL_TEST_LIST_INT8_U_REVERSE_REQUEST_COMMAND_ID (0x0D) #define ZCL_TEST_ENUMS_REQUEST_COMMAND_ID (0x0E) +#define ZCL_TEST_NULLABLE_OPTIONAL_REQUEST_COMMAND_ID (0x0F) +#define ZCL_TEST_COMPLEX_NULLABLE_OPTIONAL_REQUEST_COMMAND_ID (0x10) // Commands for cluster: Messaging #define ZCL_DISPLAY_MESSAGE_COMMAND_ID (0x00) diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h index 70411ed21f5ec6..faed693686ce08 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h @@ -1588,10 +1588,18 @@ namespace TestStructArrayArgumentRequest { static constexpr CommandId Id = 0x00000006; } // namespace TestStructArrayArgumentRequest +namespace TestNullableOptionalResponse { +static constexpr CommandId Id = 0x00000006; +} // namespace TestNullableOptionalResponse + namespace TestStructArgumentRequest { static constexpr CommandId Id = 0x00000007; } // namespace TestStructArgumentRequest +namespace TestComplexNullableOptionalResponse { +static constexpr CommandId Id = 0x00000007; +} // namespace TestComplexNullableOptionalResponse + namespace TestNestedStructArgumentRequest { static constexpr CommandId Id = 0x00000008; } // namespace TestNestedStructArgumentRequest @@ -1620,6 +1628,14 @@ namespace TestEnumsRequest { static constexpr CommandId Id = 0x0000000E; } // namespace TestEnumsRequest +namespace TestNullableOptionalRequest { +static constexpr CommandId Id = 0x0000000F; +} // namespace TestNullableOptionalRequest + +namespace TestComplexNullableOptionalRequest { +static constexpr CommandId Id = 0x00000010; +} // namespace TestComplexNullableOptionalRequest + } // namespace Commands } // namespace TestCluster diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index 4d793b89883343..ac75d9c3dd6bea 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -1848,6 +1848,18 @@ static void OnTestClusterTestListInt8UReverseResponseSuccess( command->SetCommandExitStatus(CHIP_NO_ERROR); }; +static void OnTestClusterTestNullableOptionalResponseSuccess( + void * context, const chip::app::Clusters::TestCluster::Commands::TestNullableOptionalResponse::DecodableType & data) +{ + ChipLogProgress(Zcl, "Received TestNullableOptionalResponse:"); + ChipLogProgress(Zcl, " wasPresent: %d", data.wasPresent); + ChipLogProgress(Zcl, " wasNull: Optional printing is not implemented yet."); + ChipLogProgress(Zcl, " value: Optional printing is not implemented yet."); + + ModelCommand * command = static_cast(context); + command->SetCommandExitStatus(CHIP_NO_ERROR); +}; + static void OnTestClusterTestSpecificResponseSuccess( void * context, const chip::app::Clusters::TestCluster::Commands::TestSpecificResponse::DecodableType & data) { @@ -18509,6 +18521,7 @@ class ReadTemperatureMeasurementClusterRevision : public ModelCommand | * TestListInt8UReverseRequest | 0x0D | | * TestListStructArgumentRequest | 0x09 | | * TestNotHandled | 0x01 | +| * TestNullableOptionalRequest | 0x0F | | * TestSpecific | 0x02 | | * TestStructArgumentRequest | 0x07 | | * TestUnknownCommand | 0x03 | @@ -18712,6 +18725,31 @@ class TestClusterTestNotHandled : public ModelCommand chip::app::Clusters::TestCluster::Commands::TestNotHandled::Type mRequest; }; +/* + * Command TestNullableOptionalRequest + */ +class TestClusterTestNullableOptionalRequest : public ModelCommand +{ +public: + TestClusterTestNullableOptionalRequest() : ModelCommand("test-nullable-optional-request") + { + AddArgument("Arg1", 0, UINT8_MAX, &mRequest.arg1); + ModelCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(ChipDevice * device, uint8_t endpointId) override + { + ChipLogProgress(chipTool, "Sending cluster (0x0000050F) command (0x0000000F) on endpoint %" PRIu8, endpointId); + + chip::Controller::TestClusterCluster cluster; + cluster.Associate(device, endpointId); + return cluster.InvokeCommand(mRequest, this, OnTestClusterTestNullableOptionalResponseSuccess, OnDefaultFailure); + } + +private: + chip::app::Clusters::TestCluster::Commands::TestNullableOptionalRequest::Type mRequest; +}; + /* * Command TestSpecific */ @@ -26912,6 +26950,7 @@ void registerClusterTestCluster(Commands & commands) make_unique(), // make_unique(), // make_unique(), // + make_unique(), // make_unique(), // make_unique(), // make_unique(), // diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index 6c68afa67a552d..a9f88791ea9623 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -21388,6 +21388,14 @@ class TestClusterComplexTypes : public TestCommand " ***** Test Step 6 : Send Test Command With List of Struct Argument and arg1.b of first item is false\n"); err = TestSendTestCommandWithListOfStructArgumentAndArg1bOfFirstItemIsFalse_6(); break; + case 7: + ChipLogProgress(chipTool, " ***** Test Step 7 : Send Test Command with optional arg set.\n"); + err = TestSendTestCommandWithOptionalArgSet_7(); + break; + case 8: + ChipLogProgress(chipTool, " ***** Test Step 8 : Send Test Command without its optional arg.\n"); + err = TestSendTestCommandWithoutItsOptionalArg_8(); + break; } if (CHIP_NO_ERROR != err) @@ -21399,7 +21407,7 @@ class TestClusterComplexTypes : public TestCommand private: std::atomic_uint16_t mTestIndex; - const uint16_t mTestCount = 7; + const uint16_t mTestCount = 9; // // Tests methods @@ -21663,6 +21671,70 @@ class TestClusterComplexTypes : public TestCommand void OnFailureResponse_6(uint8_t status) { NextTest(); } void OnSuccessResponse_6() { ThrowSuccessResponse(); } + + CHIP_ERROR TestSendTestCommandWithOptionalArgSet_7() + { + chip::Controller::TestClusterClusterTest cluster; + cluster.Associate(mDevice, 1); + + using requestType = chip::app::Clusters::TestCluster::Commands::TestNullableOptionalRequest::Type; + using responseType = chip::app::Clusters::TestCluster::Commands::TestNullableOptionalResponse::DecodableType; + + chip::app::Clusters::TestCluster::Commands::TestNullableOptionalRequest::Type request; + request.arg1.Emplace().SetNonNull() = 5; + + auto success = [](void * context, const responseType & data) { + (static_cast(context))->OnSuccessResponse_7(data.wasPresent, data.wasNull, data.value); + }; + + auto failure = [](void * context, EmberAfStatus status) { + (static_cast(context))->OnFailureResponse_7(status); + }; + return cluster.InvokeCommand(request, this, success, failure); + } + + void OnFailureResponse_7(uint8_t status) { ThrowFailureResponse(); } + + void OnSuccessResponse_7(bool wasPresent, const chip::Optional & wasNull, const chip::Optional & value) + { + VerifyOrReturn(CheckValue("wasPresent", wasPresent, true)); + + VerifyOrReturn(CheckValuePresent("wasNull", wasNull)); + VerifyOrReturn(CheckValue("wasNull.Value()", wasNull.Value(), false)); + + VerifyOrReturn(CheckValuePresent("value", value)); + VerifyOrReturn(CheckValue("value.Value()", value.Value(), 5)); + NextTest(); + } + + CHIP_ERROR TestSendTestCommandWithoutItsOptionalArg_8() + { + chip::Controller::TestClusterClusterTest cluster; + cluster.Associate(mDevice, 1); + + using requestType = chip::app::Clusters::TestCluster::Commands::TestNullableOptionalRequest::Type; + using responseType = chip::app::Clusters::TestCluster::Commands::TestNullableOptionalResponse::DecodableType; + + chip::app::Clusters::TestCluster::Commands::TestNullableOptionalRequest::Type request; + + auto success = [](void * context, const responseType & data) { + (static_cast(context))->OnSuccessResponse_8(data.wasPresent, data.wasNull, data.value); + }; + + auto failure = [](void * context, EmberAfStatus status) { + (static_cast(context))->OnFailureResponse_8(status); + }; + return cluster.InvokeCommand(request, this, success, failure); + } + + void OnFailureResponse_8(uint8_t status) { ThrowFailureResponse(); } + + void OnSuccessResponse_8(bool wasPresent, const chip::Optional & wasNull, const chip::Optional & value) + { + VerifyOrReturn(CheckValue("wasPresent", wasPresent, false)); + + NextTest(); + } }; class TestConstraints : public TestCommand diff --git a/zzz_generated/controller-clusters/zap-generated/CHIPClientCallbacks.cpp b/zzz_generated/controller-clusters/zap-generated/CHIPClientCallbacks.cpp index 37b468853e99c1..e683b5a2af32f9 100644 --- a/zzz_generated/controller-clusters/zap-generated/CHIPClientCallbacks.cpp +++ b/zzz_generated/controller-clusters/zap-generated/CHIPClientCallbacks.cpp @@ -1910,6 +1910,22 @@ bool emberAfTestClusterClusterTestListInt8UReverseResponseCallback(EndpointId en return true; } +bool emberAfTestClusterClusterTestNullableOptionalResponseCallback(EndpointId endpoint, app::CommandSender * commandObj, + bool wasPresent, bool wasNull, uint8_t value) +{ + ChipLogProgress(Zcl, "TestNullableOptionalResponse:"); + ChipLogProgress(Zcl, " wasPresent: %d", wasPresent); + ChipLogProgress(Zcl, " wasNull: %d", wasNull); + ChipLogProgress(Zcl, " value: %" PRIu8 "", value); + + GET_CLUSTER_RESPONSE_CALLBACKS("TestClusterClusterTestNullableOptionalResponseCallback"); + + Callback::Callback * cb = + Callback::Callback::FromCancelable(onSuccessCallback); + cb->mCall(cb->mContext, wasPresent, wasNull, value); + return true; +} + bool emberAfTestClusterClusterTestSpecificResponseCallback(EndpointId endpoint, app::CommandSender * commandObj, uint8_t returnValue) { diff --git a/zzz_generated/controller-clusters/zap-generated/CHIPClientCallbacks.h b/zzz_generated/controller-clusters/zap-generated/CHIPClientCallbacks.h index 0296e3a841e227..e49b0d78b6591c 100644 --- a/zzz_generated/controller-clusters/zap-generated/CHIPClientCallbacks.h +++ b/zzz_generated/controller-clusters/zap-generated/CHIPClientCallbacks.h @@ -146,6 +146,8 @@ typedef void (*TestClusterClusterTestAddArgumentsResponseCallback)(void * contex typedef void (*TestClusterClusterTestEnumsResponseCallback)(void * context, chip::VendorId arg1, uint8_t arg2); typedef void (*TestClusterClusterTestListInt8UReverseResponseCallback)(void * context, /* TYPE WARNING: array array defaults to */ uint8_t * arg1); +typedef void (*TestClusterClusterTestNullableOptionalResponseCallback)(void * context, bool wasPresent, bool wasNull, + uint8_t value); typedef void (*TestClusterClusterTestSpecificResponseCallback)(void * context, uint8_t returnValue); // List specific responses diff --git a/zzz_generated/controller-clusters/zap-generated/CHIPClusters.cpp b/zzz_generated/controller-clusters/zap-generated/CHIPClusters.cpp index 312940bbb1c296..7117331f485bd7 100644 --- a/zzz_generated/controller-clusters/zap-generated/CHIPClusters.cpp +++ b/zzz_generated/controller-clusters/zap-generated/CHIPClusters.cpp @@ -11693,6 +11693,48 @@ CHIP_ERROR TestClusterCluster::TestNotHandled(Callback::Cancelable * onSuccessCa return err; } +CHIP_ERROR TestClusterCluster::TestNullableOptionalRequest(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback, uint8_t arg1) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVWriter * writer = nullptr; + uint8_t argSeqNumber = 0; + + // Used when encoding non-empty command. Suppress error message when encoding empty commands. + (void) writer; + (void) argSeqNumber; + + VerifyOrReturnError(mDevice != nullptr, CHIP_ERROR_INCORRECT_STATE); + + app::CommandPathParams cmdParams = { mEndpoint, /* group id */ 0, mClusterId, + TestCluster::Commands::TestNullableOptionalRequest::Id, + (app::CommandPathFlags::kEndpointIdValid) }; + + CommandSenderHandle sender( + Platform::New(mDevice->GetInteractionModelDelegate(), mDevice->GetExchangeManager())); + + VerifyOrReturnError(sender != nullptr, CHIP_ERROR_NO_MEMORY); + + SuccessOrExit(err = sender->PrepareCommand(cmdParams)); + + VerifyOrExit((writer = sender->GetCommandDataIBTLVWriter()) != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + // arg1: int8u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), arg1)); + + SuccessOrExit(err = sender->FinishCommand()); + + // #6308: This is a temporary solution before we fully support IM on application side and should be replaced by IMDelegate. + mDevice->AddIMResponseHandler(sender.get(), onSuccessCallback, onFailureCallback); + + SuccessOrExit(err = mDevice->SendCommands(sender.get())); + + // We have successfully sent the command, and the callback handler will be responsible to free the object, release the object + // now. + sender.release(); +exit: + return err; +} + CHIP_ERROR TestClusterCluster::TestSpecific(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -12532,6 +12574,13 @@ ClusterBase::InvokeCommand, CommandResponseFailureCallback); +template CHIP_ERROR +ClusterBase::InvokeCommand( + const chip::app::Clusters::TestCluster::Commands::TestNullableOptionalRequest::Type &, void *, + CommandResponseSuccessCallback, + CommandResponseFailureCallback); + template CHIP_ERROR ClusterBase::InvokeCommand( const chip::app::Clusters::TestCluster::Commands::TestSpecific::Type &, void *, diff --git a/zzz_generated/controller-clusters/zap-generated/CHIPClusters.h b/zzz_generated/controller-clusters/zap-generated/CHIPClusters.h index c04236c47b352c..e4ee87c7a21d8d 100644 --- a/zzz_generated/controller-clusters/zap-generated/CHIPClusters.h +++ b/zzz_generated/controller-clusters/zap-generated/CHIPClusters.h @@ -1299,6 +1299,8 @@ class DLL_EXPORT TestClusterCluster : public ClusterBase CHIP_ERROR TestListStructArgumentRequest(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, uint8_t a, bool b, uint8_t c, chip::ByteSpan d, chip::CharSpan e, uint8_t f); CHIP_ERROR TestNotHandled(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback); + CHIP_ERROR TestNullableOptionalRequest(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, + uint8_t arg1); CHIP_ERROR TestSpecific(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback); CHIP_ERROR TestStructArgumentRequest(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, uint8_t a, bool b, uint8_t c, chip::ByteSpan d, chip::CharSpan e, uint8_t f); diff --git a/zzz_generated/controller-clusters/zap-generated/IMClusterCommandHandler.cpp b/zzz_generated/controller-clusters/zap-generated/IMClusterCommandHandler.cpp index a3458febceb324..aa269a32a2f479 100644 --- a/zzz_generated/controller-clusters/zap-generated/IMClusterCommandHandler.cpp +++ b/zzz_generated/controller-clusters/zap-generated/IMClusterCommandHandler.cpp @@ -5363,6 +5363,73 @@ void DispatchClientCommand(CommandSender * apCommandObj, const ConcreteCommandPa } break; } + case Commands::TestNullableOptionalResponse::Id: { + expectArgumentCount = 3; + bool wasPresent; + bool wasNull; + uint8_t value; + bool argExists[3]; + + memset(argExists, 0, sizeof argExists); + + while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) + { + // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. + // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. + if (!TLV::IsContextTag(aDataTlv.GetTag())) + { + continue; + } + currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); + if (currentDecodeTagId < 3) + { + if (argExists[currentDecodeTagId]) + { + ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); + TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + break; + } + else + { + argExists[currentDecodeTagId] = true; + validArgumentCount++; + } + } + switch (currentDecodeTagId) + { + case 0: + TLVUnpackError = aDataTlv.Get(wasPresent); + break; + case 1: + TLVUnpackError = aDataTlv.Get(wasNull); + break; + case 2: + TLVUnpackError = aDataTlv.Get(value); + break; + default: + // Unsupported tag, ignore it. + ChipLogProgress(Zcl, "Unknown TLV tag during processing."); + break; + } + if (CHIP_NO_ERROR != TLVUnpackError) + { + break; + } + } + + if (CHIP_END_OF_TLV == TLVError) + { + // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. + TLVError = CHIP_NO_ERROR; + } + + if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount) + { + wasHandled = emberAfTestClusterClusterTestNullableOptionalResponseCallback(aCommandPath.mEndpointId, apCommandObj, + wasPresent, wasNull, value); + } + break; + } case Commands::TestSpecificResponse::Id: { expectArgumentCount = 1; uint8_t returnValue;