diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index dc152c1a714f19..4297e791326786 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -26,14 +26,14 @@ on: run-codeql: required: false type: boolean - + concurrency: group: ${{ github.ref }}-${{ github.workflow }}-${{ (github.event_name == 'pull_request' && github.event.number) || (github.event_name == 'workflow_dispatch' && github.run_number) || github.sha }} cancel-in-progress: true env: CHIP_NO_LOG_TIMESTAMPS: true - + jobs: build_linux_gcc_debug: name: Build on Linux (gcc_debug) @@ -210,7 +210,7 @@ jobs: ./scripts/run_in_build_env.sh \ "./scripts/run-clang-tidy-on-compile-commands.py \ --compile-database out/sanitizers/compile_commands.json \ - --file-exclude-regex '/(repo|zzz_generated|lwip/standalone)/|-ReadImpl|-InvokeSubscribeImpl|CodegenDataModel_Write' \ + --file-exclude-regex '/(repo|zzz_generated|lwip/standalone)/|-ReadImpl|-InvokeSubscribeImpl|CodegenDataModel_Write|QuieterReporting' \ check \ " - name: Clean output @@ -243,7 +243,7 @@ jobs: run: | rm -rf ./zzz_pregenerated mv scripts/codegen.py.renamed scripts/codegen.py - mv scripts/tools/zap/generate.py.renamed scripts/tools/zap/generate.py + mv scripts/tools/zap/generate.py.renamed scripts/tools/zap/generate.py - name: Run fake linux tests with build_examples run: | ./scripts/run_in_build_env.sh \ @@ -253,7 +253,7 @@ jobs: uses: ./.github/actions/perform-codeql-analysis with: language: cpp - + - name: Uploading core files uses: actions/upload-artifact@v4 if: ${{ failure() && !env.ACT }} @@ -430,7 +430,7 @@ jobs: ./scripts/run_in_build_env.sh \ "./scripts/run-clang-tidy-on-compile-commands.py \ --compile-database out/default/compile_commands.json \ - --file-exclude-regex '/(repo|zzz_generated|lwip/standalone)/|CodegenDataModel_Write' \ + --file-exclude-regex '/(repo|zzz_generated|lwip/standalone)/|CodegenDataModel_Write|QuieterReporting' \ check \ " - name: Uploading diagnostic logs @@ -445,7 +445,7 @@ jobs: uses: ./.github/actions/perform-codeql-analysis with: language: cpp - + # TODO Log Upload https://github.com/project-chip/connectedhomeip/issues/2227 # TODO https://github.com/project-chip/connectedhomeip/issues/1512 diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index ce9da1b635563f..53195008ba4222 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -112,6 +112,7 @@ jobs: src/app/zap-templates/zcl/data-model/chip/channel-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/clusters-extensions.xml \ src/app/zap-templates/zcl/data-model/chip/color-control-cluster.xml \ + src/app/zap-templates/zcl/data-model/chip/commissioner-control-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/concentration-measurement-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/content-launch-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/content-app-observer-cluster.xml \ @@ -494,7 +495,7 @@ jobs: - name: Run Tests run: | mkdir -p out/trace_data - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --quiet --app-args "--trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script-args "--log-level INFO -t 3600 --disable-test ClusterObjectTests.TestTimedRequestTimeout --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/controller/python/test/test_scripts/mobile-device-test.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ACE_1_2.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ACE_1_3.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ACE_1_4.py' diff --git a/docs/testing/python.md b/docs/testing/python.md index 06051fee4fb33b..5745a301535fc7 100644 --- a/docs/testing/python.md +++ b/docs/testing/python.md @@ -85,58 +85,8 @@ The default_matter_test_main() function is used to run the test on the command line. These two lines should appear verbatim at the bottom of every python test file. -## Defining the test arguments - -Below is the format: - -``` -# test-runner-runs: -# test-runner-run//app: ${TYPE_OF_APP} -# test-runner-run//factoryreset: -# test-runner-run//quiet: -# test-runner-run//app-args: -# test-runner-run//script-args: -``` - -### Description of Parameters - -- test-runner-runs: Specifies the identifier for the run. This can be any - unique identifier. - - - Example: run1 - -- test-runner-run//app: Indicates the application to be used - in the test. Different app types as needed could be referenced from section - [name: Generate an argument environment file ] of the file - [.github/workflows/tests.yaml](https://github.com/project-chip/connectedhomeip/blob/master/.github/workflows/tests.yaml) - - - Example: \${TYPE_OF_APP} - -- test-runner-run//factoryreset: Determines whether a factory - reset should be performed before the test. - - - Example: True - -- test-runner-run//quiet: Sets the verbosity level of the test - run. When set to True, the test run will be quieter. - - - Example: True - -- test-runner-run//app-args: Specifies the arguments to be - passed to the application during the test. - - - Example: --discriminator 1234 --KVS kvs1 --trace-to - json:\${TRACE_APP}.json - -- test-runner-run//script-args: Specifies the arguments to be - passed to the test script. - - Example: --storage-path admin_storage.json --commissioning-method - on-network --discriminator 1234 --passcode 20202021 --trace-to - json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto - -This structured format ensures that all necessary configurations are clearly -defined and easily understood, allowing for consistent and reliable test -execution. +The structured comments above the class definition are used to set up the CI for +the tests. Please see [Running tests in CI](#running-tests-in-ci). ## Cluster Codegen @@ -610,3 +560,63 @@ example DUT on the host and includes factory reset support - if there are things in your test that will fail on CI (ex. test vendor checks), gate them on the PICS_SDK_CI_ONLY - is_ci = self.check_pics('PICS_SDK_CI_ONLY') + +The CI test runner uses a structured environment setup that can be declared +using structured comments at the top of the test file. To use this structured +format, use the --load-from-env flag with the run_python_tests.py runner. + +Ex: +`scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ICDM_2_1.py'` + +## Defining the CI test arguments + +Below is the format: + +``` +# test-runner-runs: +# test-runner-run//app: ${TYPE_OF_APP} +# test-runner-run//factoryreset: +# test-runner-run//quiet: +# test-runner-run//app-args: +# test-runner-run//script-args: +``` + +### Description of Parameters + +- test-runner-runs: Specifies the identifier for the run. This can be any + unique identifier. + + - Example: run1 + +- test-runner-run//app: Indicates the application to be used + in the test. Different app types as needed could be referenced from section + [name: Generate an argument environment file ] of the file + [.github/workflows/tests.yaml](https://github.com/project-chip/connectedhomeip/blob/master/.github/workflows/tests.yaml) + + - Example: \${TYPE_OF_APP} + +- test-runner-run//factoryreset: Determines whether a factory + reset should be performed before the test. + + - Example: True + +- test-runner-run//quiet: Sets the verbosity level of the test + run. When set to True, the test run will be quieter. + + - Example: True + +- test-runner-run//app-args: Specifies the arguments to be + passed to the application during the test. + + - Example: --discriminator 1234 --KVS kvs1 --trace-to + json:\${TRACE_APP}.json + +- test-runner-run//script-args: Specifies the arguments to be + passed to the test script. + - Example: --storage-path admin_storage.json --commissioning-method + on-network --discriminator 1234 --passcode 20202021 --trace-to + json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto + +This structured format ensures that all necessary configurations are clearly +defined and easily understood, allowing for consistent and reliable test +execution. diff --git a/docs/zap_clusters.md b/docs/zap_clusters.md index 5f2a2e262111ac..dc439fa2f37607 100644 --- a/docs/zap_clusters.md +++ b/docs/zap_clusters.md @@ -131,6 +131,7 @@ Generally regenerate using one of: | 1294 | 0x50E | AccountLogin | | 1295 | 0x50F | ContentControl | | 1296 | 0x510 | ContentAppObserver | +| 1873 | 0x751 | CommissionerControl | | 2820 | 0xB04 | ElectricalMeasurement | | 4294048773 | 0xFFF1FC05 | UnitTesting | | 4294048774 | 0xFFF1FC06 | FaultInjection | diff --git a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h index 7dc5b848e22324..6cb580ded9c35f 100644 --- a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h +++ b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h @@ -39,7 +39,7 @@ class CHIPCommandBridge : public Command { { AddArgument("commissioner-name", &mCommissionerName); AddArgument("commissioner-nodeId", 0, UINT64_MAX, &mCommissionerNodeId, - "Sets the commisser node ID of the given " + "Sets the commissioner node ID of the given " "commissioner-name. Interactive mode will only set a single commissioner on the inital command. " "The commissioner node ID will be persisted until a different one is specified."); AddArgument("paa-trust-store-path", &mPaaTrustStorePath, diff --git a/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm b/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm index 9723199ed007a4..52f0fd4bb10a17 100644 --- a/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm +++ b/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm @@ -36,7 +36,7 @@ - (void)controller:(MTRDeviceController *)controller statusUpdate:(MTRCommission ChipLogError(chipTool, "MTRCommissioningStatusDiscoveringMoreDevices: This should not happen."); break; case MTRCommissioningStatusUnknown: - ChipLogError(chipTool, "Uknown Pairing Status"); + ChipLogError(chipTool, "Unknown Pairing Status"); break; } } diff --git a/scripts/rules.matterlint b/scripts/rules.matterlint index ecfd8a99fe3d6f..eff738deb58d8e 100644 --- a/scripts/rules.matterlint +++ b/scripts/rules.matterlint @@ -19,6 +19,7 @@ load "../src/app/zap-templates/zcl/data-model/chip/chip-ota.xml"; load "../src/app/zap-templates/zcl/data-model/chip/chip-types.xml"; load "../src/app/zap-templates/zcl/data-model/chip/clusters-extensions.xml"; load "../src/app/zap-templates/zcl/data-model/chip/color-control-cluster.xml"; +load "../src/app/zap-templates/zcl/data-model/chip/commissioner-control-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/concentration-measurement-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/content-launch-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/content-app-observer-cluster.xml"; diff --git a/scripts/setup/zap.json b/scripts/setup/zap.json index c3e65c8bab9752..636da03eeb2e8f 100644 --- a/scripts/setup/zap.json +++ b/scripts/setup/zap.json @@ -8,13 +8,13 @@ "mac-amd64", "windows-amd64" ], - "tags": ["version:2@v2024.06.10-nightly.1"] + "tags": ["version:2@v2024.07.10-nightly.1"] }, { "_comment": "Always get the amd64 version on mac until usable arm64 zap build is available", "path": "fuchsia/third_party/zap/mac-amd64", "platforms": ["mac-arm64"], - "tags": ["version:2@v2024.06.10-nightly.1"] + "tags": ["version:2@v2024.07.10-nightly.1"] } ] } diff --git a/scripts/setup/zap.version b/scripts/setup/zap.version index 8b3c20afc891f6..4414b06f961e8b 100644 --- a/scripts/setup/zap.version +++ b/scripts/setup/zap.version @@ -1 +1 @@ -v2024.06.10-nightly +v2024.07.10-nightly diff --git a/scripts/tools/zap/zap_execution.py b/scripts/tools/zap/zap_execution.py index 80def9602dce77..d027079ac70070 100644 --- a/scripts/tools/zap/zap_execution.py +++ b/scripts/tools/zap/zap_execution.py @@ -23,7 +23,7 @@ # Use scripts/tools/zap/version_update.py to manage ZAP versioning as many # files may need updating for versions # -MIN_ZAP_VERSION = '2024.6.6' +MIN_ZAP_VERSION = '2024.7.10' class ZapTool: diff --git a/scripts/tools/zap_regen_all.py b/scripts/tools/zap_regen_all.py index dce4f719a19829..afe931fd8609a6 100755 --- a/scripts/tools/zap_regen_all.py +++ b/scripts/tools/zap_regen_all.py @@ -350,7 +350,8 @@ def setupArgumentsParser(): parser.add_argument('--parallel', action='store_true') parser.add_argument('--no-parallel', action='store_false', dest='parallel') - parser.set_defaults(parallel=True) + parser.add_argument('--no-rerun-in-env', action='store_false', dest='rerun_in_env') + parser.set_defaults(parallel=True, rerun_in_env=True) args = parser.parse_args() @@ -495,6 +496,26 @@ def main(): level=logging.INFO, format='%(asctime)s %(name)s %(levelname)-7s %(message)s' ) + + # The scripts executed by this generally MUST be within a bootstrapped environment because + # we need: + # - zap-cli in PATH + # - scripts/codegen.py uses click (can be in current pyenv, but guaranteed in bootstrap) + # - formatting is using bootstrapped clang-format + # Figure out if bootstrapped. For now assume `PW_ROOT` is such a marker in the environment + if "PW_ROOT" not in os.environ: + logging.error("Script MUST be run in a bootstrapped environment.") + + # using the `--no-rerun-in-env` to avoid recursive infinite calls + if '--no-rerun-in-env' not in sys.argv: + import shlex + logging.info("Will re-try running in a build environment....") + + what_to_run = sys.argv + ['--no-rerun-in-env'] + launcher = os.path.join(CHIP_ROOT_DIR, 'scripts', 'run_in_build_env.sh') + os.execv(launcher, [launcher, shlex.join(what_to_run)]) + sys.exit(1) + checkPythonVersion() os.chdir(CHIP_ROOT_DIR) args = setupArgumentsParser() diff --git a/src/BUILD.gn b/src/BUILD.gn index 3f4421d2f3f584..7e5fedcc0d539b 100644 --- a/src/BUILD.gn +++ b/src/BUILD.gn @@ -51,6 +51,7 @@ if (chip_build_tests) { deps = [] tests = [ "${chip_root}/src/app/data-model/tests", + "${chip_root}/src/app/cluster-building-blocks/tests", "${chip_root}/src/app/data-model-interface/tests", "${chip_root}/src/access/tests", "${chip_root}/src/crypto/tests", diff --git a/src/app/AttributeAccessInterfaceCache.h b/src/app/AttributeAccessInterfaceCache.h index 21e29410f9a367..9268a7096ea9d5 100644 --- a/src/app/AttributeAccessInterfaceCache.h +++ b/src/app/AttributeAccessInterfaceCache.h @@ -48,7 +48,7 @@ class AttributeAccessInterfaceCache kDefinitelyUsed }; - constexpr AttributeAccessInterfaceCache() = default; + AttributeAccessInterfaceCache() { Invalidate(); } /** * @brief Invalidate the whole cache. Must be called every time list of AAI registrations changes. @@ -106,8 +106,6 @@ class AttributeAccessInterfaceCache private: struct AttributeAccessCacheEntry { - constexpr AttributeAccessCacheEntry() = default; - EndpointId endpointId = kInvalidEndpointId; ClusterId clusterId = kInvalidClusterId; AttributeAccessInterface * accessor = nullptr; @@ -139,8 +137,8 @@ class AttributeAccessInterfaceCache return &mCacheSlots[0]; } - AttributeAccessCacheEntry mCacheSlots[1] = {}; - AttributeAccessCacheEntry mLastUnusedEntry{}; + AttributeAccessCacheEntry mCacheSlots[1]; + AttributeAccessCacheEntry mLastUnusedEntry; }; } // namespace app diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 55bc5f305ddd99..666c452b09dc3a 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -207,7 +207,7 @@ static_library("interaction-model") { public_deps = [ ":app_config", - ":command-handler", + ":command-handler-impl", ":constants", ":paths", ":subscription-info-provider", @@ -333,16 +333,32 @@ source_set("status-response") { ] } -source_set("command-handler") { +source_set("command-handler-interface") { sources = [ "CommandHandler.cpp", "CommandHandler.h", "CommandHandlerExchangeInterface.h", + ] + + public_deps = [ + ":paths", + "${chip_root}/src/access:types", + "${chip_root}/src/app/data-model", + "${chip_root}/src/lib/core", + "${chip_root}/src/lib/support", + "${chip_root}/src/messaging", + "${chip_root}/src/protocols/interaction_model", + ] +} + +source_set("command-handler-impl") { + sources = [ "CommandHandlerImpl.cpp", "CommandHandlerImpl.h", ] public_deps = [ + ":command-handler-interface", ":paths", ":required-privileges", ":status-response", diff --git a/src/app/EventLoggingTypes.h b/src/app/EventLoggingTypes.h index 666cb3886331fe..04a843ebcfbd60 100644 --- a/src/app/EventLoggingTypes.h +++ b/src/app/EventLoggingTypes.h @@ -100,7 +100,7 @@ struct Timestamp kSystem = 0, kEpoch }; - constexpr Timestamp() = default; + Timestamp() {} Timestamp(Type aType, uint64_t aValue) : mType(aType), mValue(aValue) {} Timestamp(System::Clock::Timestamp aValue) : mType(Type::kSystem), mValue(aValue.count()) {} static Timestamp Epoch(System::Clock::Timestamp aValue) diff --git a/src/app/EventManagement.cpp b/src/app/EventManagement.cpp index 7b210064898b6e..8e6d53c24c9636 100644 --- a/src/app/EventManagement.cpp +++ b/src/app/EventManagement.cpp @@ -32,7 +32,7 @@ using namespace chip::TLV; namespace chip { namespace app { -EventManagement EventManagement::sInstance; +static EventManagement sInstance; /** * @brief diff --git a/src/app/EventManagement.h b/src/app/EventManagement.h index 16e2271d3448b5..ce5a34039ea0fe 100644 --- a/src/app/EventManagement.h +++ b/src/app/EventManagement.h @@ -73,7 +73,7 @@ namespace app { inline constexpr const uint32_t kEventManagementProfile = 0x1; inline constexpr const uint32_t kFabricIndexTag = 0x1; inline constexpr size_t kMaxEventSizeReserve = 512; -inline constexpr uint16_t kRequiredEventField = +constexpr uint16_t kRequiredEventField = (1 << to_underlying(EventDataIB::Tag::kPriority)) | (1 << to_underlying(EventDataIB::Tag::kPath)); /** @@ -388,9 +388,6 @@ class EventManagement void SetScheduledEventInfo(EventNumber & aEventNumber, uint32_t & aInitialWrittenEventBytes) const; private: - constexpr EventManagement() = default; - static EventManagement sInstance; - /** * @brief * Internal structure for traversing events. @@ -558,9 +555,9 @@ class EventManagement MonotonicallyIncreasingCounter * mpEventNumberCounter = nullptr; EventNumber mLastEventNumber = 0; ///< Last event Number vended - Timestamp mLastEventTimestamp{}; ///< The timestamp of the last event in this buffer + Timestamp mLastEventTimestamp; ///< The timestamp of the last event in this buffer - System::Clock::Milliseconds64 mMonotonicStartupTime{}; + System::Clock::Milliseconds64 mMonotonicStartupTime; }; } // namespace app } // namespace chip diff --git a/src/app/cluster-building-blocks/BUILD.gn b/src/app/cluster-building-blocks/BUILD.gn new file mode 100644 index 00000000000000..dedce36ea43e6b --- /dev/null +++ b/src/app/cluster-building-blocks/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//build_overrides/chip.gni") + +source_set("cluster-building-blocks") { + sources = [ "QuieterReporting.h" ] + + public_deps = [ + "${chip_root}/src/app/data-model:nullable", + "${chip_root}/src/lib/support:support", + "${chip_root}/src/system", + ] +} diff --git a/src/app/cluster-building-blocks/QuieterReporting.h b/src/app/cluster-building-blocks/QuieterReporting.h new file mode 100644 index 00000000000000..d973f57c1a11ae --- /dev/null +++ b/src/app/cluster-building-blocks/QuieterReporting.h @@ -0,0 +1,241 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace chip { +namespace app { + +enum class QuieterReportingPolicyEnum +{ + kMarkDirtyOnChangeToFromZero = (1u << 0), + kMarkDirtyOnDecrement = (1u << 1), + kMarkDirtyOnIncrement = (1u << 2), +}; + +enum class AttributeDirtyState +{ + kNoReportNeeded = 0, + kMustReport = 1, +}; + +using QuieterReportingPolicyFlags = BitFlags; + +namespace detail { + +using Timestamp = System::Clock::Milliseconds64; +template +using Nullable = DataModel::Nullable; + +/** + * This class helps track reporting state of an attribute to properly keep track of whether + * it needs to be marked as dirty or not for purposes of reporting using + * "7.7.9 Quieter Reporting Quality" (Q quality) + * + * The class can be configured via `policy()` to have some/all of the common reasons + * for reporting (e.g. increment only, decrement only, change to/from zero). + * + * Changes of null to non-null or non-null to null are always considered dirty. + * + * It is possible to force mark the attribute as dirty (see `ForceDirty()`) such as + * for conditions like "When there is any increase or decrease in the estimated time + * remaining that was due to progressing insight of the server's control logic". + * + * Class maintains a `current value` and a timestamped `dirty` state. The `SetValue()` + * method must be used to update the `current value` and will return AttributeDirtyState::kMustReport + * if the attribute should be marked dirty/ + * + * - `SetValue()` has internal rules for null/non-null changes and policy-based rules + * - `SetValue()` with a `SufficientChangePredicate` uses the internal rules in addition to + * the predicate to determine dirty state + * + * See [QuieterReportingPolicyEnum] for policy flags on when a value is considered dirty + * beyond non/non-null changes. + * + * Common quieter reporting usecases that can be supported by this class are: + * - If attribute has changed due to a change in the X or Y attributes + * - Use SufficientChangePredicate version + * - When it changes from 0 to any other value and vice versa + * - Use `kMarkDirtyOnChangeToFromZero` internal policy. + * - When it changes from null to any other value and vice versa + * - Built-in rule. + * - When it increases + * - Use `kMarkDirtyOnIncrement` internal policy. + * - When it decreases + * - Use `kMarkDirtyOnDecrement` internal policy. + * - When there is any increase or decrease in the estimated time remaining that was + * due to progressing insight of the server's control logic + * - Use SufficientChangePredicate version with an always-true predicate. + * - When it changes at a rate significantly different from one unit per second. + * - Use SufficientChangePredicate version. + * Example usage in-situ: + * + * Class has: + * QuieterReportingAttribute mAttrib; + * + * Code at time of setting new value has: + * + * uint8_t newValue = driver.GetNewValue(); + * auto now = SystemClock().GetMonotonicTimestamp(); + * if (mAttrib.SetValue(newValue, now) == AttributeDirtyState::kMustReport) + * { + * MatterReportingAttributeChangeCallback(path_for_attribute); + * } + * + * @tparam T - the type of underlying numerical value that will be held by the class. + */ +template ::value, bool> = true> +class QuieterReportingAttribute +{ +public: + explicit QuieterReportingAttribute(const Nullable & initialValue) : mValue(initialValue), mLastDirtyValue(initialValue) {} + + struct SufficientChangePredicateCandidate + { + // Timestamp of last time attribute was marked dirty. + Timestamp lastDirtyTimestamp; + // New (`now`) timestamp passed in `SetValue()`. + Timestamp nowTimestamp; + // Value last marked as dirty. + const Nullable & lastDirtyValue; + // New value passed in `SetValue()`, to compare against lastDirtyValue for sufficient change if needed. + const Nullable & newValue; + }; + + using SufficientChangePredicate = std::function; + + /** + * @brief Factory to generate a functor for "attribute was last reported" at least `minimumDurationMillis` ago. + * + * @param minimumDurationMillis - number of millis needed since last marked as dirty before we mark dirty again. + * @return a functor usable for the `changedPredicate` arg of `SetValue()` + */ + static SufficientChangePredicate + GetPredicateForSufficientTimeSinceLastDirty(System::Clock::Milliseconds64 minimumDurationMillis) + { + return [minimumDurationMillis](const SufficientChangePredicateCandidate & candidate) -> bool { + return (candidate.lastDirtyValue != candidate.newValue) && + ((candidate.nowTimestamp - candidate.lastDirtyTimestamp) >= minimumDurationMillis); + }; + } + + /** + * @brief Factory to generate a functor that forces reportable now. + * @return a functor usable for the `changedPredicate` arg of `SetValue()` + */ + static SufficientChangePredicate GetForceReportablePredicate() + { + return [](const SufficientChangePredicateCandidate & candidate) -> bool { return true; }; + } + + Nullable value() const { return mValue; } + QuieterReportingPolicyFlags & policy() { return mPolicyFlags; } + const QuieterReportingPolicyFlags & policy() const { return mPolicyFlags; } + + /** + * Set the updated value of the attribute, computing whether it needs to be reported according to `changedPredicate` and + * policies. + * + * - Any change of nullability between `newValue` and the old value will be considered dirty. + * - The policies from `QuieterReportingPolicyEnum` and set via `SetPolicy()` are self-explanatory by name. + * - The changedPredicate will be called with last dirty and new and may override + * the dirty state altogether when it returns true. Use sparingly and default to a functor returning false. + * + * Internal recording will be done about last dirty value and last dirty timestamp based on the policies having applied. + * + * @param newValue - new value to set for the attribute + * @param now - system monotonic timestamp at the time of the call + * @param changedPredicate - functor to possibly override dirty state + * @return AttributeDirtyState::kMustReport if attribute must be marked dirty right away, or + * AttributeDirtyState::kNoReportNeeded otherwise. + */ + AttributeDirtyState SetValue(const chip::app::DataModel::Nullable & newValue, Timestamp now, + SufficientChangePredicate changedPredicate) + { + bool isChangeOfNull = newValue.IsNull() ^ mValue.IsNull(); + bool areBothValuesNonNull = !newValue.IsNull() && !mValue.IsNull(); + + bool changeToFromZero = areBothValuesNonNull && (*newValue == 0 || *mValue == 0); + bool isIncrement = areBothValuesNonNull && (*newValue > *mValue); + bool isDecrement = areBothValuesNonNull && (*newValue < *mValue); + + bool isNewlyDirty = isChangeOfNull; + isNewlyDirty = + isNewlyDirty || (mPolicyFlags.Has(QuieterReportingPolicyEnum::kMarkDirtyOnChangeToFromZero) && changeToFromZero); + isNewlyDirty = isNewlyDirty || (mPolicyFlags.Has(QuieterReportingPolicyEnum::kMarkDirtyOnDecrement) && isDecrement); + isNewlyDirty = isNewlyDirty || (mPolicyFlags.Has(QuieterReportingPolicyEnum::kMarkDirtyOnIncrement) && isIncrement); + + SufficientChangePredicateCandidate candidate{ + mLastDirtyTimestampMillis, // lastDirtyTimestamp + now, // nowTimestamp + mLastDirtyValue, // lastDirtyValue + newValue // newValue + }; + isNewlyDirty = isNewlyDirty || changedPredicate(candidate); + + mValue = newValue; + + if (isNewlyDirty) + { + mLastDirtyValue = newValue; + mLastDirtyTimestampMillis = now; + } + + return isNewlyDirty ? AttributeDirtyState::kMustReport : AttributeDirtyState::kNoReportNeeded; + } + + /** + * Same as the other `SetValue`, but assumes a changedPredicate that never overrides to dirty. + * + * This is the easy/common case. + * + * @param newValue - new value to set for the attribute + * @param now - system monotonic timestamp at the time of the call + * @return AttributeDirtyState::kMustReport if attribute must be marked dirty right away, or + * AttributeDirtyState::kNoReportNeeded otherwise. + */ + AttributeDirtyState SetValue(const chip::app::DataModel::Nullable & newValue, Timestamp now) + { + return SetValue(newValue, now, [](const SufficientChangePredicateCandidate &) -> bool { return false; }); + } + +protected: + // Current value of the attribute. + chip::app::DataModel::Nullable mValue; + // Last value that was marked as dirty (to use in comparisons for change, e.g. by SufficientChangePredicate). + chip::app::DataModel::Nullable mLastDirtyValue; + // Enabled internal change detection policies. + QuieterReportingPolicyFlags mPolicyFlags{ 0 }; + // Timestamp associated with the last time the attribute was marked dirty (to use in comparisons for change). + chip::System::Clock::Milliseconds64 mLastDirtyTimestampMillis{}; +}; + +} // namespace detail + +using detail::QuieterReportingAttribute; + +} // namespace app +} // namespace chip diff --git a/src/app/cluster-building-blocks/tests/BUILD.gn b/src/app/cluster-building-blocks/tests/BUILD.gn new file mode 100644 index 00000000000000..540e139213ef73 --- /dev/null +++ b/src/app/cluster-building-blocks/tests/BUILD.gn @@ -0,0 +1,30 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("${chip_root}/build/chip/chip_test_suite.gni") + +chip_test_suite("tests") { + output_name = "libAppClusterBuildingBlockTests" + + test_sources = [ "TestQuieterReporting.cpp" ] + + public_deps = [ + "${chip_root}/src/app/cluster-building-blocks", + "${chip_root}/src/app/data-model:nullable", + "${chip_root}/src/lib/core:error", + "${chip_root}/src/lib/support/tests:pw-test-macros", + "${chip_root}/src/system", + ] +} diff --git a/src/app/cluster-building-blocks/tests/TestQuieterReporting.cpp b/src/app/cluster-building-blocks/tests/TestQuieterReporting.cpp new file mode 100644 index 00000000000000..303d627029448e --- /dev/null +++ b/src/app/cluster-building-blocks/tests/TestQuieterReporting.cpp @@ -0,0 +1,262 @@ +/* + * + * Copyright (c) 2024 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. + */ + +#include + +#include + +#include +#include +#include + +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::DataModel; +using namespace chip::System::Clock; +using namespace chip::System::Clock::Literals; + +class FakeClock +{ +public: + FakeClock() = default; + + Timestamp Advance(Milliseconds64 numMillis) + { + mCurrentTimestamp += numMillis; + return mCurrentTimestamp; + } + + void SetMonotonic(Timestamp now) { mCurrentTimestamp = now; } + + Timestamp now() const { return mCurrentTimestamp; } + +private: + Timestamp mCurrentTimestamp{}; +}; + +TEST(TestQuieterReporting, ChangeToFromZeroPolicyWorks) +{ + FakeClock fakeClock; + fakeClock.SetMonotonic(100_ms); + + QuieterReportingAttribute attribute{ MakeNullable(10) }; + EXPECT_FALSE(attribute.value().IsNull()); + EXPECT_EQ(attribute.policy(), QuieterReportingPolicyFlags{}); + + auto now = fakeClock.now(); + + attribute.policy().Set(QuieterReportingPolicyEnum::kMarkDirtyOnChangeToFromZero); + EXPECT_TRUE(attribute.policy().HasOnly(QuieterReportingPolicyEnum::kMarkDirtyOnChangeToFromZero)); + + // 10 --> 11, expect not marked dirty yet. + EXPECT_EQ(attribute.SetValue(11, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 11); + + // 11 --> 0, expect marked dirty. + EXPECT_EQ(attribute.SetValue(0, now), AttributeDirtyState::kMustReport); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 0); + + // 0 --> 11, expect marked dirty. + EXPECT_EQ(attribute.SetValue(11, now), AttributeDirtyState::kMustReport); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 11); + + // 11 --> 12, expect not marked dirty. + EXPECT_EQ(attribute.SetValue(12, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 12); + + // Reset policy, expect 12 --> 0 does not mark dirty due to no longer having the policy that causes it. + attribute.policy().ClearAll(); + EXPECT_FALSE(attribute.policy().HasAny()); + + EXPECT_EQ(attribute.SetValue(0, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 0); +} + +TEST(TestQuieterReporting, ChangeOnIncrementPolicyWorks) +{ + FakeClock fakeClock; + fakeClock.SetMonotonic(100_ms); + + QuieterReportingAttribute attribute{ MakeNullable(10) }; + + // Always start not dirty (because first sub priming always just read value anyway). + ASSERT_EQ(*attribute.value(), 10); + + auto now = fakeClock.now(); + + attribute.policy().Set(QuieterReportingPolicyEnum::kMarkDirtyOnIncrement); + EXPECT_TRUE(attribute.policy().HasOnly(QuieterReportingPolicyEnum::kMarkDirtyOnIncrement)); + + // 10 --> 9, expect not marked dirty yet. + EXPECT_EQ(attribute.SetValue(9, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 9); + + // 9 --> 10, expect marked dirty. + EXPECT_EQ(attribute.SetValue(10, now), AttributeDirtyState::kMustReport); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 10); + + // 10 --> 11, expect marked dirty. + EXPECT_EQ(attribute.SetValue(11, now), AttributeDirtyState::kMustReport); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 11); + + // 11 --> 11, expect marked not dirty. + EXPECT_EQ(attribute.SetValue(11, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 11); + + // 11 --> null, expect marked dirty (null change always marks dirty) + EXPECT_EQ(attribute.SetValue(NullNullable, now), AttributeDirtyState::kMustReport); + EXPECT_TRUE(attribute.value().IsNull()); + + // null --> null, not dirty (no change) + EXPECT_EQ(attribute.SetValue(NullNullable, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_TRUE(attribute.value().IsNull()); + + // null --> 11, expect marked dirty (null change always marks dirty). + EXPECT_EQ(attribute.SetValue(11, now), AttributeDirtyState::kMustReport); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 11); + + // Reset policy, expect 11 --> 12 does not mark dirty due to no longer having the policy that causes it. + attribute.policy().ClearAll(); + EXPECT_FALSE(attribute.policy().HasAny()); + + EXPECT_EQ(attribute.SetValue(12, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 12); +} + +TEST(TestQuieterReporting, ChangeOnDecrementPolicyWorks) +{ + FakeClock fakeClock; + fakeClock.SetMonotonic(100_ms); + + QuieterReportingAttribute attribute{ MakeNullable(9) }; + + // Always start not dirty (because first sub priming always just read value anyway). + ASSERT_EQ(*attribute.value(), 9); + + auto now = fakeClock.now(); + + attribute.policy().Set(QuieterReportingPolicyEnum::kMarkDirtyOnDecrement); + EXPECT_TRUE(attribute.policy().HasOnly(QuieterReportingPolicyEnum::kMarkDirtyOnDecrement)); + + // 9 --> 10, expect not marked dirty yet. + EXPECT_EQ(attribute.SetValue(10, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 10); + + // 10 --> 9, expect marked dirty. + EXPECT_EQ(attribute.SetValue(9, now), AttributeDirtyState::kMustReport); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 9); + + // 9 --> 8, expect marked dirty. + EXPECT_EQ(attribute.SetValue(8, now), AttributeDirtyState::kMustReport); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 8); + + // Second call in a row always false. + + // 8 --> 8, expect not marked dirty. + EXPECT_EQ(attribute.SetValue(8, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 8); + + // 8 --> null, expect marked dirty (null change always marks dirty) + EXPECT_EQ(attribute.SetValue(NullNullable, now), AttributeDirtyState::kMustReport); + EXPECT_TRUE(attribute.value().IsNull()); + + // null --> null, not dirty (no change) + EXPECT_EQ(attribute.SetValue(NullNullable, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_TRUE(attribute.value().IsNull()); + + // null --> 11, expect marked dirty (null change always marks dirty). + EXPECT_EQ(attribute.SetValue(11, now), AttributeDirtyState::kMustReport); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 11); + + // Reset policy, expect 11 --> 10 does not mark dirty due to no longer having the policy that causes it. + attribute.policy().ClearAll(); + EXPECT_FALSE(attribute.policy().HasAny()); + + EXPECT_EQ(attribute.SetValue(10, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 10); +} + +TEST(TestQuieterReporting, SufficientChangePredicateWorks) +{ + FakeClock fakeClock; + fakeClock.SetMonotonic(100_ms); + + QuieterReportingAttribute attribute{ MakeNullable(9) }; + + // Always start not dirty (because first sub priming always just read value anyway). + ASSERT_EQ(*attribute.value(), 9); + + auto now = fakeClock.now(); + + EXPECT_EQ(attribute.SetValue(10, now), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 10); + + // Forcing dirty can be done with a force-true predicate + EXPECT_EQ(attribute.SetValue(10, now, attribute.GetForceReportablePredicate()), AttributeDirtyState::kMustReport); + + auto predicate = attribute.GetPredicateForSufficientTimeSinceLastDirty(1000_ms); + + now = fakeClock.Advance(100_ms); + + // Last dirty value is 10. This won't mark dirty again due to predicate mismatch. + EXPECT_EQ(attribute.SetValue(11, now, predicate), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 11); + + now = fakeClock.Advance(900_ms); + // Last dirty value is 10 still. This will mark dirty because both enough time has passed + // and value is different from the last dirty value. + EXPECT_EQ(attribute.SetValue(11, now, predicate), AttributeDirtyState::kMustReport); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 11); + + // Last dirty value is 11. Since there has not been a value change, no amount of time will + // mark dirty. + now = fakeClock.Advance(1000_ms); + EXPECT_EQ(attribute.SetValue(11, now, predicate), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 11); + + now = fakeClock.Advance(1000_ms); + EXPECT_EQ(attribute.SetValue(11, now, predicate), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 11); + + // Change the value to a value that marks dirty. + now = fakeClock.Advance(1_ms); + EXPECT_EQ(attribute.SetValue(12, now, predicate), AttributeDirtyState::kMustReport); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 12); + + // Wait a small delay and change again. Will not mark dirty due to too little time. + now = fakeClock.Advance(1_ms); + EXPECT_EQ(attribute.SetValue(13, now, predicate), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 13); + + now = fakeClock.Advance(1_ms); + EXPECT_EQ(attribute.SetValue(14, now, predicate), AttributeDirtyState::kNoReportNeeded); + EXPECT_EQ(attribute.value().ValueOr(INT_MAX), 14); + + // Change to a value that marks dirty no matter what (e.g. null). Should be dirty even + // before delay. + now = fakeClock.Advance(1_ms); + EXPECT_EQ(attribute.SetValue(NullNullable, now, predicate), AttributeDirtyState::kMustReport); + EXPECT_TRUE(attribute.value().IsNull()); + + // Null --> Null should not lead to dirty. + now = fakeClock.Advance(1000_ms); + EXPECT_EQ(attribute.SetValue(NullNullable, now, predicate), AttributeDirtyState::kNoReportNeeded); + EXPECT_TRUE(attribute.value().IsNull()); +} diff --git a/src/app/clusters/descriptor/descriptor.cpp b/src/app/clusters/descriptor/descriptor.cpp index 4eb68621c5767e..514051226fdcf5 100644 --- a/src/app/clusters/descriptor/descriptor.cpp +++ b/src/app/clusters/descriptor/descriptor.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -206,9 +205,7 @@ CHIP_ERROR DescriptorAttrAccess::ReadClusterRevision(EndpointId endpoint, Attrib return aEncoder.Encode(kClusterRevision); } -namespace { -Global gAttrAccess; -} +DescriptorAttrAccess gAttrAccess; CHIP_ERROR DescriptorAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) { @@ -247,5 +244,5 @@ CHIP_ERROR DescriptorAttrAccess::Read(const ConcreteReadAttributePath & aPath, A void MatterDescriptorPluginServerInitCallback() { - registerAttributeAccessOverride(&gAttrAccess.get()); + registerAttributeAccessOverride(&gAttrAccess); } diff --git a/src/app/codegen-data-model/CodegenDataModel.cpp b/src/app/codegen-data-model/CodegenDataModel.cpp index 0cc9b42aaa64f7..851f7c341ab127 100644 --- a/src/app/codegen-data-model/CodegenDataModel.cpp +++ b/src/app/codegen-data-model/CodegenDataModel.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -232,10 +233,19 @@ bool CodegenDataModel::EmberCommandListIterator::Exists(const CommandId * list, } CHIP_ERROR CodegenDataModel::Invoke(const InteractionModel::InvokeRequest & request, TLV::TLVReader & input_arguments, - InteractionModel::InvokeReply & reply) + CommandHandler * handler) { - // TODO: this needs an implementation - return CHIP_ERROR_NOT_IMPLEMENTED; + // TODO: CommandHandlerInterface support is currently + // residing in InteractionModelEngine itself. We may want to separate this out + // into its own registry, similar to attributes, so that IM is decoupled from actual storage of things. + // + // Open issue at https://github.com/project-chip/connectedhomeip/issues/34258 + + // Ember dispatching automatically uses `handler` to set an appropriate result or status + // This never fails (as handler error is encoded as needed). + DispatchSingleClusterCommand(request.path, input_arguments, handler); + + return CHIP_NO_ERROR; } EndpointId CodegenDataModel::FirstEndpoint() diff --git a/src/app/codegen-data-model/CodegenDataModel.h b/src/app/codegen-data-model/CodegenDataModel.h index b65f38b9155e73..123dcd72382291 100644 --- a/src/app/codegen-data-model/CodegenDataModel.h +++ b/src/app/codegen-data-model/CodegenDataModel.h @@ -71,7 +71,7 @@ class CodegenDataModel : public chip::app::InteractionModel::DataModel CHIP_ERROR ReadAttribute(const InteractionModel::ReadAttributeRequest & request, AttributeValueEncoder & encoder) override; CHIP_ERROR WriteAttribute(const InteractionModel::WriteAttributeRequest & request, AttributeValueDecoder & decoder) override; CHIP_ERROR Invoke(const InteractionModel::InvokeRequest & request, chip::TLV::TLVReader & input_arguments, - InteractionModel::InvokeReply & reply) override; + CommandHandler * handler) override; /// attribute tree iteration EndpointId FirstEndpoint() override; diff --git a/src/app/codegen-data-model/tests/BUILD.gn b/src/app/codegen-data-model/tests/BUILD.gn index 3d265a96a66b29..3f88ac61c41766 100644 --- a/src/app/codegen-data-model/tests/BUILD.gn +++ b/src/app/codegen-data-model/tests/BUILD.gn @@ -24,6 +24,8 @@ source_set("ember_extra_files") { "${chip_root}/src/app/util/ember-io-storage.cpp", "AttributeReportIBEncodeDecode.cpp", "AttributeReportIBEncodeDecode.h", + "EmberInvokeOverride.cpp", + "EmberInvokeOverride.h", "EmberReadWriteOverride.cpp", "EmberReadWriteOverride.h", "InteractionModelTemporaryOverrides.cpp", diff --git a/src/app/codegen-data-model/tests/EmberInvokeOverride.cpp b/src/app/codegen-data-model/tests/EmberInvokeOverride.cpp new file mode 100644 index 00000000000000..552e0be3d966ff --- /dev/null +++ b/src/app/codegen-data-model/tests/EmberInvokeOverride.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 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. + */ +#include "EmberInvokeOverride.h" + +#include + +namespace { + +chip::app::ConcreteCommandPath gLastDispatchPath; +uint32_t gDispatchCount = 0; + +} // namespace + +namespace chip { +namespace Test { + +app::ConcreteCommandPath GetLastDispatchPath() +{ + return gLastDispatchPath; +} + +uint32_t DispatchCount() +{ + return gDispatchCount; +} + +} // namespace Test +} // namespace chip + +namespace chip { +namespace app { + +void DispatchSingleClusterCommand(const ConcreteCommandPath & aRequestCommandPath, chip::TLV::TLVReader & aReader, + CommandHandler * apCommandObj) +{ + gLastDispatchPath = aRequestCommandPath; + gDispatchCount++; +} + +} // namespace app +} // namespace chip diff --git a/src/app/codegen-data-model/tests/EmberInvokeOverride.h b/src/app/codegen-data-model/tests/EmberInvokeOverride.h new file mode 100644 index 00000000000000..d2f7b5c32fb1f8 --- /dev/null +++ b/src/app/codegen-data-model/tests/EmberInvokeOverride.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 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 Test { + +/// what was the last path on which DispatchSingleClusterCommand was called +app::ConcreteCommandPath GetLastDispatchPath(); + +/// How many times was DispatchSingleClusterCommand called +uint32_t DispatchCount(); + +} // namespace Test +} // namespace chip diff --git a/src/app/codegen-data-model/tests/InteractionModelTemporaryOverrides.cpp b/src/app/codegen-data-model/tests/InteractionModelTemporaryOverrides.cpp index a595acc81f3b5c..e771827adf18f6 100644 --- a/src/app/codegen-data-model/tests/InteractionModelTemporaryOverrides.cpp +++ b/src/app/codegen-data-model/tests/InteractionModelTemporaryOverrides.cpp @@ -74,12 +74,6 @@ CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescr return CHIP_ERROR_NOT_IMPLEMENTED; } -void DispatchSingleClusterCommand(const ConcreteCommandPath & aRequestCommandPath, chip::TLV::TLVReader & aReader, - CommandHandler * apCommandObj) -{ - // TODO: total hardcoded noop -} - } // namespace app } // namespace chip diff --git a/src/app/codegen-data-model/tests/TestCodegenModelViaMocks.cpp b/src/app/codegen-data-model/tests/TestCodegenModelViaMocks.cpp index 2bf88a02bae6ef..e0fd4f6148f7c4 100644 --- a/src/app/codegen-data-model/tests/TestCodegenModelViaMocks.cpp +++ b/src/app/codegen-data-model/tests/TestCodegenModelViaMocks.cpp @@ -14,9 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "app/ConcreteCommandPath.h" #include #include +#include #include #include @@ -69,6 +71,9 @@ constexpr NodeId kTestNodeId = 0xFFFF'1234'ABCD'4321; constexpr AttributeId kAttributeIdReadOnly = 0x3001; constexpr AttributeId kAttributeIdTimedWrite = 0x3002; +constexpr CommandId kMockCommandId1 = 0x1234; +constexpr CommandId kMockCommandId2 = 0x1122; + constexpr EndpointId kEndpointIdThatIsMissing = kMockEndpointMin - 1; constexpr AttributeId kReadOnlyAttributeId = 0x5001; @@ -2430,6 +2435,47 @@ TEST(TestCodegenModelViaMocks, EmberWriteAttributeAccessInterfaceTest) TestEmberScalarNullWrite(); } +TEST(TestCodegenModelViaMocks, EmberInvokeTest) +{ + // Ember invoke is fully code-generated - there is a single function for Dispatch + // that will do a `switch` on the path elements and invoke a corresponding `emberAf*` + // callback. + // + // The only thing that can be validated is that this `DispatchSingleClusterCommand` + // is actually invoked. + + UseMockNodeConfig config(gTestNodeConfig); + chip::app::CodegenDataModel model; + + { + const ConcreteCommandPath kCommandPath(kMockEndpoint1, MockClusterId(1), kMockCommandId1); + const InvokeRequest kInvokeRequest{ .path = kCommandPath }; + chip::TLV::TLVReader tlvReader; + + const uint32_t kDispatchCountPre = chip::Test::DispatchCount(); + + // Using a handler set to nullptr as it is not used by the impl + ASSERT_EQ(model.Invoke(kInvokeRequest, tlvReader, /* handler = */ nullptr), CHIP_NO_ERROR); + + EXPECT_EQ(chip::Test::DispatchCount(), kDispatchCountPre + 1); // single dispatch + EXPECT_EQ(chip::Test::GetLastDispatchPath(), kCommandPath); // for the right path + } + + { + const ConcreteCommandPath kCommandPath(kMockEndpoint1, MockClusterId(1), kMockCommandId2); + const InvokeRequest kInvokeRequest{ .path = kCommandPath }; + chip::TLV::TLVReader tlvReader; + + const uint32_t kDispatchCountPre = chip::Test::DispatchCount(); + + // Using a handler set to nullpotr as it is not used by the impl + ASSERT_EQ(model.Invoke(kInvokeRequest, tlvReader, /* handler = */ nullptr), CHIP_NO_ERROR); + + EXPECT_EQ(chip::Test::DispatchCount(), kDispatchCountPre + 1); // single dispatch + EXPECT_EQ(chip::Test::GetLastDispatchPath(), kCommandPath); // for the right path + } +} + TEST(TestCodegenModelViaMocks, EmberWriteAttributeAccessInterfaceReturningError) { UseMockNodeConfig config(gTestNodeConfig); diff --git a/src/app/data-model-interface/BUILD.gn b/src/app/data-model-interface/BUILD.gn index 65cde75612e2ba..abe66a68f342bd 100644 --- a/src/app/data-model-interface/BUILD.gn +++ b/src/app/data-model-interface/BUILD.gn @@ -20,7 +20,6 @@ source_set("data-model-interface") { "DataModel.h", "DataModelChangeListener.h", "EventsGenerator.h", - "InvokeResponder.h", "MetadataTypes.cpp", "MetadataTypes.h", "OperationTypes.h", @@ -29,6 +28,7 @@ source_set("data-model-interface") { public_deps = [ "${chip_root}/src/access:types", "${chip_root}/src/app:attribute-access", + "${chip_root}/src/app:command-handler-interface", "${chip_root}/src/app:events", "${chip_root}/src/app:paths", "${chip_root}/src/app/MessageDef", diff --git a/src/app/data-model-interface/DataModel.h b/src/app/data-model-interface/DataModel.h index d673b79aac72a9..bcf24c1aa9e7b2 100644 --- a/src/app/data-model-interface/DataModel.h +++ b/src/app/data-model-interface/DataModel.h @@ -21,9 +21,9 @@ #include #include +#include #include -#include #include #include @@ -99,25 +99,9 @@ class DataModel : public DataModelMetadataTree /// - `NeedsTimedInteraction` for writes that are not timed however are required to be so virtual CHIP_ERROR WriteAttribute(const WriteAttributeRequest & request, AttributeValueDecoder & decoder) = 0; - /// `reply` is used to send back the reply. - /// - calling Reply() or ReplyAsync() will let the application control the reply - /// - returning a CHIP_NO_ERROR without reply/reply_async implies a Status::Success reply without data + /// `handler` is used to send back the reply. /// - returning a value other than CHIP_NO_ERROR implies an error reply (error and data are mutually exclusive) - /// - /// See InvokeReply/AutoCompleteInvokeResponder for details on how to send back replies and expected - /// error handling. If you need to know weather a response was successfully sent, use the underlying - /// `reply` object instead of returning an error code from Invoke. - /// - /// Return codes - /// CHIP_IM_GLOBAL_STATUS(code): - /// - error codes that are translatable to specific IM codes - /// - in particular, the following codes are interesting/expected - /// - `UnsupportedEndpoint` for invalid endpoint - /// - `UnsupportedCluster` for no such cluster on the endpoint - /// - `UnsupportedCommand` for no such command in the cluster - /// - `UnsupportedAccess` for permission errors (ACL or fabric scoped with invalid fabric) - /// - `NeedsTimedInteraction` if the invoke requires timed interaction support - virtual CHIP_ERROR Invoke(const InvokeRequest & request, chip::TLV::TLVReader & input_arguments, InvokeReply & reply) = 0; + virtual CHIP_ERROR Invoke(const InvokeRequest & request, chip::TLV::TLVReader & input_arguments, CommandHandler * handler) = 0; private: InteractionModelContext mContext = { nullptr }; diff --git a/src/app/data-model-interface/InvokeResponder.h b/src/app/data-model-interface/InvokeResponder.h deleted file mode 100644 index 9890c3bb6f6d7e..00000000000000 --- a/src/app/data-model-interface/InvokeResponder.h +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (c) 2024 Project CHIP Authors - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include -#include -#include - -namespace chip { -namespace app { -namespace InteractionModel { - -/// Handles encoding of an invoke response for a specific invoke request. -/// -/// This class handles a single request (i.e. a CommandDataIB within the -/// matter protocol) and is responsible for constructing its corresponding -/// response (i.e. a InvokeResponseIB within the matter protocol) -/// -/// Invoke responses MUST contain exactly ONE of: -/// - response data (accessed via `ResponseEncoder`) -/// - A status, which may be success or failure, both of which may -/// contain a cluster-specific error code. -/// -/// To encode a response, `Complete` MUST be called. -/// -/// `Complete` requirements -/// - Complete with InteractionModel::Status::Success will respond with data -/// some response data was written. -/// - Any other case (including success with cluster specific codes) implies -/// no response data and a status will be encoded instead -/// - this includes the case when some response data was written already. -/// In that case, the response data will be rolled back and only the status -/// will be encoded. -/// -/// Creating a response MAY be retried at most once, if and only if `Complete` -/// returns CHIP_ERROR_BUFFER_TOO_SMALL. Retry attempts MUST not exceed 1: -/// - FlushPendingResponses MUST be called to make as much buffer space as possible -/// available for encoding -/// - The response encoding (including `ResponseEncoder` usage and calling Complete) -/// MUST be retried once more. If the final Complete returns an error, the result -/// of the invoke will be an error status. -/// -class InvokeResponder -{ -public: - virtual ~InvokeResponder() = default; - - // Copying not allowed since underlying requirement is that on deletion of this - // object, a reply will be sent. - InvokeResponder(const InvokeResponder &) = delete; - InvokeResponder & operator=(const InvokeResponder &) = delete; - - /// Flush any pending replies before encoding the current reply. - /// - /// MAY be called at most once. - /// - /// This function is intended to provided the ability to retry sending a reply - /// if a reply encoding fails due to insufficient buffer. - /// - /// Call this if `Complete(...)` returns CHIP_ERROR_BUFFER_TOO_SMALL and try - /// again. If reply data is needed, the complete ResponseEncoder + Complete - /// call chain MUST be re-run. - virtual CHIP_ERROR FlushPendingResponses() = 0; - - /// Reply with a data payload. - /// - /// MUST be called at most once per reply. - /// Can be called a 2nd time after a `FlushPendingResponses()` call - /// - /// - responseCommandId must correspond with the data encoded in the returned encoder - /// - Complete(CHIP_NO_ERROR) MUST be called to flush the reply - /// - /// If encoder returns CHIP_ERROR_BUFFER_TOO_SMALL, FlushPendingResponses should be - /// used to attempt to free up buffer space then encoding should be tried again. - virtual DataModel::WrappedStructEncoder & ResponseEncoder(CommandId responseCommandId) = 0; - - /// Signal completing of the reply. - /// - /// MUST be called exactly once to signal a response is to be recorded to be sent. - /// The error code (and the data encoded by ResponseEncoder) may be buffered for - /// sending among other batched responses. - /// - /// If this returns CHIP_ERROR_BUFFER_TOO_SMALL, this can be called a 2nd time after - /// a FlushPendingResponses. - /// - /// Argument behavior: - /// - Commands can only be replied with ONE of the following (spec 8.9.4.4): - /// - command data (i.e. ResponseEncoder contents) - /// - A status (including success/error/cluster-specific-success-or-error ) - /// - As a result there are two possible paths: - /// - IF a Status::Success is given (WITHOUT cluster specific status), then - /// the data in ResponseEncoder is sent as a reply. If no data was sent, - /// a invoke `Status::Success` with no cluster specific data is sent - /// - OTHERWISE any previously encoded data via ResponseEncoder is discarded - /// and the given reply (success with cluster status or failure) is sent - /// as a reply to the invoke. - /// - /// - /// Returns success/failure state. One error code MUST be handled in particular: - /// - /// - CHIP_ERROR_BUFFER_TOO_SMALL will return IF AND ONLY IF the responder was unable - /// to fully serialize the given reply/error data. - /// - /// If such an error is returned, the caller MUST retry by calling FlushPendingResponses - /// first and then re-encoding the reply content (use ResponseEncoder if applicable and - /// call Complete again) - /// - /// - Any other error (i.e. different from CHIP_NO_ERROR) mean that the invoke response - /// will contain an error and such an error is considered permanent. - /// - virtual CHIP_ERROR Complete(StatusIB error) = 0; -}; - -/// Enforces that once acquired, Complete will be called on the underlying writer -class AutoCompleteInvokeResponder -{ -public: - // non-copyable: once you have a handle, keep it - AutoCompleteInvokeResponder(const AutoCompleteInvokeResponder &) = delete; - AutoCompleteInvokeResponder & operator=(const AutoCompleteInvokeResponder &) = delete; - - AutoCompleteInvokeResponder(InvokeResponder * writer) : mWriter(writer) {} - ~AutoCompleteInvokeResponder() - { - if (mCompleteState != CompleteState::kComplete) - { - mWriter->Complete(StatusIB{ Protocols::InteractionModel::Status::Failure }); - } - } - - /// Direct access to reply encoding. - /// - /// Use this only in conjunction with the other Raw* calls - DataModel::WrappedStructEncoder & RawResponseEncoder(CommandId replyCommandId) - { - return mWriter->ResponseEncoder(replyCommandId); - } - - /// Direct access to flushing replies - /// - /// Use this only in conjunction with the other Raw* calls - CHIP_ERROR RawFlushPendingReplies() - { - // allow a flush if we never called it (this may not be reasonable, however - // we accept an early flush) or if flush is expected - VerifyOrReturnError((mCompleteState == CompleteState::kNeverCalled) || (mCompleteState == CompleteState::kFlushExpected), - CHIP_ERROR_INCORRECT_STATE); - mCompleteState = CompleteState::kFlushed; - return mWriter->FlushPendingResponses(); - } - - /// Call "Complete" without the automatic retries. - /// - /// Use this in conjunction with the other Raw* calls - CHIP_ERROR RawComplete(StatusIB status) - { - VerifyOrReturnError((mCompleteState == CompleteState::kNeverCalled) || (mCompleteState == CompleteState::kFlushed), - CHIP_ERROR_INCORRECT_STATE); - CHIP_ERROR err = mWriter->Complete(status); - if ((err == CHIP_ERROR_BUFFER_TOO_SMALL) && (mCompleteState == CompleteState::kNeverCalled)) - { - mCompleteState = CompleteState::kFlushExpected; - } - else - { - mCompleteState = CompleteState::kComplete; - } - return err; - } - - /// Complete the given command. - /// - /// Automatically handles retries for sending. - /// Cannot be called after Raw* methods are used. - /// - /// Any error returned by this are final and not retriable - /// as a retry for CHIP_ERROR_BUFFER_TOO_SMALL is already built in. - CHIP_ERROR Complete(StatusIB status) - { - VerifyOrReturnError(mCompleteState == CompleteState::kNeverCalled, CHIP_ERROR_INCORRECT_STATE); - // this is a final complete, including retry handling - mCompleteState = CompleteState::kComplete; - CHIP_ERROR err = mWriter->Complete(status); - - if (err != CHIP_ERROR_BUFFER_TOO_SMALL) - { - return err; - } - - // retry once. Failure to flush is permanent. - ReturnErrorOnFailure(mWriter->FlushPendingResponses()); - return mWriter->Complete(status); - } - - /// Sends the specified data structure as a response - /// - /// This version of the send has built-in RETRY and handles - /// Flush/Complete automatically. - /// Cannot be called after Raw* methods are used. - /// - /// Any error returned by this are final and not retriable - /// as a retry for CHIP_ERROR_BUFFER_TOO_SMALL is already built in. - template - CHIP_ERROR Send(const ReplyData & data) - { - VerifyOrReturnError(mCompleteState == CompleteState::kNeverCalled, CHIP_ERROR_INCORRECT_STATE); - // this is a final complete, including retry handling - mCompleteState = CompleteState::kComplete; - CHIP_ERROR err = data.Encode(ResponseEncoder(ReplyData::GetCommandId())); - if (err != CHIP_ERROR_BUFFER_TOO_SMALL) - { - LogErrorOnFailure(err); - err = mWriter->Complete(StatusIB(err)); - } - if (err != CHIP_ERROR_BUFFER_TOO_SMALL) - { - return err; - } - - // retry once. Failure to flush is permanent. - ReturnErrorOnFailure(mWriter->FlushPendingResponses()); - err = data.Encode(ResponseEncoder(ReplyData::GetCommandId())); - - // If encoding fails, we will end up sending an error back to the other side - // the caller - LogErrorOnFailure(err); - if (err == CHIP_NO_ERROR) - { - err = mWriter->Complete(StatusIB(err)); - } - else - { - // Error in "complete" is not something we can really forward anymore since - // we already got an error in Encode ... just log this. - LogErrorOnFailure(mWriter->Complete(StatusIB(err))); - } - - return err; - } - -private: - // Contract says that complete may only be called twice: - // - initial complete - // - again after a `Flush` - // The states here expect we are in: - // - // +----------------------------Flush---------| - // | v - // NEVER --Complete--> F_EXPECTED --Flush--> FLUSHED --Complete--> COMPLETE - // | ^ - // +-------------(success or permanent error)-----------| - enum class CompleteState - { - kNeverCalled, - kFlushExpected, - kFlushed, - kComplete, - }; - - InvokeResponder * mWriter; - CompleteState mCompleteState = CompleteState::kNeverCalled; -}; - -enum ReplyAsyncFlags -{ - // Some commands that are expensive to process (e.g. crypto). - // Implementations may choose to send an ack on the message right away to - // avoid MRP retransmits. - kSlowCommandHandling = 0x0001, -}; - -class InvokeReply -{ -public: - virtual ~InvokeReply() = default; - - // reply with no data - CHIP_ERROR Reply(StatusIB status) { return this->Reply().Complete(status); } - - // Enqueue the content of the reply at this point in time (rather than Async sending it). - // - // Implementations will often batch several replies into one packet for batch commands, - // so it will be implementation-specific on when the actual reply packet is - // sent. - virtual AutoCompleteInvokeResponder Reply() = 0; - - // Reply "later" to the command. This allows async processing. A reply will be forced - // when the returned InvokeReply is destroyed. - // - // NOTE: Each InvokeReply is associated with a separate `CommandDataIB` within batch - // commands. When replying asynchronously, each InvokeReply will set the response - // data for the given commandpath/ref only. - // - // IF empty pointer is returned, insufficient memory to reply async is available and - // this should be handled (e.g. by returning an error to the handler/replying with - // an errorcode synchronously). - virtual std::unique_ptr ReplyAsync(BitFlags flags) = 0; -}; - -} // namespace InteractionModel -} // namespace app -} // namespace chip diff --git a/src/app/zap-templates/zcl/data-model/all.xml b/src/app/zap-templates/zcl/data-model/all.xml index 04fbb6fb6f309b..61d39b3b0173ea 100644 --- a/src/app/zap-templates/zcl/data-model/all.xml +++ b/src/app/zap-templates/zcl/data-model/all.xml @@ -18,6 +18,7 @@ + diff --git a/src/app/zap-templates/zcl/data-model/chip/commissioner-control-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/commissioner-control-cluster.xml new file mode 100644 index 00000000000000..7228b8f47a20ab --- /dev/null +++ b/src/app/zap-templates/zcl/data-model/chip/commissioner-control-cluster.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + General + Commissioner Control + 0x0751 + COMMISSIONER_CONTROL_CLUSTER + true + true + Supports the ability for clients to request the commissioning of themselves or other nodes onto a fabric which the cluster server can commission onto. + + + + + SupportedDeviceCategories + + + + + This command is sent by a client to request approval for a future CommissionNode call. + + + + + + + + + This command is sent by a client to request that the server begins commissioning a previously approved request. + + + + + + + + + + When received within the timeout specified by CommissionNode, the client SHALL open a commissioning window on to the node which the client called RequestCommissioningApproval to have commissioned. + + + + + + + + + This event SHALL be sent by the server following a RequestCommissioningApproval command which the server responded to with SUCCESS. + + + + + + + + diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index a220de465f3686..c6b39c837a1e00 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -33,6 +33,7 @@ "channel-cluster.xml", "clusters-extensions.xml", "color-control-cluster.xml", + "commissioner-control-cluster.xml", "concentration-measurement-cluster.xml", "content-launch-cluster.xml", "content-app-observer-cluster.xml", diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index 7c8b05d39fd708..18afa7eacc2f8a 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -32,6 +32,7 @@ "channel-cluster.xml", "clusters-extensions.xml", "color-control-cluster.xml", + "commissioner-control-cluster.xml", "concentration-measurement-cluster.xml", "content-launch-cluster.xml", "content-app-observer-cluster.xml", diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index 4c7757224b1a7d..dc324968991adc 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -23,6 +23,7 @@ "CHANNEL_CLUSTER": [], "CLIENT_MONITORING_CLUSTER": [], "COLOR_CONTROL_CLUSTER": [], + "COMMISSIONER_CONTROL_CLUSTER": [], "COMMISSIONING_CLUSTER": [], "CONTENT_LAUNCHER_CLUSTER": [], "CONTENT_CONTROL_CLUSTER": [], @@ -168,6 +169,7 @@ ], "CHANNEL_CLUSTER": ["channel-server"], "COLOR_CONTROL_CLUSTER": ["color-control-server"], + "COMMISSIONER_CONTROL_CLUSTER": ["commissioner-control-server"], "COMMISSIONING_CLUSTER": [], "CONTENT_LAUNCHER_CLUSTER": ["content-launch-server"], "CONTENT_CONTROL_CLUSTER": ["content-control-server"], diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 18ce0ab3cbf8a8..917e1a0584afe9 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -9198,6 +9198,57 @@ provisional cluster ContentAppObserver = 1296 { command ContentAppMessage(ContentAppMessageRequest): ContentAppMessageResponse = 0; } +/** Supports the ability for clients to request the commissioning of themselves or other nodes onto a fabric which the cluster server can commission onto. */ +provisional cluster CommissionerControl = 1873 { + revision 1; + + bitmap SupportedDeviceCategoryBitmap : bitmap32 { + kFabricSynchronization = 0x1; + } + + fabric_sensitive info event access(read: manage) CommissioningRequestResult = 0 { + int64u requestId = 0; + node_id clientNodeId = 1; + enum8 statusCode = 2; + fabric_idx fabricIndex = 254; + } + + readonly attribute access(read: manage) SupportedDeviceCategoryBitmap supportedDeviceCategories = 0; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct RequestCommissioningApprovalRequest { + int64u requestId = 0; + vendor_id vendorId = 1; + int16u productId = 2; + optional char_string<64> label = 3; + } + + request struct CommissionNodeRequest { + int64u requestId = 0; + int16u responseTimeoutSeconds = 1; + optional octet_string ipAddress = 2; + optional int16u port = 3; + } + + response struct ReverseOpenCommissioningWindow = 2 { + int16u commissioningTimeout = 0; + octet_string PAKEPasscodeVerifier = 1; + int16u discriminator = 2; + int32u iterations = 3; + octet_string<32> salt = 4; + } + + /** This command is sent by a client to request approval for a future CommissionNode call. */ + command access(invoke: manage) RequestCommissioningApproval(RequestCommissioningApprovalRequest): DefaultSuccess = 0; + /** This command is sent by a client to request that the server begins commissioning a previously approved request. */ + command access(invoke: manage) CommissionNode(CommissionNodeRequest): ReverseOpenCommissioningWindow = 1; +} + /** Attributes related to the electrical properties of a device. This cluster is used by power outlets and other devices that need to provide instantaneous data as opposed to metrology data which should be retrieved from the metering cluster.. */ deprecated cluster ElectricalMeasurement = 2820 { revision 3; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index 15ef0629b5daca..0e027a3c0c0647 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -60158,6 +60158,332 @@ public void onSuccess(byte[] tlv) { } } + public static class CommissionerControlCluster extends BaseChipCluster { + public static final long CLUSTER_ID = 1873L; + + private static final long SUPPORTED_DEVICE_CATEGORIES_ATTRIBUTE_ID = 0L; + private static final long GENERATED_COMMAND_LIST_ATTRIBUTE_ID = 65528L; + private static final long ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID = 65529L; + private static final long EVENT_LIST_ATTRIBUTE_ID = 65530L; + private static final long ATTRIBUTE_LIST_ATTRIBUTE_ID = 65531L; + private static final long FEATURE_MAP_ATTRIBUTE_ID = 65532L; + private static final long CLUSTER_REVISION_ATTRIBUTE_ID = 65533L; + + public CommissionerControlCluster(long devicePtr, int endpointId) { + super(devicePtr, endpointId, CLUSTER_ID); + } + + @Override + @Deprecated + public long initWithDevice(long devicePtr, int endpointId) { + return 0L; + } + + public void requestCommissioningApproval(DefaultClusterCallback callback, Long requestId, Integer vendorId, Integer productId, Optional label) { + requestCommissioningApproval(callback, requestId, vendorId, productId, label, 0); + } + + public void requestCommissioningApproval(DefaultClusterCallback callback, Long requestId, Integer vendorId, Integer productId, Optional label, int timedInvokeTimeoutMs) { + final long commandId = 0L; + + ArrayList elements = new ArrayList<>(); + final long requestIdFieldID = 0L; + BaseTLVType requestIdtlvValue = new UIntType(requestId); + elements.add(new StructElement(requestIdFieldID, requestIdtlvValue)); + + final long vendorIdFieldID = 1L; + BaseTLVType vendorIdtlvValue = new UIntType(vendorId); + elements.add(new StructElement(vendorIdFieldID, vendorIdtlvValue)); + + final long productIdFieldID = 2L; + BaseTLVType productIdtlvValue = new UIntType(productId); + elements.add(new StructElement(productIdFieldID, productIdtlvValue)); + + final long labelFieldID = 3L; + BaseTLVType labeltlvValue = label.map((nonOptionallabel) -> new StringType(nonOptionallabel)).orElse(new EmptyType()); + elements.add(new StructElement(labelFieldID, labeltlvValue)); + + StructType commandArgs = new StructType(elements); + invoke(new InvokeCallbackImpl(callback) { + @Override + public void onResponse(StructType invokeStructValue) { + callback.onSuccess(); + }}, commandId, commandArgs, timedInvokeTimeoutMs); + } + + public void commissionNode(ReverseOpenCommissioningWindowCallback callback, Long requestId, Integer responseTimeoutSeconds, Optional ipAddress, Optional port) { + commissionNode(callback, requestId, responseTimeoutSeconds, ipAddress, port, 0); + } + + public void commissionNode(ReverseOpenCommissioningWindowCallback callback, Long requestId, Integer responseTimeoutSeconds, Optional ipAddress, Optional port, int timedInvokeTimeoutMs) { + final long commandId = 1L; + + ArrayList elements = new ArrayList<>(); + final long requestIdFieldID = 0L; + BaseTLVType requestIdtlvValue = new UIntType(requestId); + elements.add(new StructElement(requestIdFieldID, requestIdtlvValue)); + + final long responseTimeoutSecondsFieldID = 1L; + BaseTLVType responseTimeoutSecondstlvValue = new UIntType(responseTimeoutSeconds); + elements.add(new StructElement(responseTimeoutSecondsFieldID, responseTimeoutSecondstlvValue)); + + final long ipAddressFieldID = 2L; + BaseTLVType ipAddresstlvValue = ipAddress.map((nonOptionalipAddress) -> new ByteArrayType(nonOptionalipAddress)).orElse(new EmptyType()); + elements.add(new StructElement(ipAddressFieldID, ipAddresstlvValue)); + + final long portFieldID = 3L; + BaseTLVType porttlvValue = port.map((nonOptionalport) -> new UIntType(nonOptionalport)).orElse(new EmptyType()); + elements.add(new StructElement(portFieldID, porttlvValue)); + + StructType commandArgs = new StructType(elements); + invoke(new InvokeCallbackImpl(callback) { + @Override + public void onResponse(StructType invokeStructValue) { + final long commissioningTimeoutFieldID = 0L; + Integer commissioningTimeout = null; + final long PAKEPasscodeVerifierFieldID = 1L; + byte[] PAKEPasscodeVerifier = null; + final long discriminatorFieldID = 2L; + Integer discriminator = null; + final long iterationsFieldID = 3L; + Long iterations = null; + final long saltFieldID = 4L; + byte[] salt = null; + for (StructElement element: invokeStructValue.value()) { + if (element.contextTagNum() == commissioningTimeoutFieldID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + commissioningTimeout = castingValue.value(Integer.class); + } + } else if (element.contextTagNum() == PAKEPasscodeVerifierFieldID) { + if (element.value(BaseTLVType.class).type() == TLVType.ByteArray) { + ByteArrayType castingValue = element.value(ByteArrayType.class); + PAKEPasscodeVerifier = castingValue.value(byte[].class); + } + } else if (element.contextTagNum() == discriminatorFieldID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + discriminator = castingValue.value(Integer.class); + } + } else if (element.contextTagNum() == iterationsFieldID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + iterations = castingValue.value(Long.class); + } + } else if (element.contextTagNum() == saltFieldID) { + if (element.value(BaseTLVType.class).type() == TLVType.ByteArray) { + ByteArrayType castingValue = element.value(ByteArrayType.class); + salt = castingValue.value(byte[].class); + } + } + } + callback.onSuccess(commissioningTimeout, PAKEPasscodeVerifier, discriminator, iterations, salt); + }}, commandId, commandArgs, timedInvokeTimeoutMs); + } + + public interface ReverseOpenCommissioningWindowCallback extends BaseClusterCallback { + void onSuccess(Integer commissioningTimeout, byte[] PAKEPasscodeVerifier, Integer discriminator, Long iterations, byte[] salt); + } + + public interface GeneratedCommandListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface AcceptedCommandListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface EventListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface AttributeListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public void readSupportedDeviceCategoriesAttribute( + LongAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SUPPORTED_DEVICE_CATEGORIES_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, SUPPORTED_DEVICE_CATEGORIES_ATTRIBUTE_ID, true); + } + + public void subscribeSupportedDeviceCategoriesAttribute( + LongAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SUPPORTED_DEVICE_CATEGORIES_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, SUPPORTED_DEVICE_CATEGORIES_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readGeneratedCommandListAttribute( + GeneratedCommandListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, GENERATED_COMMAND_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, GENERATED_COMMAND_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeGeneratedCommandListAttribute( + GeneratedCommandListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, GENERATED_COMMAND_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, GENERATED_COMMAND_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readAcceptedCommandListAttribute( + AcceptedCommandListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeAcceptedCommandListAttribute( + AcceptedCommandListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readEventListAttribute( + EventListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, EVENT_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, EVENT_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeEventListAttribute( + EventListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, EVENT_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, EVENT_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readAttributeListAttribute( + AttributeListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ATTRIBUTE_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ATTRIBUTE_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeAttributeListAttribute( + AttributeListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ATTRIBUTE_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ATTRIBUTE_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readFeatureMapAttribute( + LongAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, FEATURE_MAP_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, FEATURE_MAP_ATTRIBUTE_ID, true); + } + + public void subscribeFeatureMapAttribute( + LongAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, FEATURE_MAP_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, FEATURE_MAP_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readClusterRevisionAttribute( + IntegerAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CLUSTER_REVISION_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, CLUSTER_REVISION_ATTRIBUTE_ID, true); + } + + public void subscribeClusterRevisionAttribute( + IntegerAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CLUSTER_REVISION_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, CLUSTER_REVISION_ATTRIBUTE_ID, minInterval, maxInterval); + } + } + public static class ElectricalMeasurementCluster extends BaseChipCluster { public static final long CLUSTER_ID = 2820L; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java b/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java index 5cdcb6843ec864..d256c91c32d9ed 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java @@ -5976,6 +5976,97 @@ public String toString() { return output.toString(); } } +public static class CommissionerControlClusterCommissioningRequestResultEvent { + public Long requestId; + public Long clientNodeId; + public Integer statusCode; + public Integer fabricIndex; + private static final long REQUEST_ID_ID = 0L; + private static final long CLIENT_NODE_ID_ID = 1L; + private static final long STATUS_CODE_ID = 2L; + private static final long FABRIC_INDEX_ID = 254L; + + public CommissionerControlClusterCommissioningRequestResultEvent( + Long requestId, + Long clientNodeId, + Integer statusCode, + Integer fabricIndex + ) { + this.requestId = requestId; + this.clientNodeId = clientNodeId; + this.statusCode = statusCode; + this.fabricIndex = fabricIndex; + } + + public StructType encodeTlv() { + ArrayList values = new ArrayList<>(); + values.add(new StructElement(REQUEST_ID_ID, new UIntType(requestId))); + values.add(new StructElement(CLIENT_NODE_ID_ID, new UIntType(clientNodeId))); + values.add(new StructElement(STATUS_CODE_ID, new UIntType(statusCode))); + values.add(new StructElement(FABRIC_INDEX_ID, new UIntType(fabricIndex))); + + return new StructType(values); + } + + public static CommissionerControlClusterCommissioningRequestResultEvent decodeTlv(BaseTLVType tlvValue) { + if (tlvValue == null || tlvValue.type() != TLVType.Struct) { + return null; + } + Long requestId = null; + Long clientNodeId = null; + Integer statusCode = null; + Integer fabricIndex = null; + for (StructElement element: ((StructType)tlvValue).value()) { + if (element.contextTagNum() == REQUEST_ID_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + requestId = castingValue.value(Long.class); + } + } else if (element.contextTagNum() == CLIENT_NODE_ID_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + clientNodeId = castingValue.value(Long.class); + } + } else if (element.contextTagNum() == STATUS_CODE_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + statusCode = castingValue.value(Integer.class); + } + } else if (element.contextTagNum() == FABRIC_INDEX_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + fabricIndex = castingValue.value(Integer.class); + } + } + } + return new CommissionerControlClusterCommissioningRequestResultEvent( + requestId, + clientNodeId, + statusCode, + fabricIndex + ); + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("CommissionerControlClusterCommissioningRequestResultEvent {\n"); + output.append("\trequestId: "); + output.append(requestId); + output.append("\n"); + output.append("\tclientNodeId: "); + output.append(clientNodeId); + output.append("\n"); + output.append("\tstatusCode: "); + output.append(statusCode); + output.append("\n"); + output.append("\tfabricIndex: "); + output.append(fabricIndex); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } +} public static class UnitTestingClusterTestEventEvent { public Integer arg1; public Integer arg2; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java index 596b91f1920db5..698ee556bb324b 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java @@ -385,6 +385,9 @@ public static BaseCluster getCluster(long clusterId) { if (clusterId == ContentAppObserver.ID) { return new ContentAppObserver(); } + if (clusterId == CommissionerControl.ID) { + return new CommissionerControl(); + } if (clusterId == ElectricalMeasurement.ID) { return new ElectricalMeasurement(); } @@ -17038,6 +17041,144 @@ public long getCommandID(String name) throws IllegalArgumentException { return Command.valueOf(name).getID(); } } + public static class CommissionerControl implements BaseCluster { + public static final long ID = 1873L; + public long getID() { + return ID; + } + + public enum Attribute { + SupportedDeviceCategories(0L), + GeneratedCommandList(65528L), + AcceptedCommandList(65529L), + EventList(65530L), + AttributeList(65531L), + FeatureMap(65532L), + ClusterRevision(65533L),; + private final long id; + Attribute(long id) { + this.id = id; + } + + public long getID() { + return id; + } + + public static Attribute value(long id) throws NoSuchFieldError { + for (Attribute attribute : Attribute.values()) { + if (attribute.getID() == id) { + return attribute; + } + } + throw new NoSuchFieldError(); + } + } + + public enum Event { + CommissioningRequestResult(0L),; + private final long id; + Event(long id) { + this.id = id; + } + + public long getID() { + return id; + } + + public static Event value(long id) throws NoSuchFieldError { + for (Event event : Event.values()) { + if (event.getID() == id) { + return event; + } + } + throw new NoSuchFieldError(); + } + } + + public enum Command { + RequestCommissioningApproval(0L), + CommissionNode(1L),; + private final long id; + Command(long id) { + this.id = id; + } + + public long getID() { + return id; + } + + public static Command value(long id) throws NoSuchFieldError { + for (Command command : Command.values()) { + if (command.getID() == id) { + return command; + } + } + throw new NoSuchFieldError(); + } + }public enum RequestCommissioningApprovalCommandField {RequestId(0),VendorId(1),ProductId(2),Label(3),; + private final int id; + RequestCommissioningApprovalCommandField(int id) { + this.id = id; + } + + public int getID() { + return id; + } + public static RequestCommissioningApprovalCommandField value(int id) throws NoSuchFieldError { + for (RequestCommissioningApprovalCommandField field : RequestCommissioningApprovalCommandField.values()) { + if (field.getID() == id) { + return field; + } + } + throw new NoSuchFieldError(); + } + }public enum CommissionNodeCommandField {RequestId(0),ResponseTimeoutSeconds(1),IpAddress(2),Port(3),; + private final int id; + CommissionNodeCommandField(int id) { + this.id = id; + } + + public int getID() { + return id; + } + public static CommissionNodeCommandField value(int id) throws NoSuchFieldError { + for (CommissionNodeCommandField field : CommissionNodeCommandField.values()) { + if (field.getID() == id) { + return field; + } + } + throw new NoSuchFieldError(); + } + }@Override + public String getAttributeName(long id) throws NoSuchFieldError { + return Attribute.value(id).toString(); + } + + @Override + public String getEventName(long id) throws NoSuchFieldError { + return Event.value(id).toString(); + } + + @Override + public String getCommandName(long id) throws NoSuchFieldError { + return Command.value(id).toString(); + } + + @Override + public long getAttributeID(String name) throws IllegalArgumentException { + return Attribute.valueOf(name).getID(); + } + + @Override + public long getEventID(String name) throws IllegalArgumentException { + return Event.valueOf(name).getID(); + } + + @Override + public long getCommandID(String name) throws IllegalArgumentException { + return Command.valueOf(name).getID(); + } + } public static class ElectricalMeasurement implements BaseCluster { public static final long ID = 2820L; public long getID() { diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index dfe72ba2f8a7d9..06b24ad59e09af 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -19939,6 +19939,120 @@ public void onError(Exception ex) { } } + + public static class DelegatedCommissionerControlClusterReverseOpenCommissioningWindowCallback implements ChipClusters.CommissionerControlCluster.ReverseOpenCommissioningWindowCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(Integer commissioningTimeout, byte[] PAKEPasscodeVerifier, Integer discriminator, Long iterations, byte[] salt) { + Map responseValues = new LinkedHashMap<>(); + + CommandResponseInfo commissioningTimeoutResponseValue = new CommandResponseInfo("commissioningTimeout", "Integer"); + responseValues.put(commissioningTimeoutResponseValue, commissioningTimeout); + CommandResponseInfo PAKEPasscodeVerifierResponseValue = new CommandResponseInfo("PAKEPasscodeVerifier", "byte[]"); + responseValues.put(PAKEPasscodeVerifierResponseValue, PAKEPasscodeVerifier); + CommandResponseInfo discriminatorResponseValue = new CommandResponseInfo("discriminator", "Integer"); + responseValues.put(discriminatorResponseValue, discriminator); + CommandResponseInfo iterationsResponseValue = new CommandResponseInfo("iterations", "Long"); + responseValues.put(iterationsResponseValue, iterations); + CommandResponseInfo saltResponseValue = new CommandResponseInfo("salt", "byte[]"); + responseValues.put(saltResponseValue, salt); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception error) { + callback.onFailure(error); + } + } + public static class DelegatedCommissionerControlClusterGeneratedCommandListAttributeCallback implements ChipClusters.CommissionerControlCluster.GeneratedCommandListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedCommissionerControlClusterAcceptedCommandListAttributeCallback implements ChipClusters.CommissionerControlCluster.AcceptedCommandListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedCommissionerControlClusterEventListAttributeCallback implements ChipClusters.CommissionerControlCluster.EventListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedCommissionerControlClusterAttributeListAttributeCallback implements ChipClusters.CommissionerControlCluster.AttributeListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + public static class DelegatedElectricalMeasurementClusterGeneratedCommandListAttributeCallback implements ChipClusters.ElectricalMeasurementCluster.GeneratedCommandListAttributeCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override @@ -22040,6 +22154,10 @@ public Map initializeClusterMap() { (ptr, endpointId) -> new ChipClusters.ContentAppObserverCluster(ptr, endpointId), new HashMap<>()); clusterMap.put("contentAppObserver", contentAppObserverClusterInfo); + ClusterInfo commissionerControlClusterInfo = new ClusterInfo( + (ptr, endpointId) -> new ChipClusters.CommissionerControlCluster(ptr, endpointId), new HashMap<>()); + clusterMap.put("commissionerControl", commissionerControlClusterInfo); + ClusterInfo electricalMeasurementClusterInfo = new ClusterInfo( (ptr, endpointId) -> new ChipClusters.ElectricalMeasurementCluster(ptr, endpointId), new HashMap<>()); clusterMap.put("electricalMeasurement", electricalMeasurementClusterInfo); @@ -22179,6 +22297,7 @@ public void combineCommand(Map destination, Map> getCommandMap() { commandMap.put("contentAppObserver", contentAppObserverClusterInteractionInfoMap); + Map commissionerControlClusterInteractionInfoMap = new LinkedHashMap<>(); + + Map commissionerControlrequestCommissioningApprovalCommandParams = new LinkedHashMap(); + + CommandParameterInfo commissionerControlrequestCommissioningApprovalrequestIdCommandParameterInfo = new CommandParameterInfo("requestId", Long.class, Long.class); + commissionerControlrequestCommissioningApprovalCommandParams.put("requestId",commissionerControlrequestCommissioningApprovalrequestIdCommandParameterInfo); + + CommandParameterInfo commissionerControlrequestCommissioningApprovalvendorIdCommandParameterInfo = new CommandParameterInfo("vendorId", Integer.class, Integer.class); + commissionerControlrequestCommissioningApprovalCommandParams.put("vendorId",commissionerControlrequestCommissioningApprovalvendorIdCommandParameterInfo); + + CommandParameterInfo commissionerControlrequestCommissioningApprovalproductIdCommandParameterInfo = new CommandParameterInfo("productId", Integer.class, Integer.class); + commissionerControlrequestCommissioningApprovalCommandParams.put("productId",commissionerControlrequestCommissioningApprovalproductIdCommandParameterInfo); + + CommandParameterInfo commissionerControlrequestCommissioningApprovallabelCommandParameterInfo = new CommandParameterInfo("label", Optional.class, String.class); + commissionerControlrequestCommissioningApprovalCommandParams.put("label",commissionerControlrequestCommissioningApprovallabelCommandParameterInfo); + InteractionInfo commissionerControlrequestCommissioningApprovalInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.CommissionerControlCluster) cluster) + .requestCommissioningApproval((DefaultClusterCallback) callback + , (Long) + commandArguments.get("requestId") + , (Integer) + commandArguments.get("vendorId") + , (Integer) + commandArguments.get("productId") + , (Optional) + commandArguments.get("label") + ); + }, + () -> new DelegatedDefaultClusterCallback(), + commissionerControlrequestCommissioningApprovalCommandParams + ); + commissionerControlClusterInteractionInfoMap.put("requestCommissioningApproval", commissionerControlrequestCommissioningApprovalInteractionInfo); + + Map commissionerControlcommissionNodeCommandParams = new LinkedHashMap(); + + CommandParameterInfo commissionerControlcommissionNoderequestIdCommandParameterInfo = new CommandParameterInfo("requestId", Long.class, Long.class); + commissionerControlcommissionNodeCommandParams.put("requestId",commissionerControlcommissionNoderequestIdCommandParameterInfo); + + CommandParameterInfo commissionerControlcommissionNoderesponseTimeoutSecondsCommandParameterInfo = new CommandParameterInfo("responseTimeoutSeconds", Integer.class, Integer.class); + commissionerControlcommissionNodeCommandParams.put("responseTimeoutSeconds",commissionerControlcommissionNoderesponseTimeoutSecondsCommandParameterInfo); + + CommandParameterInfo commissionerControlcommissionNodeipAddressCommandParameterInfo = new CommandParameterInfo("ipAddress", Optional.class, byte[].class); + commissionerControlcommissionNodeCommandParams.put("ipAddress",commissionerControlcommissionNodeipAddressCommandParameterInfo); + + CommandParameterInfo commissionerControlcommissionNodeportCommandParameterInfo = new CommandParameterInfo("port", Optional.class, Integer.class); + commissionerControlcommissionNodeCommandParams.put("port",commissionerControlcommissionNodeportCommandParameterInfo); + InteractionInfo commissionerControlcommissionNodeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.CommissionerControlCluster) cluster) + .commissionNode((ChipClusters.CommissionerControlCluster.ReverseOpenCommissioningWindowCallback) callback + , (Long) + commandArguments.get("requestId") + + , (Integer) + commandArguments.get("responseTimeoutSeconds") + + , (Optional) + commandArguments.get("ipAddress") + + , (Optional) + commandArguments.get("port") + + ); + }, + () -> new DelegatedCommissionerControlClusterReverseOpenCommissioningWindowCallback(), + commissionerControlcommissionNodeCommandParams + ); + commissionerControlClusterInteractionInfoMap.put("commissionNode", commissionerControlcommissionNodeInteractionInfo); + + commandMap.put("commissionerControl", commissionerControlClusterInteractionInfoMap); + Map electricalMeasurementClusterInteractionInfoMap = new LinkedHashMap<>(); Map electricalMeasurementgetProfileInfoCommandCommandParams = new LinkedHashMap(); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java index 25549f9f6a6b6a..a15dca9774da6b 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java @@ -18475,6 +18475,87 @@ private static Map readContentAppObserverInteractionInf return result; } + private static Map readCommissionerControlInteractionInfo() { + Map result = new LinkedHashMap<>();Map readCommissionerControlSupportedDeviceCategoriesCommandParams = new LinkedHashMap(); + InteractionInfo readCommissionerControlSupportedDeviceCategoriesAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.CommissionerControlCluster) cluster).readSupportedDeviceCategoriesAttribute( + (ChipClusters.LongAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedLongAttributeCallback(), + readCommissionerControlSupportedDeviceCategoriesCommandParams + ); + result.put("readSupportedDeviceCategoriesAttribute", readCommissionerControlSupportedDeviceCategoriesAttributeInteractionInfo); + Map readCommissionerControlGeneratedCommandListCommandParams = new LinkedHashMap(); + InteractionInfo readCommissionerControlGeneratedCommandListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.CommissionerControlCluster) cluster).readGeneratedCommandListAttribute( + (ChipClusters.CommissionerControlCluster.GeneratedCommandListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedCommissionerControlClusterGeneratedCommandListAttributeCallback(), + readCommissionerControlGeneratedCommandListCommandParams + ); + result.put("readGeneratedCommandListAttribute", readCommissionerControlGeneratedCommandListAttributeInteractionInfo); + Map readCommissionerControlAcceptedCommandListCommandParams = new LinkedHashMap(); + InteractionInfo readCommissionerControlAcceptedCommandListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.CommissionerControlCluster) cluster).readAcceptedCommandListAttribute( + (ChipClusters.CommissionerControlCluster.AcceptedCommandListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedCommissionerControlClusterAcceptedCommandListAttributeCallback(), + readCommissionerControlAcceptedCommandListCommandParams + ); + result.put("readAcceptedCommandListAttribute", readCommissionerControlAcceptedCommandListAttributeInteractionInfo); + Map readCommissionerControlEventListCommandParams = new LinkedHashMap(); + InteractionInfo readCommissionerControlEventListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.CommissionerControlCluster) cluster).readEventListAttribute( + (ChipClusters.CommissionerControlCluster.EventListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedCommissionerControlClusterEventListAttributeCallback(), + readCommissionerControlEventListCommandParams + ); + result.put("readEventListAttribute", readCommissionerControlEventListAttributeInteractionInfo); + Map readCommissionerControlAttributeListCommandParams = new LinkedHashMap(); + InteractionInfo readCommissionerControlAttributeListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.CommissionerControlCluster) cluster).readAttributeListAttribute( + (ChipClusters.CommissionerControlCluster.AttributeListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedCommissionerControlClusterAttributeListAttributeCallback(), + readCommissionerControlAttributeListCommandParams + ); + result.put("readAttributeListAttribute", readCommissionerControlAttributeListAttributeInteractionInfo); + Map readCommissionerControlFeatureMapCommandParams = new LinkedHashMap(); + InteractionInfo readCommissionerControlFeatureMapAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.CommissionerControlCluster) cluster).readFeatureMapAttribute( + (ChipClusters.LongAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedLongAttributeCallback(), + readCommissionerControlFeatureMapCommandParams + ); + result.put("readFeatureMapAttribute", readCommissionerControlFeatureMapAttributeInteractionInfo); + Map readCommissionerControlClusterRevisionCommandParams = new LinkedHashMap(); + InteractionInfo readCommissionerControlClusterRevisionAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.CommissionerControlCluster) cluster).readClusterRevisionAttribute( + (ChipClusters.IntegerAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), + readCommissionerControlClusterRevisionCommandParams + ); + result.put("readClusterRevisionAttribute", readCommissionerControlClusterRevisionAttributeInteractionInfo); + + return result; + } private static Map readElectricalMeasurementInteractionInfo() { Map result = new LinkedHashMap<>();Map readElectricalMeasurementMeasurementTypeCommandParams = new LinkedHashMap(); InteractionInfo readElectricalMeasurementMeasurementTypeAttributeInteractionInfo = new InteractionInfo( @@ -21188,6 +21269,7 @@ public Map> getReadAttributeMap() { put("accountLogin", readAccountLoginInteractionInfo()); put("contentControl", readContentControlInteractionInfo()); put("contentAppObserver", readContentAppObserverInteractionInfo()); + put("commissionerControl", readCommissionerControlInteractionInfo()); put("electricalMeasurement", readElectricalMeasurementInteractionInfo()); put("unitTesting", readUnitTestingInteractionInfo()); put("faultInjection", readFaultInjectionInteractionInfo()); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java index fff901e8da037a..635f5bf1b48830 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java @@ -3718,6 +3718,8 @@ public Map> getWriteAttributeMap() { writeAttributeMap.put("contentControl", writeContentControlInteractionInfo); Map writeContentAppObserverInteractionInfo = new LinkedHashMap<>(); writeAttributeMap.put("contentAppObserver", writeContentAppObserverInteractionInfo); + Map writeCommissionerControlInteractionInfo = new LinkedHashMap<>(); + writeAttributeMap.put("commissionerControl", writeCommissionerControlInteractionInfo); Map writeElectricalMeasurementInteractionInfo = new LinkedHashMap<>(); Map writeElectricalMeasurementAverageRmsVoltageMeasurementPeriodCommandParams = new LinkedHashMap(); CommandParameterInfo electricalMeasurementaverageRmsVoltageMeasurementPeriodCommandParameterInfo = diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/CommissionerControlClusterCommissioningRequestResultEvent.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/CommissionerControlClusterCommissioningRequestResultEvent.kt new file mode 100644 index 00000000000000..2a7a8d3c5b8ffb --- /dev/null +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/CommissionerControlClusterCommissioningRequestResultEvent.kt @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package chip.devicecontroller.cluster.eventstructs + +import chip.devicecontroller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class CommissionerControlClusterCommissioningRequestResultEvent( + val requestId: ULong, + val clientNodeId: ULong, + val statusCode: UInt, + val fabricIndex: UInt, +) { + override fun toString(): String = buildString { + append("CommissionerControlClusterCommissioningRequestResultEvent {\n") + append("\trequestId : $requestId\n") + append("\tclientNodeId : $clientNodeId\n") + append("\tstatusCode : $statusCode\n") + append("\tfabricIndex : $fabricIndex\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_REQUEST_ID), requestId) + put(ContextSpecificTag(TAG_CLIENT_NODE_ID), clientNodeId) + put(ContextSpecificTag(TAG_STATUS_CODE), statusCode) + put(ContextSpecificTag(TAG_FABRIC_INDEX), fabricIndex) + endStructure() + } + } + + companion object { + private const val TAG_REQUEST_ID = 0 + private const val TAG_CLIENT_NODE_ID = 1 + private const val TAG_STATUS_CODE = 2 + private const val TAG_FABRIC_INDEX = 254 + + fun fromTlv( + tlvTag: Tag, + tlvReader: TlvReader, + ): CommissionerControlClusterCommissioningRequestResultEvent { + tlvReader.enterStructure(tlvTag) + val requestId = tlvReader.getULong(ContextSpecificTag(TAG_REQUEST_ID)) + val clientNodeId = tlvReader.getULong(ContextSpecificTag(TAG_CLIENT_NODE_ID)) + val statusCode = tlvReader.getUInt(ContextSpecificTag(TAG_STATUS_CODE)) + val fabricIndex = tlvReader.getUInt(ContextSpecificTag(TAG_FABRIC_INDEX)) + + tlvReader.exitContainer() + + return CommissionerControlClusterCommissioningRequestResultEvent( + requestId, + clientNodeId, + statusCode, + fabricIndex, + ) + } + } +} diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni index a62e5ec79a241e..631feb9442d4c0 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni @@ -163,6 +163,7 @@ eventstructs_sources = [ "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterReachableChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterStartUpEvent.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/CommissionerControlClusterCommissioningRequestResultEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/DemandResponseLoadControlClusterLoadControlEventStatusChangeEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/DeviceEnergyManagementClusterPowerAdjustEndEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/DeviceEnergyManagementClusterResumedEvent.kt", diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/CommissionerControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/CommissionerControlCluster.kt new file mode 100644 index 00000000000000..6a3d288d56e49c --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/CommissionerControlCluster.kt @@ -0,0 +1,874 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package matter.controller.cluster.clusters + +import java.time.Duration +import java.util.logging.Level +import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.InvokeRequest +import matter.controller.InvokeResponse +import matter.controller.MatterController +import matter.controller.ReadData +import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState +import matter.controller.cluster.structs.* +import matter.controller.model.AttributePath +import matter.controller.model.CommandPath +import matter.tlv.AnonymousTag +import matter.tlv.ContextSpecificTag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class CommissionerControlCluster( + private val controller: MatterController, + private val endpointId: UShort, +) { + class ReverseOpenCommissioningWindow( + val commissioningTimeout: UShort, + val PAKEPasscodeVerifier: ByteArray, + val discriminator: UShort, + val iterations: UInt, + val salt: ByteArray, + ) + + class GeneratedCommandListAttribute(val value: List) + + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + + class AcceptedCommandListAttribute(val value: List) + + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + + class EventListAttribute(val value: List) + + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + + class AttributeListAttribute(val value: List) + + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + + suspend fun requestCommissioningApproval( + requestId: ULong, + vendorId: UShort, + productId: UShort, + label: String?, + timedInvokeTimeout: Duration? = null, + ) { + val commandId: UInt = 0u + + val tlvWriter = TlvWriter() + tlvWriter.startStructure(AnonymousTag) + + val TAG_REQUEST_ID_REQ: Int = 0 + tlvWriter.put(ContextSpecificTag(TAG_REQUEST_ID_REQ), requestId) + + val TAG_VENDOR_ID_REQ: Int = 1 + tlvWriter.put(ContextSpecificTag(TAG_VENDOR_ID_REQ), vendorId) + + val TAG_PRODUCT_ID_REQ: Int = 2 + tlvWriter.put(ContextSpecificTag(TAG_PRODUCT_ID_REQ), productId) + + val TAG_LABEL_REQ: Int = 3 + label?.let { tlvWriter.put(ContextSpecificTag(TAG_LABEL_REQ), label) } + tlvWriter.endStructure() + + val request: InvokeRequest = + InvokeRequest( + CommandPath(endpointId, clusterId = CLUSTER_ID, commandId), + tlvPayload = tlvWriter.getEncoded(), + timedRequest = timedInvokeTimeout, + ) + + val response: InvokeResponse = controller.invoke(request) + logger.log(Level.FINE, "Invoke command succeeded: ${response}") + } + + suspend fun commissionNode( + requestId: ULong, + responseTimeoutSeconds: UShort, + ipAddress: ByteArray?, + port: UShort?, + timedInvokeTimeout: Duration? = null, + ): ReverseOpenCommissioningWindow { + val commandId: UInt = 1u + + val tlvWriter = TlvWriter() + tlvWriter.startStructure(AnonymousTag) + + val TAG_REQUEST_ID_REQ: Int = 0 + tlvWriter.put(ContextSpecificTag(TAG_REQUEST_ID_REQ), requestId) + + val TAG_RESPONSE_TIMEOUT_SECONDS_REQ: Int = 1 + tlvWriter.put(ContextSpecificTag(TAG_RESPONSE_TIMEOUT_SECONDS_REQ), responseTimeoutSeconds) + + val TAG_IP_ADDRESS_REQ: Int = 2 + ipAddress?.let { tlvWriter.put(ContextSpecificTag(TAG_IP_ADDRESS_REQ), ipAddress) } + + val TAG_PORT_REQ: Int = 3 + port?.let { tlvWriter.put(ContextSpecificTag(TAG_PORT_REQ), port) } + tlvWriter.endStructure() + + val request: InvokeRequest = + InvokeRequest( + CommandPath(endpointId, clusterId = CLUSTER_ID, commandId), + tlvPayload = tlvWriter.getEncoded(), + timedRequest = timedInvokeTimeout, + ) + + val response: InvokeResponse = controller.invoke(request) + logger.log(Level.FINE, "Invoke command succeeded: ${response}") + + val tlvReader = TlvReader(response.payload) + tlvReader.enterStructure(AnonymousTag) + val TAG_COMMISSIONING_TIMEOUT: Int = 0 + var commissioningTimeout_decoded: UShort? = null + + val TAG_P_A_K_E_PASSCODE_VERIFIER: Int = 1 + var PAKEPasscodeVerifier_decoded: ByteArray? = null + + val TAG_DISCRIMINATOR: Int = 2 + var discriminator_decoded: UShort? = null + + val TAG_ITERATIONS: Int = 3 + var iterations_decoded: UInt? = null + + val TAG_SALT: Int = 4 + var salt_decoded: ByteArray? = null + + while (!tlvReader.isEndOfContainer()) { + val tag = tlvReader.peekElement().tag + + if (tag == ContextSpecificTag(TAG_COMMISSIONING_TIMEOUT)) { + commissioningTimeout_decoded = tlvReader.getUShort(tag) + } + + if (tag == ContextSpecificTag(TAG_P_A_K_E_PASSCODE_VERIFIER)) { + PAKEPasscodeVerifier_decoded = tlvReader.getByteArray(tag) + } + + if (tag == ContextSpecificTag(TAG_DISCRIMINATOR)) { + discriminator_decoded = tlvReader.getUShort(tag) + } + + if (tag == ContextSpecificTag(TAG_ITERATIONS)) { + iterations_decoded = tlvReader.getUInt(tag) + } + + if (tag == ContextSpecificTag(TAG_SALT)) { + salt_decoded = tlvReader.getByteArray(tag) + } else { + tlvReader.skipElement() + } + } + + if (commissioningTimeout_decoded == null) { + throw IllegalStateException("commissioningTimeout not found in TLV") + } + + if (PAKEPasscodeVerifier_decoded == null) { + throw IllegalStateException("PAKEPasscodeVerifier not found in TLV") + } + + if (discriminator_decoded == null) { + throw IllegalStateException("discriminator not found in TLV") + } + + if (iterations_decoded == null) { + throw IllegalStateException("iterations not found in TLV") + } + + if (salt_decoded == null) { + throw IllegalStateException("salt not found in TLV") + } + + tlvReader.exitContainer() + + return ReverseOpenCommissioningWindow( + commissioningTimeout_decoded, + PAKEPasscodeVerifier_decoded, + discriminator_decoded, + iterations_decoded, + salt_decoded, + ) + } + + suspend fun readSupportedDeviceCategoriesAttribute(): UInt { + val ATTRIBUTE_ID: UInt = 0u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Supporteddevicecategories attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + return decodedValue + } + + suspend fun subscribeSupportedDeviceCategoriesAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supporteddevicecategories attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { + val ATTRIBUTE_ID: UInt = 65528u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Generatedcommandlist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return GeneratedCommandListAttribute(decodedValue) + } + + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { + val ATTRIBUTE_ID: UInt = 65529u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Acceptedcommandlist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return AcceptedCommandListAttribute(decodedValue) + } + + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readEventListAttribute(): EventListAttribute { + val ATTRIBUTE_ID: UInt = 65530u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Eventlist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return EventListAttribute(decodedValue) + } + + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readAttributeListAttribute(): AttributeListAttribute { + val ATTRIBUTE_ID: UInt = 65531u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Attributelist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return AttributeListAttribute(decodedValue) + } + + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readFeatureMapAttribute(): UInt { + val ATTRIBUTE_ID: UInt = 65532u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Featuremap attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + return decodedValue + } + + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readClusterRevisionAttribute(): UShort { + val ATTRIBUTE_ID: UInt = 65533u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Clusterrevision attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + return decodedValue + } + + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + + companion object { + private val logger = Logger.getLogger(CommissionerControlCluster::class.java.name) + const val CLUSTER_ID: UInt = 1873u + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/eventstructs/CommissionerControlClusterCommissioningRequestResultEvent.kt b/src/controller/java/generated/java/matter/controller/cluster/eventstructs/CommissionerControlClusterCommissioningRequestResultEvent.kt new file mode 100644 index 00000000000000..c8947776269773 --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/eventstructs/CommissionerControlClusterCommissioningRequestResultEvent.kt @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package matter.controller.cluster.eventstructs + +import matter.controller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class CommissionerControlClusterCommissioningRequestResultEvent( + val requestId: ULong, + val clientNodeId: ULong, + val statusCode: UByte, + val fabricIndex: UByte, +) { + override fun toString(): String = buildString { + append("CommissionerControlClusterCommissioningRequestResultEvent {\n") + append("\trequestId : $requestId\n") + append("\tclientNodeId : $clientNodeId\n") + append("\tstatusCode : $statusCode\n") + append("\tfabricIndex : $fabricIndex\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_REQUEST_ID), requestId) + put(ContextSpecificTag(TAG_CLIENT_NODE_ID), clientNodeId) + put(ContextSpecificTag(TAG_STATUS_CODE), statusCode) + put(ContextSpecificTag(TAG_FABRIC_INDEX), fabricIndex) + endStructure() + } + } + + companion object { + private const val TAG_REQUEST_ID = 0 + private const val TAG_CLIENT_NODE_ID = 1 + private const val TAG_STATUS_CODE = 2 + private const val TAG_FABRIC_INDEX = 254 + + fun fromTlv( + tlvTag: Tag, + tlvReader: TlvReader, + ): CommissionerControlClusterCommissioningRequestResultEvent { + tlvReader.enterStructure(tlvTag) + val requestId = tlvReader.getULong(ContextSpecificTag(TAG_REQUEST_ID)) + val clientNodeId = tlvReader.getULong(ContextSpecificTag(TAG_CLIENT_NODE_ID)) + val statusCode = tlvReader.getUByte(ContextSpecificTag(TAG_STATUS_CODE)) + val fabricIndex = tlvReader.getUByte(ContextSpecificTag(TAG_FABRIC_INDEX)) + + tlvReader.exitContainer() + + return CommissionerControlClusterCommissioningRequestResultEvent( + requestId, + clientNodeId, + statusCode, + fabricIndex, + ) + } + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/files.gni b/src/controller/java/generated/java/matter/controller/cluster/files.gni index ceeea1ba075f34..2bebadb13c36ce 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/files.gni +++ b/src/controller/java/generated/java/matter/controller/cluster/files.gni @@ -163,6 +163,7 @@ matter_eventstructs_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterReachableChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterStartUpEvent.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/CommissionerControlClusterCommissioningRequestResultEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/DemandResponseLoadControlClusterLoadControlEventStatusChangeEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/DeviceEnergyManagementClusterPowerAdjustEndEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/DeviceEnergyManagementClusterResumedEvent.kt", @@ -254,6 +255,7 @@ matter_clusters_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonMonoxideConcentrationMeasurementCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/ChannelCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/ColorControlCluster.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/CommissionerControlCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentAppObserverCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentControlCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentLauncherCluster.kt", diff --git a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp index dc02a801afbcd8..01a75bcc216288 100644 --- a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp @@ -42400,6 +42400,164 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR } break; } + case app::Clusters::CommissionerControl::Id: { + using namespace app::Clusters::CommissionerControl; + switch (aPath.mAttributeId) + { + case Attributes::SupportedDeviceCategories::Id: { + using TypeInfo = Attributes::SupportedDeviceCategories::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Long"; + std::string valueCtorSignature = "(J)V"; + jlong jnivalue = static_cast(cppValue.Raw()); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), + jnivalue, value); + return value; + } + case Attributes::GeneratedCommandList::Id: { + using TypeInfo = Attributes::GeneratedCommandList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::AcceptedCommandList::Id: { + using TypeInfo = Attributes::AcceptedCommandList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::EventList::Id: { + using TypeInfo = Attributes::EventList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::AttributeList::Id: { + using TypeInfo = Attributes::AttributeList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::FeatureMap::Id: { + using TypeInfo = Attributes::FeatureMap::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Long"; + std::string valueCtorSignature = "(J)V"; + jlong jnivalue = static_cast(cppValue); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), + jnivalue, value); + return value; + } + case Attributes::ClusterRevision::Id: { + using TypeInfo = Attributes::ClusterRevision::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Integer"; + std::string valueCtorSignature = "(I)V"; + jint jnivalue = static_cast(cppValue); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), jnivalue, + value); + return value; + } + default: + *aError = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB; + break; + } + break; + } case app::Clusters::ElectricalMeasurement::Id: { using namespace app::Clusters::ElectricalMeasurement; switch (aPath.mAttributeId) diff --git a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp index 301efce5eb3634..a61c38ca0edcc6 100644 --- a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp @@ -7968,6 +7968,80 @@ jobject DecodeEventValue(const app::ConcreteEventPath & aPath, TLV::TLVReader & } break; } + case app::Clusters::CommissionerControl::Id: { + using namespace app::Clusters::CommissionerControl; + switch (aPath.mEventId) + { + case Events::CommissioningRequestResult::Id: { + Events::CommissioningRequestResult::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value_requestId; + std::string value_requestIdClassName = "java/lang/Long"; + std::string value_requestIdCtorSignature = "(J)V"; + jlong jnivalue_requestId = static_cast(cppValue.requestId); + chip::JniReferences::GetInstance().CreateBoxedObject( + value_requestIdClassName.c_str(), value_requestIdCtorSignature.c_str(), jnivalue_requestId, value_requestId); + + jobject value_clientNodeId; + std::string value_clientNodeIdClassName = "java/lang/Long"; + std::string value_clientNodeIdCtorSignature = "(J)V"; + jlong jnivalue_clientNodeId = static_cast(cppValue.clientNodeId); + chip::JniReferences::GetInstance().CreateBoxedObject(value_clientNodeIdClassName.c_str(), + value_clientNodeIdCtorSignature.c_str(), + jnivalue_clientNodeId, value_clientNodeId); + + jobject value_statusCode; + std::string value_statusCodeClassName = "java/lang/Integer"; + std::string value_statusCodeCtorSignature = "(I)V"; + jint jnivalue_statusCode = static_cast(cppValue.statusCode); + chip::JniReferences::GetInstance().CreateBoxedObject( + value_statusCodeClassName.c_str(), value_statusCodeCtorSignature.c_str(), jnivalue_statusCode, value_statusCode); + + jobject value_fabricIndex; + std::string value_fabricIndexClassName = "java/lang/Integer"; + std::string value_fabricIndexCtorSignature = "(I)V"; + jint jnivalue_fabricIndex = static_cast(cppValue.fabricIndex); + chip::JniReferences::GetInstance().CreateBoxedObject(value_fabricIndexClassName.c_str(), + value_fabricIndexCtorSignature.c_str(), jnivalue_fabricIndex, + value_fabricIndex); + + jclass commissioningRequestResultStructClass; + err = chip::JniReferences::GetInstance().GetLocalClassRef( + env, "chip/devicecontroller/ChipEventStructs$CommissionerControlClusterCommissioningRequestResultEvent", + commissioningRequestResultStructClass); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, + "Could not find class ChipEventStructs$CommissionerControlClusterCommissioningRequestResultEvent"); + return nullptr; + } + + jmethodID commissioningRequestResultStructCtor; + err = chip::JniReferences::GetInstance().FindMethod( + env, commissioningRequestResultStructClass, "", + "(Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Integer;Ljava/lang/Integer;)V", &commissioningRequestResultStructCtor); + if (err != CHIP_NO_ERROR || commissioningRequestResultStructCtor == nullptr) + { + ChipLogError( + Zcl, "Could not find ChipEventStructs$CommissionerControlClusterCommissioningRequestResultEvent constructor"); + return nullptr; + } + + jobject value = env->NewObject(commissioningRequestResultStructClass, commissioningRequestResultStructCtor, + value_requestId, value_clientNodeId, value_statusCode, value_fabricIndex); + + return value; + } + default: + *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; + break; + } + break; + } case app::Clusters::ElectricalMeasurement::Id: { using namespace app::Clusters::ElectricalMeasurement; switch (aPath.mEventId) diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index 67bb0bc48134be..5d0d1ffd38fd3c 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -13199,6 +13199,76 @@ class ChipClusters: }, }, } + _COMMISSIONER_CONTROL_CLUSTER_INFO = { + "clusterName": "CommissionerControl", + "clusterId": 0x00000751, + "commands": { + 0x00000000: { + "commandId": 0x00000000, + "commandName": "RequestCommissioningApproval", + "args": { + "requestId": "int", + "vendorId": "int", + "productId": "int", + "label": "str", + }, + }, + 0x00000001: { + "commandId": 0x00000001, + "commandName": "CommissionNode", + "args": { + "requestId": "int", + "responseTimeoutSeconds": "int", + "ipAddress": "bytes", + "port": "int", + }, + }, + }, + "attributes": { + 0x00000000: { + "attributeName": "SupportedDeviceCategories", + "attributeId": 0x00000000, + "type": "int", + "reportable": True, + }, + 0x0000FFF8: { + "attributeName": "GeneratedCommandList", + "attributeId": 0x0000FFF8, + "type": "int", + "reportable": True, + }, + 0x0000FFF9: { + "attributeName": "AcceptedCommandList", + "attributeId": 0x0000FFF9, + "type": "int", + "reportable": True, + }, + 0x0000FFFA: { + "attributeName": "EventList", + "attributeId": 0x0000FFFA, + "type": "int", + "reportable": True, + }, + 0x0000FFFB: { + "attributeName": "AttributeList", + "attributeId": 0x0000FFFB, + "type": "int", + "reportable": True, + }, + 0x0000FFFC: { + "attributeName": "FeatureMap", + "attributeId": 0x0000FFFC, + "type": "int", + "reportable": True, + }, + 0x0000FFFD: { + "attributeName": "ClusterRevision", + "attributeId": 0x0000FFFD, + "type": "int", + "reportable": True, + }, + }, + } _ELECTRICAL_MEASUREMENT_CLUSTER_INFO = { "clusterName": "ElectricalMeasurement", "clusterId": 0x00000B04, @@ -15110,6 +15180,7 @@ class ChipClusters: 0x0000050E: _ACCOUNT_LOGIN_CLUSTER_INFO, 0x0000050F: _CONTENT_CONTROL_CLUSTER_INFO, 0x00000510: _CONTENT_APP_OBSERVER_CLUSTER_INFO, + 0x00000751: _COMMISSIONER_CONTROL_CLUSTER_INFO, 0x00000B04: _ELECTRICAL_MEASUREMENT_CLUSTER_INFO, 0xFFF1FC05: _UNIT_TESTING_CLUSTER_INFO, 0xFFF1FC06: _FAULT_INJECTION_CLUSTER_INFO, @@ -15236,6 +15307,7 @@ class ChipClusters: "AccountLogin": _ACCOUNT_LOGIN_CLUSTER_INFO, "ContentControl": _CONTENT_CONTROL_CLUSTER_INFO, "ContentAppObserver": _CONTENT_APP_OBSERVER_CLUSTER_INFO, + "CommissionerControl": _COMMISSIONER_CONTROL_CLUSTER_INFO, "ElectricalMeasurement": _ELECTRICAL_MEASUREMENT_CLUSTER_INFO, "UnitTesting": _UNIT_TESTING_CLUSTER_INFO, "FaultInjection": _FAULT_INJECTION_CLUSTER_INFO, diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 86ac54aeef23d3..511bdb3399f619 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -46373,6 +46373,244 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'uint' = 0 +@dataclass +class CommissionerControl(Cluster): + id: typing.ClassVar[int] = 0x00000751 + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="supportedDeviceCategories", Tag=0x00000000, Type=uint), + ClusterObjectFieldDescriptor(Label="generatedCommandList", Tag=0x0000FFF8, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="acceptedCommandList", Tag=0x0000FFF9, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="eventList", Tag=0x0000FFFA, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="attributeList", Tag=0x0000FFFB, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="featureMap", Tag=0x0000FFFC, Type=uint), + ClusterObjectFieldDescriptor(Label="clusterRevision", Tag=0x0000FFFD, Type=uint), + ]) + + supportedDeviceCategories: 'uint' = None + generatedCommandList: 'typing.List[uint]' = None + acceptedCommandList: 'typing.List[uint]' = None + eventList: 'typing.List[uint]' = None + attributeList: 'typing.List[uint]' = None + featureMap: 'uint' = None + clusterRevision: 'uint' = None + + class Bitmaps: + class SupportedDeviceCategoryBitmap(IntFlag): + kFabricSynchronization = 0x1 + + class Commands: + @dataclass + class RequestCommissioningApproval(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x00000751 + command_id: typing.ClassVar[int] = 0x00000000 + is_client: typing.ClassVar[bool] = True + response_type: typing.ClassVar[str] = None + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="requestId", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="vendorId", Tag=1, Type=uint), + ClusterObjectFieldDescriptor(Label="productId", Tag=2, Type=uint), + ClusterObjectFieldDescriptor(Label="label", Tag=3, Type=typing.Optional[str]), + ]) + + requestId: 'uint' = 0 + vendorId: 'uint' = 0 + productId: 'uint' = 0 + label: 'typing.Optional[str]' = None + + @dataclass + class CommissionNode(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x00000751 + command_id: typing.ClassVar[int] = 0x00000001 + is_client: typing.ClassVar[bool] = True + response_type: typing.ClassVar[str] = 'ReverseOpenCommissioningWindow' + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="requestId", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="responseTimeoutSeconds", Tag=1, Type=uint), + ClusterObjectFieldDescriptor(Label="ipAddress", Tag=2, Type=typing.Optional[bytes]), + ClusterObjectFieldDescriptor(Label="port", Tag=3, Type=typing.Optional[uint]), + ]) + + requestId: 'uint' = 0 + responseTimeoutSeconds: 'uint' = 0 + ipAddress: 'typing.Optional[bytes]' = None + port: 'typing.Optional[uint]' = None + + @dataclass + class ReverseOpenCommissioningWindow(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x00000751 + command_id: typing.ClassVar[int] = 0x00000002 + is_client: typing.ClassVar[bool] = False + response_type: typing.ClassVar[str] = None + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="commissioningTimeout", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="PAKEPasscodeVerifier", Tag=1, Type=bytes), + ClusterObjectFieldDescriptor(Label="discriminator", Tag=2, Type=uint), + ClusterObjectFieldDescriptor(Label="iterations", Tag=3, Type=uint), + ClusterObjectFieldDescriptor(Label="salt", Tag=4, Type=bytes), + ]) + + commissioningTimeout: 'uint' = 0 + PAKEPasscodeVerifier: 'bytes' = b"" + discriminator: 'uint' = 0 + iterations: 'uint' = 0 + salt: 'bytes' = b"" + + class Attributes: + @dataclass + class SupportedDeviceCategories(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000751 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x00000000 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=uint) + + value: 'uint' = 0 + + @dataclass + class GeneratedCommandList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000751 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFF8 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class AcceptedCommandList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000751 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFF9 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class EventList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000751 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFA + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class AttributeList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000751 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFB + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class FeatureMap(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000751 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFC + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=uint) + + value: 'uint' = 0 + + @dataclass + class ClusterRevision(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000751 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFD + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=uint) + + value: 'uint' = 0 + + class Events: + @dataclass + class CommissioningRequestResult(ClusterEvent): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000751 + + @ChipUtility.classproperty + def event_id(cls) -> int: + return 0x00000000 + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="requestId", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="clientNodeId", Tag=1, Type=uint), + ClusterObjectFieldDescriptor(Label="statusCode", Tag=2, Type=uint), + ClusterObjectFieldDescriptor(Label="fabricIndex", Tag=254, Type=uint), + ]) + + requestId: 'uint' = 0 + clientNodeId: 'uint' = 0 + statusCode: 'uint' = 0 + fabricIndex: 'uint' = 0 + + @dataclass class ElectricalMeasurement(Cluster): id: typing.ClassVar[int] = 0x00000B04 diff --git a/src/controller/python/test/test_scripts/mobile-device-test.py b/src/controller/python/test/test_scripts/mobile-device-test.py index 27f8e98964d7b9..39be65941a2a9f 100755 --- a/src/controller/python/test/test_scripts/mobile-device-test.py +++ b/src/controller/python/test/test_scripts/mobile-device-test.py @@ -19,6 +19,13 @@ # Commissioning test. +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --log-level INFO -t 3600 --disable-test ClusterObjectTests.TestTimedRequestTimeout --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto + import asyncio import os diff --git a/src/darwin/Framework/CHIP/MTRDevice.mm b/src/darwin/Framework/CHIP/MTRDevice.mm index 30d96d3c2e9f43..89478554cbdc8b 100644 --- a/src/darwin/Framework/CHIP/MTRDevice.mm +++ b/src/darwin/Framework/CHIP/MTRDevice.mm @@ -539,6 +539,9 @@ - (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceControlle - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:_systemTimeChangeObserverToken]; + + // TODO: retain cycle and clean up https://github.com/project-chip/connectedhomeip/issues/34267 + MTR_LOG("MTRDevice dealloc: %p", self); } - (NSString *)description @@ -844,11 +847,13 @@ - (void)_addDelegate:(id)delegate queue:(dispatch_queue_t)que #endif if (shouldSetUpSubscription) { + MTR_LOG("%@ - starting subscription setup", self); // Record the time of first addDelegate call that triggers initial subscribe, and do not reset this value on subsequent addDelegate calls if (!_initialSubscribeStart) { _initialSubscribeStart = [NSDate now]; } if ([self _deviceUsesThread]) { + MTR_LOG(" => %@ - device is a thread device, scheduling in pool", self); [self _scheduleSubscriptionPoolWork:^{ std::lock_guard lock(self->_lock); [self _setupSubscriptionWithReason:@"delegate is set and scheduled subscription is happening"]; @@ -1301,7 +1306,7 @@ - (void)_scheduleSubscriptionPoolWork:(dispatch_block_t)workBlock inNanoseconds: // Sanity check we are not scheduling for this device multiple times in the pool if (_subscriptionPoolWorkCompletionBlock) { - MTR_LOG_ERROR("%@ already scheduled in subscription pool for this device - ignoring: %@", self, description); + MTR_LOG("%@ already scheduled in subscription pool for this device - ignoring: %@", self, description); return; } @@ -1310,6 +1315,7 @@ - (void)_scheduleSubscriptionPoolWork:(dispatch_block_t)workBlock inNanoseconds: // In the case where a resubscription triggering event happened and already established, running the work block should result in a no-op MTRAsyncWorkItem * workItem = [[MTRAsyncWorkItem alloc] initWithQueue:self.queue]; [workItem setReadyHandler:^(id _Nonnull context, NSInteger retryCount, MTRAsyncWorkCompletionBlock _Nonnull completion) { + MTR_LOG("%@ - work item is ready to attempt pooled subscription", self); os_unfair_lock_lock(&self->_lock); #ifdef DEBUG [self _callDelegatesWithBlock:^(id testDelegate) { @@ -1335,6 +1341,7 @@ - (void)_scheduleSubscriptionPoolWork:(dispatch_block_t)workBlock inNanoseconds: workBlock(); }]; [self->_deviceController.concurrentSubscriptionPool enqueueWorkItem:workItem description:description]; + MTR_LOG("%@ - enqueued in the subscription pool", self); }); } diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index cea281551384d0..0ba1b181ff6f4d 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -605,11 +605,23 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams MTR_LOG("Loaded attribute values for %lu nodes from storage for controller uuid %@", static_cast(clusterDataByNode.count), self->_uniqueIdentifier); std::lock_guard lock(self->_deviceMapLock); + NSMutableArray * deviceList = [NSMutableArray array]; for (NSNumber * nodeID in clusterDataByNode) { NSDictionary * clusterData = clusterDataByNode[nodeID]; MTRDevice * device = [self _setupDeviceForNodeID:nodeID prefetchedClusterData:clusterData]; MTR_LOG("Loaded %lu cluster data from storage for %@", static_cast(clusterData.count), device); + + [deviceList addObject:device]; } + +#define kSecondsToWaitBeforeAPIClientRetainsMTRDevice 60 + // Keep the devices retained for a while, in case API client doesn't immediately retain them. + // + // Note that this is just an optimization to avoid throwing the information away and immediately + // re-reading it from storage. + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (kSecondsToWaitBeforeAPIClientRetainsMTRDevice * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + MTR_LOG("MTRDeviceController: un-retain devices loaded at startup %lu", static_cast(deviceList.count)); + }); }]; } @@ -1101,7 +1113,7 @@ - (NSData * _Nullable)attestationChallengeForDeviceID:(NSNumber *)deviceID chip::CommissioneeDeviceProxy * deviceProxy; auto errorCode = CHIP_NO_ERROR; - MATTER_LOG_METRIC_SCOPE(kMetricPASEVerifierForSetupCode, errorCode); + MATTER_LOG_METRIC_SCOPE(kMetricAttestationChallengeForDevice, errorCode); errorCode = self->_cppCommissioner->GetDeviceBeingCommissioned([deviceID unsignedLongLongValue], &deviceProxy); VerifyOrReturnValue(![MTRDeviceController checkForError:errorCode logMsg:kErrorGetCommissionee error:nil], nil); @@ -1257,15 +1269,12 @@ - (BOOL)checkIsRunning:(NSError * __autoreleasing *)error - (void)getSessionForNode:(chip::NodeId)nodeID completion:(MTRInternalDeviceConnectionCallback)completion { - // First check if MTRDevice exists from having loaded from storage, or created by a client. - // Do not use deviceForNodeID here, because we don't want to create the device if it does not already exist. - os_unfair_lock_lock(&_deviceMapLock); - MTRDevice * device = [_nodeIDToDeviceMap objectForKey:@(nodeID)]; - os_unfair_lock_unlock(&_deviceMapLock); + // Get the corresponding MTRDevice object to determine if the case/subscription pool is to be used + MTRDevice * device = [self deviceForNodeID:@(nodeID)]; // In the case that this device is known to use thread, queue this with subscription attempts as well, to // help with throttling Thread traffic. - if (device && [device deviceUsesThread]) { + if ([device deviceUsesThread]) { MTRAsyncWorkItem * workItem = [[MTRAsyncWorkItem alloc] initWithQueue:dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)]; [workItem setReadyHandler:^(id _Nonnull context, NSInteger retryCount, MTRAsyncWorkCompletionBlock _Nonnull workItemCompletion) { MTRInternalDeviceConnectionCallback completionWrapper = ^(chip::Messaging::ExchangeManager * _Nullable exchangeManager, @@ -1876,10 +1885,10 @@ - (BOOL)openPairingWindow:(uint64_t)deviceID duration:(NSUInteger)duration error return NO; } - __block CHIP_ERROR errorCode = CHIP_NO_ERROR; - MATTER_LOG_METRIC_SCOPE(kMetricOpenPairingWindow, errorCode); - auto block = ^BOOL { + CHIP_ERROR errorCode = CHIP_NO_ERROR; + MATTER_LOG_METRIC_SCOPE(kMetricOpenPairingWindow, errorCode); + errorCode = chip::Controller::AutoCommissioningWindowOpener::OpenBasicCommissioningWindow( self->_cppCommissioner, deviceID, chip::System::Clock::Seconds16(static_cast(duration))); return ![MTRDeviceController checkForError:errorCode logMsg:kErrorOpenPairingWindow error:error]; diff --git a/src/darwin/Framework/CHIP/MTRError_Internal.h b/src/darwin/Framework/CHIP/MTRError_Internal.h index c79cc17d95f198..af19f4888ff050 100644 --- a/src/darwin/Framework/CHIP/MTRError_Internal.h +++ b/src/darwin/Framework/CHIP/MTRError_Internal.h @@ -26,6 +26,10 @@ NS_ASSUME_NONNULL_BEGIN +#ifndef YES_NO +#define YES_NO(x) ((x) ? @"YES" : @"NO") +#endif + MTR_DIRECT_MEMBERS @interface MTRError : NSObject + (NSError *)errorWithCode:(MTRErrorCode)code; diff --git a/src/darwin/Framework/CHIP/MTRMetricKeys.h b/src/darwin/Framework/CHIP/MTRMetricKeys.h index d20ec3395656a4..42064b7f049394 100644 --- a/src/darwin/Framework/CHIP/MTRMetricKeys.h +++ b/src/darwin/Framework/CHIP/MTRMetricKeys.h @@ -61,8 +61,11 @@ constexpr Tracing::MetricKey kMetricDeviceBeingCommissioned = "dwnfw_dev_being_c // Tracks the request to generate PASE verifier for a given setup code constexpr Tracing::MetricKey kMetricPASEVerifierForSetupCode = "dwnfw_pase_verifier_for_code"; +// Tracks the request to get attestation challenge for a device +constexpr Tracing::MetricKey kMetricAttestationChallengeForDevice = "dwnfw_attestation_challenge_for_device"; + // Marks the request to open pairing window -constexpr Tracing::MetricKey kMetricOpenPairingWindow = "dwnfw_pase_verifier_for_code"; +constexpr Tracing::MetricKey kMetricOpenPairingWindow = "dwnfw_open_pairing_window"; // Device Vendor ID constexpr Tracing::MetricKey kMetricDeviceVendorID = "dwnfw_device_vendor_id"; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm index c4ca1e5d409bcb..b735da19e2edf6 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm @@ -5996,6 +5996,36 @@ static BOOL AttributeIsSpecifiedInContentAppObserverCluster(AttributeId aAttribu } } } +static BOOL AttributeIsSpecifiedInCommissionerControlCluster(AttributeId aAttributeId) +{ + using namespace Clusters::CommissionerControl; + switch (aAttributeId) { + case Attributes::SupportedDeviceCategories::Id: { + return YES; + } + case Attributes::GeneratedCommandList::Id: { + return YES; + } + case Attributes::AcceptedCommandList::Id: { + return YES; + } + case Attributes::EventList::Id: { + return YES; + } + case Attributes::AttributeList::Id: { + return YES; + } + case Attributes::FeatureMap::Id: { + return YES; + } + case Attributes::ClusterRevision::Id: { + return YES; + } + default: { + return NO; + } + } +} static BOOL AttributeIsSpecifiedInElectricalMeasurementCluster(AttributeId aAttributeId) { using namespace Clusters::ElectricalMeasurement; @@ -7065,6 +7095,9 @@ BOOL MTRAttributeIsSpecified(ClusterId aClusterId, AttributeId aAttributeId) case Clusters::ContentAppObserver::Id: { return AttributeIsSpecifiedInContentAppObserverCluster(aAttributeId); } + case Clusters::CommissionerControl::Id: { + return AttributeIsSpecifiedInCommissionerControlCluster(aAttributeId); + } case Clusters::ElectricalMeasurement::Id: { return AttributeIsSpecifiedInElectricalMeasurementCluster(aAttributeId); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm index 56728e6e7d944f..d55efa91505867 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm @@ -16942,6 +16942,29 @@ static id _Nullable DecodeAttributeValueForContentAppObserverCluster(AttributeId *aError = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB; return nil; } +static id _Nullable DecodeAttributeValueForCommissionerControlCluster(AttributeId aAttributeId, TLV::TLVReader & aReader, CHIP_ERROR * aError) +{ + using namespace Clusters::CommissionerControl; + switch (aAttributeId) { + case Attributes::SupportedDeviceCategories::Id: { + using TypeInfo = Attributes::SupportedDeviceCategories::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + NSNumber * _Nonnull value; + value = [NSNumber numberWithUnsignedInt:cppValue.Raw()]; + return value; + } + default: { + break; + } + } + + *aError = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB; + return nil; +} static id _Nullable DecodeAttributeValueForElectricalMeasurementCluster(AttributeId aAttributeId, TLV::TLVReader & aReader, CHIP_ERROR * aError) { using namespace Clusters::ElectricalMeasurement; @@ -20163,6 +20186,9 @@ id _Nullable MTRDecodeAttributeValue(const ConcreteAttributePath & aPath, TLV::T case Clusters::ContentAppObserver::Id: { return DecodeAttributeValueForContentAppObserverCluster(aPath.mAttributeId, aReader, aError); } + case Clusters::CommissionerControl::Id: { + return DecodeAttributeValueForCommissionerControlCluster(aPath.mAttributeId, aReader, aError); + } case Clusters::ElectricalMeasurement::Id: { return DecodeAttributeValueForElectricalMeasurementCluster(aPath.mAttributeId, aReader, aError); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 777e1ff03892a5..671383907ad433 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -14979,6 +14979,86 @@ MTR_PROVISIONALLY_AVAILABLE @end +/** + * Cluster Commissioner Control + * + * Supports the ability for clients to request the commissioning of themselves or other nodes onto a fabric which the cluster server can commission onto. + */ +MTR_PROVISIONALLY_AVAILABLE +@interface MTRBaseClusterCommissionerControl : MTRGenericBaseCluster + +/** + * Command RequestCommissioningApproval + * + * This command is sent by a client to request approval for a future CommissionNode call. + */ +- (void)requestCommissioningApprovalWithParams:(MTRCommissionerControlClusterRequestCommissioningApprovalParams *)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +/** + * Command CommissionNode + * + * This command is sent by a client to request that the server begins commissioning a previously approved request. + */ +- (void)commissionNodeWithParams:(MTRCommissionerControlClusterCommissionNodeParams *)params completion:(void (^)(MTRCommissionerControlClusterReverseOpenCommissioningWindowParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeSupportedDeviceCategoriesWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeSupportedDeviceCategoriesWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeSupportedDeviceCategoriesWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeGeneratedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeAcceptedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeAcceptedCommandListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeAcceptedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeEventListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeEventListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeEventListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeAttributeListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeAttributeListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeAttributeListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeFeatureMapWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeFeatureMapWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeFeatureMapWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeClusterRevisionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeClusterRevisionWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@end + +@interface MTRBaseClusterCommissionerControl (Availability) + +/** + * For all instance methods (reads, writes, commands) that take a completion, + * the completion will be called on the provided queue. + */ +- (instancetype _Nullable)initWithDevice:(MTRBaseDevice *)device + endpointID:(NSNumber *)endpointID + queue:(dispatch_queue_t)queue MTR_PROVISIONALLY_AVAILABLE; + +@end + /** * Cluster Electrical Measurement * @@ -20723,6 +20803,10 @@ typedef NS_ENUM(uint8_t, MTRContentAppObserverStatus) { MTRContentAppObserverStatusUnexpectedData MTR_PROVISIONALLY_AVAILABLE = 0x01, } MTR_PROVISIONALLY_AVAILABLE; +typedef NS_OPTIONS(uint32_t, MTRCommissionerControlSupportedDeviceCategoryBitmap) { + MTRCommissionerControlSupportedDeviceCategoryBitmapFabricSynchronization MTR_PROVISIONALLY_AVAILABLE = 0x1, +} MTR_PROVISIONALLY_AVAILABLE; + typedef NS_ENUM(uint8_t, MTRUnitTestingSimple) { MTRUnitTestingSimpleUnspecified MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00, MTRUnitTestingSimpleValueA MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x01, diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index 5ad1ae496448fa..fa9a4ef3fcf602 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -104667,6 +104667,311 @@ + (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheC @end +@implementation MTRBaseClusterCommissionerControl + +- (void)requestCommissioningApprovalWithParams:(MTRCommissionerControlClusterRequestCommissioningApprovalParams *)params completion:(MTRStatusCompletion)completion +{ + if (params == nil) { + params = [[MTRCommissionerControlClusterRequestCommissioningApprovalParams + alloc] init]; + } + + auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { + completion(error); + }; + + auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; + + using RequestType = CommissionerControl::Commands::RequestCommissioningApproval::Type; + [self.device _invokeKnownCommandWithEndpointID:self.endpointID + clusterID:@(RequestType::GetClusterId()) + commandID:@(RequestType::GetCommandId()) + commandPayload:params + timedInvokeTimeout:timedInvokeTimeoutMs + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:nil + queue:self.callbackQueue + completion:responseHandler]; +} +- (void)commissionNodeWithParams:(MTRCommissionerControlClusterCommissionNodeParams *)params completion:(void (^)(MTRCommissionerControlClusterReverseOpenCommissioningWindowParams * _Nullable data, NSError * _Nullable error))completion +{ + if (params == nil) { + params = [[MTRCommissionerControlClusterCommissionNodeParams + alloc] init]; + } + + auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { + completion(response, error); + }; + + auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; + + using RequestType = CommissionerControl::Commands::CommissionNode::Type; + [self.device _invokeKnownCommandWithEndpointID:self.endpointID + clusterID:@(RequestType::GetClusterId()) + commandID:@(RequestType::GetCommandId()) + commandPayload:params + timedInvokeTimeout:timedInvokeTimeoutMs + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:MTRCommissionerControlClusterReverseOpenCommissioningWindowParams.class + queue:self.callbackQueue + completion:responseHandler]; +} + +- (void)readAttributeSupportedDeviceCategoriesWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::SupportedDeviceCategories::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeSupportedDeviceCategoriesWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = CommissionerControl::Attributes::SupportedDeviceCategories::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeSupportedDeviceCategoriesWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::SupportedDeviceCategories::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::GeneratedCommandList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = CommissionerControl::Attributes::GeneratedCommandList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeGeneratedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::GeneratedCommandList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeAcceptedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::AcceptedCommandList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeAcceptedCommandListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = CommissionerControl::Attributes::AcceptedCommandList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeAcceptedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::AcceptedCommandList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeEventListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::EventList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeEventListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = CommissionerControl::Attributes::EventList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeEventListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::EventList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeAttributeListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::AttributeList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeAttributeListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = CommissionerControl::Attributes::AttributeList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeAttributeListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::AttributeList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeFeatureMapWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::FeatureMap::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeFeatureMapWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = CommissionerControl::Attributes::FeatureMap::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeFeatureMapWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::FeatureMap::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeClusterRevisionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::ClusterRevision::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeClusterRevisionWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = CommissionerControl::Attributes::ClusterRevision::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = CommissionerControl::Attributes::ClusterRevision::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +@end + @implementation MTRBaseClusterElectricalMeasurement - (void)getProfileInfoCommandWithCompletion:(MTRStatusCompletion)completion diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index a662b4413ef6e0..02230b74b6483f 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -203,6 +203,7 @@ typedef NS_ENUM(uint32_t, MTRClusterIDType) { MTRClusterIDTypeAccountLoginID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x0000050E, MTRClusterIDTypeContentControlID MTR_PROVISIONALLY_AVAILABLE = 0x0000050F, MTRClusterIDTypeContentAppObserverID MTR_PROVISIONALLY_AVAILABLE = 0x00000510, + MTRClusterIDTypeCommissionerControlID MTR_PROVISIONALLY_AVAILABLE = 0x00000751, MTRClusterIDTypeElectricalMeasurementID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000B04, MTRClusterIDTypeUnitTestingID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0xFFF1FC05, MTRClusterIDTypeSampleMEIID MTR_PROVISIONALLY_AVAILABLE = 0xFFF1FC20, @@ -4874,6 +4875,15 @@ typedef NS_ENUM(uint32_t, MTRAttributeIDType) { MTRAttributeIDTypeClusterContentAppObserverAttributeFeatureMapID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeFeatureMapID, MTRAttributeIDTypeClusterContentAppObserverAttributeClusterRevisionID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeClusterRevisionID, + // Cluster CommissionerControl attributes + MTRAttributeIDTypeClusterCommissionerControlAttributeSupportedDeviceCategoriesID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + MTRAttributeIDTypeClusterCommissionerControlAttributeGeneratedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeGeneratedCommandListID, + MTRAttributeIDTypeClusterCommissionerControlAttributeAcceptedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID, + MTRAttributeIDTypeClusterCommissionerControlAttributeEventListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeEventListID, + MTRAttributeIDTypeClusterCommissionerControlAttributeAttributeListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeAttributeListID, + MTRAttributeIDTypeClusterCommissionerControlAttributeFeatureMapID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeFeatureMapID, + MTRAttributeIDTypeClusterCommissionerControlAttributeClusterRevisionID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeClusterRevisionID, + // Cluster ElectricalMeasurement deprecated attribute names MTRClusterElectricalMeasurementAttributeMeasurementTypeID MTR_DEPRECATED("Please use MTRAttributeIDTypeClusterElectricalMeasurementAttributeMeasurementTypeID", ios(16.1, 16.4), macos(13.0, 13.3), watchos(9.1, 9.4), tvos(16.1, 16.4)) @@ -6886,6 +6896,11 @@ typedef NS_ENUM(uint32_t, MTRCommandIDType) { MTRCommandIDTypeClusterContentAppObserverCommandContentAppMessageID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, MTRCommandIDTypeClusterContentAppObserverCommandContentAppMessageResponseID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, + // Cluster CommissionerControl commands + MTRCommandIDTypeClusterCommissionerControlCommandRequestCommissioningApprovalID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + MTRCommandIDTypeClusterCommissionerControlCommandCommissionNodeID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, + MTRCommandIDTypeClusterCommissionerControlCommandReverseOpenCommissioningWindowID MTR_PROVISIONALLY_AVAILABLE = 0x00000002, + // Cluster ElectricalMeasurement deprecated command id names MTRClusterElectricalMeasurementCommandGetProfileInfoResponseCommandID MTR_DEPRECATED("Please use MTRCommandIDTypeClusterElectricalMeasurementCommandGetProfileInfoResponseCommandID", ios(16.1, 16.4), macos(13.0, 13.3), watchos(9.1, 9.4), tvos(16.1, 16.4)) @@ -7441,6 +7456,9 @@ typedef NS_ENUM(uint32_t, MTREventIDType) { // Cluster ContentControl events MTREventIDTypeClusterContentControlEventRemainingScreenTimeExpiredID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + // Cluster CommissionerControl events + MTREventIDTypeClusterCommissionerControlEventCommissioningRequestResultID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + // Cluster TestCluster deprecated event names MTRClusterTestClusterEventTestEventID MTR_DEPRECATED("Please use MTREventIDTypeClusterUnitTestingEventTestEventID", ios(16.1, 16.4), macos(13.0, 13.3), watchos(9.1, 9.4), tvos(16.1, 16.4)) diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm index fb130c161b4f6d..4492c5895c3219 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm @@ -375,6 +375,9 @@ case MTRClusterIDTypeContentAppObserverID: result = @"ContentAppObserver"; break; + case MTRClusterIDTypeCommissionerControlID: + result = @"CommissionerControl"; + break; case MTRClusterIDTypeElectricalMeasurementID: result = @"ElectricalMeasurement"; break; @@ -8133,6 +8136,44 @@ break; } + case MTRClusterIDTypeCommissionerControlID: + + switch (attributeID) { + + // Cluster CommissionerControl attributes + case MTRAttributeIDTypeClusterCommissionerControlAttributeSupportedDeviceCategoriesID: + result = @"SupportedDeviceCategories"; + break; + + case MTRAttributeIDTypeClusterCommissionerControlAttributeGeneratedCommandListID: + result = @"GeneratedCommandList"; + break; + + case MTRAttributeIDTypeClusterCommissionerControlAttributeAcceptedCommandListID: + result = @"AcceptedCommandList"; + break; + + case MTRAttributeIDTypeClusterCommissionerControlAttributeEventListID: + result = @"EventList"; + break; + + case MTRAttributeIDTypeClusterCommissionerControlAttributeAttributeListID: + result = @"AttributeList"; + break; + + case MTRAttributeIDTypeClusterCommissionerControlAttributeFeatureMapID: + result = @"FeatureMap"; + break; + + case MTRAttributeIDTypeClusterCommissionerControlAttributeClusterRevisionID: + result = @"ClusterRevision"; + break; + + default: + result = [NSString stringWithFormat:@"", attributeID]; + break; + } + case MTRClusterIDTypeElectricalMeasurementID: switch (attributeID) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h index 437e1b030e46e2..1113a02929193b 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h @@ -6948,6 +6948,47 @@ MTR_PROVISIONALLY_AVAILABLE @end +/** + * Cluster Commissioner Control + * Supports the ability for clients to request the commissioning of themselves or other nodes onto a fabric which the cluster server can commission onto. + */ +MTR_PROVISIONALLY_AVAILABLE +@interface MTRClusterCommissionerControl : MTRGenericCluster + +- (void)requestCommissioningApprovalWithParams:(MTRCommissionerControlClusterRequestCommissioningApprovalParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)commissionNodeWithParams:(MTRCommissionerControlClusterCommissionNodeParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRCommissionerControlClusterReverseOpenCommissioningWindowParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeSupportedDeviceCategoriesWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeAcceptedCommandListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeEventListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeAttributeListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeFeatureMapWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeClusterRevisionWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@end + +@interface MTRClusterCommissionerControl (Availability) + +/** + * For all instance methods that take a completion (i.e. command invocations), + * the completion will be called on the provided queue. + */ +- (instancetype _Nullable)initWithDevice:(MTRDevice *)device + endpointID:(NSNumber *)endpointID + queue:(dispatch_queue_t)queue MTR_PROVISIONALLY_AVAILABLE; + +@end + /** * Cluster Electrical Measurement * Attributes related to the electrical properties of a device. This cluster is used by power outlets and other devices that need to provide instantaneous data as opposed to metrology data which should be retrieved from the metering cluster.. diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm index 5316c8fb94905e..c9b3095c75b150 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm @@ -19906,6 +19906,99 @@ - (void)contentAppMessageWithParams:(MTRContentAppObserverClusterContentAppMessa @end +@implementation MTRClusterCommissionerControl + +- (void)requestCommissioningApprovalWithParams:(MTRCommissionerControlClusterRequestCommissioningApprovalParams *)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion +{ + if (params == nil) { + params = [[MTRCommissionerControlClusterRequestCommissioningApprovalParams + alloc] init]; + } + + auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { + completion(error); + }; + + auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; + + using RequestType = CommissionerControl::Commands::RequestCommissioningApproval::Type; + [self.device _invokeKnownCommandWithEndpointID:self.endpointID + clusterID:@(RequestType::GetClusterId()) + commandID:@(RequestType::GetCommandId()) + commandPayload:params + expectedValues:expectedValues + expectedValueInterval:expectedValueIntervalMs + timedInvokeTimeout:timedInvokeTimeoutMs + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:nil + queue:self.callbackQueue + completion:responseHandler]; +} + +- (void)commissionNodeWithParams:(MTRCommissionerControlClusterCommissionNodeParams *)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRCommissionerControlClusterReverseOpenCommissioningWindowParams * _Nullable data, NSError * _Nullable error))completion +{ + if (params == nil) { + params = [[MTRCommissionerControlClusterCommissionNodeParams + alloc] init]; + } + + auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { + completion(response, error); + }; + + auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; + + using RequestType = CommissionerControl::Commands::CommissionNode::Type; + [self.device _invokeKnownCommandWithEndpointID:self.endpointID + clusterID:@(RequestType::GetClusterId()) + commandID:@(RequestType::GetCommandId()) + commandPayload:params + expectedValues:expectedValues + expectedValueInterval:expectedValueIntervalMs + timedInvokeTimeout:timedInvokeTimeoutMs + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:MTRCommissionerControlClusterReverseOpenCommissioningWindowParams.class + queue:self.callbackQueue + completion:responseHandler]; +} + +- (NSDictionary * _Nullable)readAttributeSupportedDeviceCategoriesWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeCommissionerControlID) attributeID:@(MTRAttributeIDTypeClusterCommissionerControlAttributeSupportedDeviceCategoriesID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeCommissionerControlID) attributeID:@(MTRAttributeIDTypeClusterCommissionerControlAttributeGeneratedCommandListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeAcceptedCommandListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeCommissionerControlID) attributeID:@(MTRAttributeIDTypeClusterCommissionerControlAttributeAcceptedCommandListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeEventListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeCommissionerControlID) attributeID:@(MTRAttributeIDTypeClusterCommissionerControlAttributeEventListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeAttributeListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeCommissionerControlID) attributeID:@(MTRAttributeIDTypeClusterCommissionerControlAttributeAttributeListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeFeatureMapWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeCommissionerControlID) attributeID:@(MTRAttributeIDTypeClusterCommissionerControlAttributeFeatureMapID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeClusterRevisionWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeCommissionerControlID) attributeID:@(MTRAttributeIDTypeClusterCommissionerControlAttributeClusterRevisionID) params:params]; +} + +@end + @implementation MTRClusterElectricalMeasurement - (void)getProfileInfoCommandWithExpectedValues:(NSArray *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:(MTRStatusCompletion)completion diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index 7a81facf60704e..acb7982d9f9283 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -10805,6 +10805,105 @@ MTR_PROVISIONALLY_AVAILABLE error:(NSError * __autoreleasing *)error MTR_PROVISIONALLY_AVAILABLE; @end +MTR_PROVISIONALLY_AVAILABLE +@interface MTRCommissionerControlClusterRequestCommissioningApprovalParams : NSObject + +@property (nonatomic, copy) NSNumber * _Nonnull requestId MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSNumber * _Nonnull vendorId MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSNumber * _Nonnull productId MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSString * _Nullable label MTR_PROVISIONALLY_AVAILABLE; +/** + * Controls whether the command is a timed command (using Timed Invoke). + * + * If nil (the default value), a regular invoke is done for commands that do + * not require a timed invoke and a timed invoke with some default timed request + * timeout is done for commands that require a timed invoke. + * + * If not nil, a timed invoke is done, with the provided value used as the timed + * request timeout. The value should be chosen small enough to provide the + * desired security properties but large enough that it will allow a round-trip + * from the sever to the client (for the status response and actual invoke + * request) within the timeout window. + * + */ +@property (nonatomic, copy, nullable) NSNumber * timedInvokeTimeoutMs; + +/** + * Controls how much time, in seconds, we will allow for the server to process the command. + * + * The command will then time out if that much time, plus an allowance for retransmits due to network failures, passes. + * + * If nil, the framework will try to select an appropriate timeout value itself. + */ +@property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; +@end + +MTR_PROVISIONALLY_AVAILABLE +@interface MTRCommissionerControlClusterCommissionNodeParams : NSObject + +@property (nonatomic, copy) NSNumber * _Nonnull requestId MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSNumber * _Nonnull responseTimeoutSeconds MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSData * _Nullable ipAddress MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSNumber * _Nullable port MTR_PROVISIONALLY_AVAILABLE; +/** + * Controls whether the command is a timed command (using Timed Invoke). + * + * If nil (the default value), a regular invoke is done for commands that do + * not require a timed invoke and a timed invoke with some default timed request + * timeout is done for commands that require a timed invoke. + * + * If not nil, a timed invoke is done, with the provided value used as the timed + * request timeout. The value should be chosen small enough to provide the + * desired security properties but large enough that it will allow a round-trip + * from the sever to the client (for the status response and actual invoke + * request) within the timeout window. + * + */ +@property (nonatomic, copy, nullable) NSNumber * timedInvokeTimeoutMs; + +/** + * Controls how much time, in seconds, we will allow for the server to process the command. + * + * The command will then time out if that much time, plus an allowance for retransmits due to network failures, passes. + * + * If nil, the framework will try to select an appropriate timeout value itself. + */ +@property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; +@end + +MTR_PROVISIONALLY_AVAILABLE +@interface MTRCommissionerControlClusterReverseOpenCommissioningWindowParams : NSObject + +@property (nonatomic, copy) NSNumber * _Nonnull commissioningTimeout MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSData * _Nonnull pakePasscodeVerifier MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSNumber * _Nonnull discriminator MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSNumber * _Nonnull iterations MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSData * _Nonnull salt MTR_PROVISIONALLY_AVAILABLE; + +/** + * Initialize an MTRCommissionerControlClusterReverseOpenCommissioningWindowParams with a response-value dictionary + * of the sort that MTRDeviceResponseHandler would receive. + * + * Will return nil and hand out an error if the response-value dictionary is not + * a command data response or is not the right command response. + * + * Will return nil and hand out an error if the data response does not match the known + * schema for this command. + */ +- (nullable instancetype)initWithResponseValue:(NSDictionary *)responseValue + error:(NSError * __autoreleasing *)error MTR_PROVISIONALLY_AVAILABLE; +@end + MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTRElectricalMeasurementClusterGetProfileInfoResponseCommandParams : NSObject diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index c959fedea5a841..8ab9ac346812c5 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -31033,6 +31033,312 @@ - (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ContentA @end +@implementation MTRCommissionerControlClusterRequestCommissioningApprovalParams +- (instancetype)init +{ + if (self = [super init]) { + + _requestId = @(0); + + _vendorId = @(0); + + _productId = @(0); + + _label = nil; + _timedInvokeTimeoutMs = nil; + _serverSideProcessingTimeout = nil; + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone; +{ + auto other = [[MTRCommissionerControlClusterRequestCommissioningApprovalParams alloc] init]; + + other.requestId = self.requestId; + other.vendorId = self.vendorId; + other.productId = self.productId; + other.label = self.label; + other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; + other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: requestId:%@; vendorId:%@; productId:%@; label:%@; >", NSStringFromClass([self class]), _requestId, _vendorId, _productId, _label]; + return descriptionString; +} + +@end + +@implementation MTRCommissionerControlClusterRequestCommissioningApprovalParams (InternalMethods) + +- (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader +{ + chip::app::Clusters::CommissionerControl::Commands::RequestCommissioningApproval::Type encodableStruct; + ListFreer listFreer; + { + encodableStruct.requestId = self.requestId.unsignedLongLongValue; + } + { + encodableStruct.vendorId = static_cast>(self.vendorId.unsignedShortValue); + } + { + encodableStruct.productId = self.productId.unsignedShortValue; + } + { + if (self.label != nil) { + auto & definedValue_0 = encodableStruct.label.Emplace(); + definedValue_0 = AsCharSpan(self.label); + } + } + + auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); + if (buffer.IsNull()) { + return CHIP_ERROR_NO_MEMORY; + } + + chip::System::PacketBufferTLVWriter writer; + // Commands never need chained buffers, since they cannot be chunked. + writer.Init(std::move(buffer), /* useChainedBuffers = */ false); + + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::AnonymousTag(), encodableStruct)); + + ReturnErrorOnFailure(writer.Finalize(&buffer)); + + reader.Init(std::move(buffer)); + return reader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag()); +} + +- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error +{ + chip::System::PacketBufferTLVReader reader; + CHIP_ERROR err = [self _encodeToTLVReader:reader]; + if (err != CHIP_NO_ERROR) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:err]; + } + return nil; + } + + auto decodedObj = MTRDecodeDataValueDictionaryFromCHIPTLV(&reader); + if (decodedObj == nil) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]; + } + } + return decodedObj; +} +@end + +@implementation MTRCommissionerControlClusterCommissionNodeParams +- (instancetype)init +{ + if (self = [super init]) { + + _requestId = @(0); + + _responseTimeoutSeconds = @(0); + + _ipAddress = nil; + + _port = nil; + _timedInvokeTimeoutMs = nil; + _serverSideProcessingTimeout = nil; + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone; +{ + auto other = [[MTRCommissionerControlClusterCommissionNodeParams alloc] init]; + + other.requestId = self.requestId; + other.responseTimeoutSeconds = self.responseTimeoutSeconds; + other.ipAddress = self.ipAddress; + other.port = self.port; + other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; + other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: requestId:%@; responseTimeoutSeconds:%@; ipAddress:%@; port:%@; >", NSStringFromClass([self class]), _requestId, _responseTimeoutSeconds, [_ipAddress base64EncodedStringWithOptions:0], _port]; + return descriptionString; +} + +@end + +@implementation MTRCommissionerControlClusterCommissionNodeParams (InternalMethods) + +- (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader +{ + chip::app::Clusters::CommissionerControl::Commands::CommissionNode::Type encodableStruct; + ListFreer listFreer; + { + encodableStruct.requestId = self.requestId.unsignedLongLongValue; + } + { + encodableStruct.responseTimeoutSeconds = self.responseTimeoutSeconds.unsignedShortValue; + } + { + if (self.ipAddress != nil) { + auto & definedValue_0 = encodableStruct.ipAddress.Emplace(); + definedValue_0 = AsByteSpan(self.ipAddress); + } + } + { + if (self.port != nil) { + auto & definedValue_0 = encodableStruct.port.Emplace(); + definedValue_0 = self.port.unsignedShortValue; + } + } + + auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); + if (buffer.IsNull()) { + return CHIP_ERROR_NO_MEMORY; + } + + chip::System::PacketBufferTLVWriter writer; + // Commands never need chained buffers, since they cannot be chunked. + writer.Init(std::move(buffer), /* useChainedBuffers = */ false); + + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::AnonymousTag(), encodableStruct)); + + ReturnErrorOnFailure(writer.Finalize(&buffer)); + + reader.Init(std::move(buffer)); + return reader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag()); +} + +- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error +{ + chip::System::PacketBufferTLVReader reader; + CHIP_ERROR err = [self _encodeToTLVReader:reader]; + if (err != CHIP_NO_ERROR) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:err]; + } + return nil; + } + + auto decodedObj = MTRDecodeDataValueDictionaryFromCHIPTLV(&reader); + if (decodedObj == nil) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]; + } + } + return decodedObj; +} +@end + +@implementation MTRCommissionerControlClusterReverseOpenCommissioningWindowParams +- (instancetype)init +{ + if (self = [super init]) { + + _commissioningTimeout = @(0); + + _pakePasscodeVerifier = [NSData data]; + + _discriminator = @(0); + + _iterations = @(0); + + _salt = [NSData data]; + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone; +{ + auto other = [[MTRCommissionerControlClusterReverseOpenCommissioningWindowParams alloc] init]; + + other.commissioningTimeout = self.commissioningTimeout; + other.pakePasscodeVerifier = self.pakePasscodeVerifier; + other.discriminator = self.discriminator; + other.iterations = self.iterations; + other.salt = self.salt; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: commissioningTimeout:%@; pakePasscodeVerifier:%@; discriminator:%@; iterations:%@; salt:%@; >", NSStringFromClass([self class]), _commissioningTimeout, [_pakePasscodeVerifier base64EncodedStringWithOptions:0], _discriminator, _iterations, [_salt base64EncodedStringWithOptions:0]]; + return descriptionString; +} + +- (nullable instancetype)initWithResponseValue:(NSDictionary *)responseValue + error:(NSError * __autoreleasing *)error +{ + if (!(self = [super init])) { + return nil; + } + + using DecodableType = chip::app::Clusters::CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType; + chip::System::PacketBufferHandle buffer = [MTRBaseDevice _responseDataForCommand:responseValue + clusterID:DecodableType::GetClusterId() + commandID:DecodableType::GetCommandId() + error:error]; + if (buffer.IsNull()) { + return nil; + } + + chip::TLV::TLVReader reader; + reader.Init(buffer->Start(), buffer->DataLength()); + + CHIP_ERROR err = reader.Next(chip::TLV::AnonymousTag()); + if (err == CHIP_NO_ERROR) { + DecodableType decodedStruct; + err = chip::app::DataModel::Decode(reader, decodedStruct); + if (err == CHIP_NO_ERROR) { + err = [self _setFieldsFromDecodableStruct:decodedStruct]; + if (err == CHIP_NO_ERROR) { + return self; + } + } + } + + NSString * errorStr = [NSString stringWithFormat:@"Command payload decoding failed: %s", err.AsString()]; + MTR_LOG_ERROR("%s", errorStr.UTF8String); + if (error != nil) { + NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : NSLocalizedString(errorStr, nil) }; + *error = [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeSchemaMismatch userInfo:userInfo]; + } + return nil; +} + +@end + +@implementation MTRCommissionerControlClusterReverseOpenCommissioningWindowParams (InternalMethods) + +- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType &)decodableStruct +{ + { + self.commissioningTimeout = [NSNumber numberWithUnsignedShort:decodableStruct.commissioningTimeout]; + } + { + self.pakePasscodeVerifier = AsData(decodableStruct.PAKEPasscodeVerifier); + } + { + self.discriminator = [NSNumber numberWithUnsignedShort:decodableStruct.discriminator]; + } + { + self.iterations = [NSNumber numberWithUnsignedInt:decodableStruct.iterations]; + } + { + self.salt = AsData(decodableStruct.salt); + } + return CHIP_NO_ERROR; +} + +@end + @implementation MTRElectricalMeasurementClusterGetProfileInfoResponseCommandParams - (instancetype)init { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h index a38602a4053044..7072a0db6c26ef 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h @@ -2020,6 +2020,24 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface MTRCommissionerControlClusterRequestCommissioningApprovalParams (InternalMethods) + +- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; + +@end + +@interface MTRCommissionerControlClusterCommissionNodeParams (InternalMethods) + +- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; + +@end + +@interface MTRCommissionerControlClusterReverseOpenCommissioningWindowParams (InternalMethods) + +- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType &)decodableStruct; + +@end + @interface MTRElectricalMeasurementClusterGetProfileInfoResponseCommandParams (InternalMethods) - (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ElectricalMeasurement::Commands::GetProfileInfoResponseCommand::DecodableType &)decodableStruct; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm index 23ef1d7ef1648d..5e09e32a955523 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm @@ -1145,6 +1145,15 @@ static BOOL CommandNeedsTimedInvokeInContentAppObserverCluster(AttributeId aAttr } } } +static BOOL CommandNeedsTimedInvokeInCommissionerControlCluster(AttributeId aAttributeId) +{ + using namespace Clusters::CommissionerControl; + switch (aAttributeId) { + default: { + return NO; + } + } +} static BOOL CommandNeedsTimedInvokeInElectricalMeasurementCluster(AttributeId aAttributeId) { using namespace Clusters::ElectricalMeasurement; @@ -1530,6 +1539,9 @@ BOOL MTRCommandNeedsTimedInvoke(NSNumber * _Nonnull aClusterID, NSNumber * _Nonn case Clusters::ContentAppObserver::Id: { return CommandNeedsTimedInvokeInContentAppObserverCluster(commandID); } + case Clusters::CommissionerControl::Id: { + return CommandNeedsTimedInvokeInCommissionerControlCluster(commandID); + } case Clusters::ElectricalMeasurement::Id: { return CommandNeedsTimedInvokeInElectricalMeasurementCluster(commandID); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm index 4a5dba79c49565..049f67951b7408 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm @@ -4446,6 +4446,50 @@ static id _Nullable DecodeEventPayloadForContentAppObserverCluster(EventId aEven *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; return nil; } +static id _Nullable DecodeEventPayloadForCommissionerControlCluster(EventId aEventId, TLV::TLVReader & aReader, CHIP_ERROR * aError) +{ + using namespace Clusters::CommissionerControl; + switch (aEventId) { + case Events::CommissioningRequestResult::Id: { + Events::CommissioningRequestResult::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + + __auto_type * value = [MTRCommissionerControlClusterCommissioningRequestResultEvent new]; + + do { + NSNumber * _Nonnull memberValue; + memberValue = [NSNumber numberWithUnsignedLongLong:cppValue.requestId]; + value.requestId = memberValue; + } while (0); + do { + NSNumber * _Nonnull memberValue; + memberValue = [NSNumber numberWithUnsignedLongLong:cppValue.clientNodeId]; + value.clientNodeId = memberValue; + } while (0); + do { + NSNumber * _Nonnull memberValue; + memberValue = [NSNumber numberWithUnsignedChar:cppValue.statusCode]; + value.statusCode = memberValue; + } while (0); + do { + NSNumber * _Nonnull memberValue; + memberValue = [NSNumber numberWithUnsignedChar:cppValue.fabricIndex]; + value.fabricIndex = memberValue; + } while (0); + + return value; + } + default: { + break; + } + } + + *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; + return nil; +} static id _Nullable DecodeEventPayloadForElectricalMeasurementCluster(EventId aEventId, TLV::TLVReader & aReader, CHIP_ERROR * aError) { using namespace Clusters::ElectricalMeasurement; @@ -4988,6 +5032,9 @@ id _Nullable MTRDecodeEventPayload(const ConcreteEventPath & aPath, TLV::TLVRead case Clusters::ContentAppObserver::Id: { return DecodeEventPayloadForContentAppObserverCluster(aPath.mEventId, aReader, aError); } + case Clusters::CommissionerControl::Id: { + return DecodeEventPayloadForCommissionerControlCluster(aPath.mEventId, aReader, aError); + } case Clusters::ElectricalMeasurement::Id: { return DecodeEventPayloadForElectricalMeasurementCluster(aPath.mEventId, aReader, aError); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h index 172c5f76731356..e72e520b198f79 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h @@ -2039,6 +2039,14 @@ MTR_PROVISIONALLY_AVAILABLE @interface MTRContentControlClusterRemainingScreenTimeExpiredEvent : NSObject @end +MTR_PROVISIONALLY_AVAILABLE +@interface MTRCommissionerControlClusterCommissioningRequestResultEvent : NSObject +@property (nonatomic, copy) NSNumber * _Nonnull requestId MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull clientNodeId MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull statusCode MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull fabricIndex MTR_PROVISIONALLY_AVAILABLE; +@end + MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) @interface MTRUnitTestingClusterSimpleStruct : NSObject @property (nonatomic, copy) NSNumber * _Nonnull a MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm index aee0f31d37afc6..09314a688222f6 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm @@ -8391,6 +8391,42 @@ - (NSString *)description @end +@implementation MTRCommissionerControlClusterCommissioningRequestResultEvent +- (instancetype)init +{ + if (self = [super init]) { + + _requestId = @(0); + + _clientNodeId = @(0); + + _statusCode = @(0); + + _fabricIndex = @(0); + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone +{ + auto other = [[MTRCommissionerControlClusterCommissioningRequestResultEvent alloc] init]; + + other.requestId = self.requestId; + other.clientNodeId = self.clientNodeId; + other.statusCode = self.statusCode; + other.fabricIndex = self.fabricIndex; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: requestId:%@; clientNodeId:%@; statusCode:%@; fabricIndex:%@; >", NSStringFromClass([self class]), _requestId, _clientNodeId, _statusCode, _fabricIndex]; + return descriptionString; +} + +@end + @implementation MTRUnitTestingClusterSimpleStruct - (instancetype)init { diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index 05037ef3e16822..df5949868d0012 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -2497,7 +2497,6 @@ "-Wl,-unexported_symbol,\"__Unwind_*\"", "-Wl,-unexported_symbol,\"_unw_*\"", "-Wl,-hidden-lCHIP", - "-Wl,-no_inits", ); "OTHER_LDFLAGS[sdk=macosx*]" = ( "-framework", @@ -2516,7 +2515,6 @@ "-Wl,-unexported_symbol,\"__Unwind_*\"", "-Wl,-unexported_symbol,\"_unw_*\"", "-Wl,-hidden-lCHIP", - "-Wl,-no_inits", ); PRODUCT_BUNDLE_IDENTIFIER = com.csa.matter; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; diff --git a/src/include/platform/internal/GenericConfigurationManagerImpl.ipp b/src/include/platform/internal/GenericConfigurationManagerImpl.ipp index bb9e56a8bb2a82..9b36f341042aa9 100644 --- a/src/include/platform/internal/GenericConfigurationManagerImpl.ipp +++ b/src/include/platform/internal/GenericConfigurationManagerImpl.ipp @@ -49,8 +49,6 @@ #include #endif -#include - // TODO : may be we can make it configurable #define BLE_ADVERTISEMENT_VERSION 0 @@ -58,9 +56,7 @@ namespace chip { namespace DeviceLayer { namespace Internal { -namespace { -std::optional gFirmwareBuildChipEpochTime; -} +static Optional sFirmwareBuildChipEpochTime; #if CHIP_USE_TRANSITIONAL_COMMISSIONABLE_DATA_PROVIDER @@ -292,9 +288,9 @@ template CHIP_ERROR GenericConfigurationManagerImpl::GetFirmwareBuildChipEpochTime(System::Clock::Seconds32 & chipEpochTime) { // If the setter was called and we have a value in memory, return this. - if (gFirmwareBuildChipEpochTime.has_value()) + if (sFirmwareBuildChipEpochTime.HasValue()) { - chipEpochTime = gFirmwareBuildChipEpochTime.value(); + chipEpochTime = sFirmwareBuildChipEpochTime.Value(); return CHIP_NO_ERROR; } #ifdef CHIP_DEVICE_CONFIG_FIRMWARE_BUILD_TIME_MATTER_EPOCH_S @@ -327,7 +323,7 @@ CHIP_ERROR GenericConfigurationManagerImpl::SetFirmwareBuildChipEpo // // Implementations that can't use the hard-coded time for whatever reason // should set this at each init. - gFirmwareBuildChipEpochTime = chipEpochTime; + sFirmwareBuildChipEpochTime.SetValue(chipEpochTime); return CHIP_NO_ERROR; } diff --git a/src/lib/support/IntrusiveList.h b/src/lib/support/IntrusiveList.h index be9c139babc3dc..961113e8d1ee6b 100644 --- a/src/lib/support/IntrusiveList.h +++ b/src/lib/support/IntrusiveList.h @@ -84,7 +84,7 @@ enum class IntrusiveMode class IntrusiveListNodePrivateBase { public: - constexpr IntrusiveListNodePrivateBase() : mPrev(nullptr), mNext(nullptr) {} + IntrusiveListNodePrivateBase() : mPrev(nullptr), mNext(nullptr) {} ~IntrusiveListNodePrivateBase() { VerifyOrDie(!IsInList()); } // Note: The copy construct/assignment is not provided because the list node state is not copyable. @@ -98,7 +98,7 @@ class IntrusiveListNodePrivateBase private: friend class IntrusiveListBase; - constexpr IntrusiveListNodePrivateBase(IntrusiveListNodePrivateBase * prev, IntrusiveListNodePrivateBase * next) : + IntrusiveListNodePrivateBase(IntrusiveListNodePrivateBase * prev, IntrusiveListNodePrivateBase * next) : mPrev(prev), mNext(next) {} @@ -284,7 +284,7 @@ class IntrusiveListBase // ^ | // \------------------------------------------/ // - constexpr IntrusiveListBase() : mNode(&mNode, &mNode) {} + IntrusiveListBase() : mNode(&mNode, &mNode) {} ~IntrusiveListBase() { VerifyOrDie(Empty()); @@ -399,7 +399,7 @@ template // nogncheck #endif -#include - namespace chip { using namespace System::Clock::Literals; #if CONFIG_BUILD_FOR_HOST_UNIT_TEST -namespace { -// Use std::optional for globals to avoid static initializers -std::optional gIdleRetransTimeoutOverride; -std::optional gActiveRetransTimeoutOverride; -std::optional gActiveThresholdTimeOverride; -} // namespace +static Optional idleRetransTimeoutOverride = NullOptional; +static Optional activeRetransTimeoutOverride = NullOptional; +static Optional activeThresholdTimeOverride = NullOptional; void OverrideLocalMRPConfig(System::Clock::Timeout idleRetransTimeout, System::Clock::Timeout activeRetransTimeout, System::Clock::Timeout activeThresholdTime) { - gIdleRetransTimeoutOverride = idleRetransTimeout; - gActiveRetransTimeoutOverride = activeRetransTimeout; - gActiveThresholdTimeOverride = activeThresholdTime; + idleRetransTimeoutOverride.SetValue(idleRetransTimeout); + activeRetransTimeoutOverride.SetValue(activeRetransTimeout); + activeThresholdTimeOverride.SetValue(activeThresholdTime); } void ClearLocalMRPConfigOverride() { - gActiveRetransTimeoutOverride = std::nullopt; - gIdleRetransTimeoutOverride = std::nullopt; - gActiveThresholdTimeOverride = std::nullopt; + activeRetransTimeoutOverride.ClearValue(); + idleRetransTimeoutOverride.ClearValue(); + activeThresholdTimeOverride.ClearValue(); } #endif @@ -67,15 +62,14 @@ namespace { // This is not a static member of ReliableMessageProtocolConfig because the free // function GetLocalMRPConfig() needs access to it. -// Use std::optional to avoid a static initializer -std::optional sDynamicLocalMPRConfig; +Optional sDynamicLocalMPRConfig; } // anonymous namespace bool ReliableMessageProtocolConfig::SetLocalMRPConfig(const Optional & localMRPConfig) { auto oldConfig = GetLocalMRPConfig(); - sDynamicLocalMPRConfig = localMRPConfig.std_optional(); + sDynamicLocalMPRConfig = localMRPConfig; return oldConfig != GetLocalMRPConfig(); } #endif // CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG @@ -95,9 +89,9 @@ Optional GetLocalMRPConfig() ReliableMessageProtocolConfig config(CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL, CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL); #if CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG - if (sDynamicLocalMPRConfig.has_value()) + if (sDynamicLocalMPRConfig.HasValue()) { - config = sDynamicLocalMPRConfig.value(); + config = sDynamicLocalMPRConfig.Value(); } #endif // CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG @@ -111,19 +105,19 @@ Optional GetLocalMRPConfig() #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST - if (gIdleRetransTimeoutOverride.has_value()) + if (idleRetransTimeoutOverride.HasValue()) { - config.mIdleRetransTimeout = gIdleRetransTimeoutOverride.value(); + config.mIdleRetransTimeout = idleRetransTimeoutOverride.Value(); } - if (gActiveRetransTimeoutOverride.has_value()) + if (activeRetransTimeoutOverride.HasValue()) { - config.mActiveRetransTimeout = gActiveRetransTimeoutOverride.value(); + config.mActiveRetransTimeout = activeRetransTimeoutOverride.Value(); } - if (gActiveThresholdTimeOverride.has_value()) + if (activeThresholdTimeOverride.HasValue()) { - config.mActiveThresholdTime = gActiveThresholdTimeOverride.value(); + config.mActiveThresholdTime = activeRetransTimeoutOverride.Value(); } #endif diff --git a/src/messaging/ReliableMessageProtocolConfig.h b/src/messaging/ReliableMessageProtocolConfig.h index f8d8cfa9bbf2fe..beceee6c52de46 100644 --- a/src/messaging/ReliableMessageProtocolConfig.h +++ b/src/messaging/ReliableMessageProtocolConfig.h @@ -191,9 +191,8 @@ inline constexpr System::Clock::Milliseconds32 kDefaultActiveTime = System::Cloc */ struct ReliableMessageProtocolConfig { - constexpr ReliableMessageProtocolConfig(System::Clock::Milliseconds32 idleInterval, - System::Clock::Milliseconds32 activeInterval, - System::Clock::Milliseconds16 activeThreshold = kDefaultActiveTime) : + ReliableMessageProtocolConfig(System::Clock::Milliseconds32 idleInterval, System::Clock::Milliseconds32 activeInterval, + System::Clock::Milliseconds16 activeThreshold = kDefaultActiveTime) : mIdleRetransTimeout(idleInterval), mActiveRetransTimeout(activeInterval), mActiveThresholdTime(activeThreshold) {} diff --git a/src/platform/Darwin/ConfigurationManagerImpl.cpp b/src/platform/Darwin/ConfigurationManagerImpl.cpp index ae00faf58d81a1..10a2ad0a8eb600 100644 --- a/src/platform/Darwin/ConfigurationManagerImpl.cpp +++ b/src/platform/Darwin/ConfigurationManagerImpl.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -139,13 +138,10 @@ CHIP_ERROR GetMACAddressFromInterfaces(io_iterator_t primaryInterfaceIterator, u } #endif // TARGET_OS_OSX -namespace { -AtomicGlobal gInstance; -} - ConfigurationManagerImpl & ConfigurationManagerImpl::GetDefaultInstance() { - return gInstance.get(); + static ConfigurationManagerImpl sInstance; + return sInstance; } CHIP_ERROR ConfigurationManagerImpl::Init() diff --git a/src/platform/Darwin/ConfigurationManagerImpl.h b/src/platform/Darwin/ConfigurationManagerImpl.h index 5f99243b95adc4..74a13606be9c53 100644 --- a/src/platform/Darwin/ConfigurationManagerImpl.h +++ b/src/platform/Darwin/ConfigurationManagerImpl.h @@ -34,7 +34,7 @@ namespace chip { namespace DeviceLayer { -inline constexpr int kCountryCodeLength = 2; +static constexpr int kCountryCodeLength = 2; /** * Concrete implementation of the ConfigurationManager singleton object for the Darwin platform. diff --git a/src/platform/Darwin/DeviceInstanceInfoProviderImpl.cpp b/src/platform/Darwin/DeviceInstanceInfoProviderImpl.cpp index caf4e25191575e..6bb1d1bfd79c65 100644 --- a/src/platform/Darwin/DeviceInstanceInfoProviderImpl.cpp +++ b/src/platform/Darwin/DeviceInstanceInfoProviderImpl.cpp @@ -18,7 +18,6 @@ #include "DeviceInstanceInfoProviderImpl.h" -#include #include namespace chip { @@ -34,14 +33,5 @@ CHIP_ERROR DeviceInstanceInfoProviderImpl::GetProductId(uint16_t & productId) return Internal::PosixConfig::ReadConfigValue(Internal::PosixConfig::kConfigKey_ProductId, productId); } -namespace { -AtomicGlobal gInstance; -} // namespace - -DeviceInstanceInfoProviderImpl & DeviceInstanceInfoProviderMgrImpl() -{ - return gInstance.get(); -} - } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/Darwin/DeviceInstanceInfoProviderImpl.h b/src/platform/Darwin/DeviceInstanceInfoProviderImpl.h index 48603b583d9f86..630fdbe24c8a12 100644 --- a/src/platform/Darwin/DeviceInstanceInfoProviderImpl.h +++ b/src/platform/Darwin/DeviceInstanceInfoProviderImpl.h @@ -30,13 +30,15 @@ class DeviceInstanceInfoProviderImpl : public Internal::GenericDeviceInstanceInf CHIP_ERROR GetVendorId(uint16_t & vendorId) override; CHIP_ERROR GetProductId(uint16_t & productId) override; - DeviceInstanceInfoProviderImpl() : DeviceInstanceInfoProviderImpl(ConfigurationManagerImpl::GetDefaultInstance()) {} DeviceInstanceInfoProviderImpl(ConfigurationManagerImpl & configManager) : Internal::GenericDeviceInstanceInfoProvider(configManager) {} }; -DeviceInstanceInfoProviderImpl & DeviceInstanceInfoProviderMgrImpl(); - +inline DeviceInstanceInfoProviderImpl & DeviceInstanceInfoProviderMgrImpl() +{ + static DeviceInstanceInfoProviderImpl sInstance(ConfigurationManagerImpl::GetDefaultInstance()); + return sInstance; +} } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/nxp/common/CHIPDeviceNXPPlatformDefaultConfig.h b/src/platform/nxp/common/CHIPDeviceNXPPlatformDefaultConfig.h index fba6a32fa26326..28e26038e6a3e2 100644 --- a/src/platform/nxp/common/CHIPDeviceNXPPlatformDefaultConfig.h +++ b/src/platform/nxp/common/CHIPDeviceNXPPlatformDefaultConfig.h @@ -106,3 +106,15 @@ #define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DISCOVERY 1 #define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 #endif + +#ifndef CHIP_DEVICE_CONFIG_USE_ZEPHYR_BLE +#define CHIP_DEVICE_CONFIG_USE_ZEPHYR_BLE 1 +#endif // CHIP_DEVICE_CONFIG_USE_ZEPHYR_BLE + +#ifndef CHIP_DEVICE_CONFIG_PROCESS_BLE_IN_THREAD +#define CHIP_DEVICE_CONFIG_PROCESS_BLE_IN_THREAD 0 +#endif // CHIP_DEVICE_CONFIG_PROCESS_BLE_IN_THREAD + +#ifndef CHIP_DEVICE_CONFIG_INIT_OT_PLAT_ALARM +#define CHIP_DEVICE_CONFIG_INIT_OT_PLAT_ALARM 1 +#endif // CHIP_DEVICE_CONFIG_INIT_OT_PLAT_ALARM diff --git a/src/platform/nxp/common/CHIPDevicePlatformEvent.h b/src/platform/nxp/common/CHIPDevicePlatformEvent.h index 4ea4ffcd304dbe..5c6a5c3c39ecf9 100644 --- a/src/platform/nxp/common/CHIPDevicePlatformEvent.h +++ b/src/platform/nxp/common/CHIPDevicePlatformEvent.h @@ -24,7 +24,7 @@ */ #pragma once -#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE && CHIP_DEVICE_CONFIG_USE_ZEPHYR_BLE #include #include #include @@ -74,7 +74,7 @@ enum InternalPlatformSpecificEventTypes } // namespace DeviceEventType -#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE && CHIP_DEVICE_CONFIG_USE_ZEPHYR_BLE struct BleConnEventType { bt_conn * BtConn; @@ -108,7 +108,7 @@ struct ChipDevicePlatformEvent final { union { -#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE && CHIP_DEVICE_CONFIG_USE_ZEPHYR_BLE BleConnEventType BleConnEvent; BleCCCWriteEventType BleCCCWriteEvent; BleC1WriteEventType BleC1WriteEvent; diff --git a/src/platform/nxp/common/CHIPNXPPlatformDefaultConfig.h b/src/platform/nxp/common/CHIPNXPPlatformDefaultConfig.h index 9282ffb5fe868e..0c263fc6ae3cfa 100644 --- a/src/platform/nxp/common/CHIPNXPPlatformDefaultConfig.h +++ b/src/platform/nxp/common/CHIPNXPPlatformDefaultConfig.h @@ -217,6 +217,34 @@ #define WDM_PUBLISHER_MAX_NOTIFIES_IN_FLIGHT 2 #endif // WDM_PUBLISHER_MAX_NOTIFIES_IN_FLIGHT +// ==================== ICD Configuration Overrides ==================== + +#ifndef NXP_ICD_ENABLED +#define NXP_ICD_ENABLED 0 +#endif // NXP_ICD_ENABLED + +#if NXP_ICD_ENABLED +#ifndef CHIP_CONFIG_ICD_IDLE_MODE_DURATION_SEC +#define CHIP_CONFIG_ICD_IDLE_MODE_DURATION_SEC NXP_IDLE_MODE_DURATION_SEC +#endif // CHIP_CONFIG_ICD_IDLE_MODE_DURATION_SEC + +#ifndef CHIP_CONFIG_ICD_ACTIVE_MODE_DURATION_MS +#define CHIP_CONFIG_ICD_ACTIVE_MODE_DURATION_MS NXP_ACTIVE_MODE_DURATION_MS +#endif // CHIP_CONFIG_ICD_ACTIVE_MODE_DURATION_MS + +#ifndef CHIP_CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS +#define CHIP_CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS NXP_ACTIVE_MODE_THRESHOLD +#endif // CHIP_CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS + +#ifndef CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC +#define CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC NXP_ICD_SUPPORTED_CLIENTS_PER_FABRIC +#endif // CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC + +#ifndef CHIP_CONFIG_SYNCHRONOUS_REPORTS_ENABLED +#define CHIP_CONFIG_SYNCHRONOUS_REPORTS_ENABLED 1 +#endif +#endif // NXP_ICD_ENABLED + // ==================== Other Configuration Overrides ==================== #ifndef CHIP_CONFIG_RMP_DEFAULT_MAX_RETRANS diff --git a/src/platform/nxp/common/ConfigurationManagerImpl.cpp b/src/platform/nxp/common/ConfigurationManagerImpl.cpp index e99f913369eda8..ad8f00eaf3a4cb 100644 --- a/src/platform/nxp/common/ConfigurationManagerImpl.cpp +++ b/src/platform/nxp/common/ConfigurationManagerImpl.cpp @@ -33,6 +33,10 @@ #include "fsl_device_registers.h" +#if CONFIG_BOOT_REASON_SDK_SUPPORT +#include "fsl_power.h" +#endif + #if CONFIG_CHIP_PLAT_LOAD_REAL_FACTORY_DATA #include "FactoryDataProvider.h" #endif @@ -54,12 +58,61 @@ ConfigurationManagerImpl & ConfigurationManagerImpl::GetDefaultInstance() return sInstance; } +#if CONFIG_BOOT_REASON_SDK_SUPPORT +CHIP_ERROR ConfigurationManagerImpl::DetermineBootReason(uint8_t rebootCause) +{ + /* + With current implementation kBrownOutReset couldn't be catched + */ + BootReasonType bootReason = BootReasonType::kUnspecified; + + if (rebootCause == 0) + { + bootReason = BootReasonType::kPowerOnReboot; + } + + else if (rebootCause == kPOWER_ResetCauseWdt) + { + /* Reboot can be due to hardware or software watchdog */ + bootReason = BootReasonType::kHardwareWatchdogReset; + } + else if (rebootCause == kPOWER_ResetCauseSysResetReq) + { + /* + kConfigKey_SoftwareUpdateCompleted not supported for now + if (NXPConfig::ConfigValueExists(NXPConfig::kConfigKey_SoftwareUpdateCompleted)) + { + bootReason = BootReasonType::kSoftwareUpdateCompleted; + } + else + { + bootReason = BootReasonType::kSoftwareReset; + } + */ + bootReason = BootReasonType::kSoftwareReset; + } + + return StoreBootReason(to_underlying(bootReason)); +} +#endif + +CHIP_ERROR ConfigurationManagerImpl::StoreSoftwareUpdateCompleted() +{ + /* Empty implementation*/ + return CHIP_NO_ERROR; +} + CHIP_ERROR ConfigurationManagerImpl::Init() { CHIP_ERROR err; uint32_t rebootCount = 0; bool failSafeArmed; +#if CONFIG_BOOT_REASON_SDK_SUPPORT + uint8_t rebootCause = POWER_GetResetCause(); + POWER_ClearResetCause(rebootCause); +#endif + // Initialize the generic implementation base class. err = Internal::GenericConfigurationManagerImpl::Init(); SuccessOrExit(err); @@ -84,12 +137,15 @@ CHIP_ERROR ConfigurationManagerImpl::Init() err = StoreTotalOperationalHours(0); SuccessOrExit(err); } - +#if CONFIG_BOOT_REASON_SDK_SUPPORT + SuccessOrExit(err = DetermineBootReason(rebootCause)); +#else if (!NXPConfig::ConfigValueExists(NXPConfig::kCounterKey_BootReason)) { err = StoreBootReason(to_underlying(BootReasonType::kUnspecified)); SuccessOrExit(err); } +#endif // TODO: Initialize the global GroupKeyStore object here diff --git a/src/platform/nxp/common/ConfigurationManagerImpl.h b/src/platform/nxp/common/ConfigurationManagerImpl.h index 062cc9dcac3901..e680942af6e6fe 100644 --- a/src/platform/nxp/common/ConfigurationManagerImpl.h +++ b/src/platform/nxp/common/ConfigurationManagerImpl.h @@ -39,6 +39,7 @@ class ConfigurationManagerImpl final : public Internal::GenericConfigurationMana public: // This returns an instance of this class. static ConfigurationManagerImpl & GetDefaultInstance(); + CHIP_ERROR StoreSoftwareUpdateCompleted(); private: // ===== Members that implement the ConfigurationManager public interface. @@ -78,6 +79,9 @@ class ConfigurationManagerImpl final : public Internal::GenericConfigurationMana // ===== Private members reserved for use by this class only. static void DoFactoryReset(intptr_t arg); +#if CONFIG_BOOT_REASON_SDK_SUPPORT + CHIP_ERROR DetermineBootReason(uint8_t rebootCause); +#endif }; /** diff --git a/src/platform/nxp/common/ConnectivityManagerImpl.cpp b/src/platform/nxp/common/ConnectivityManagerImpl.cpp index 0386de643455ef..cbdb866ae71973 100644 --- a/src/platform/nxp/common/ConnectivityManagerImpl.cpp +++ b/src/platform/nxp/common/ConnectivityManagerImpl.cpp @@ -32,10 +32,12 @@ #include #endif +#if CHIP_SYSTEM_CONFIG_USE_LWIP #include #include #include #include +#endif #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE #include diff --git a/src/platform/nxp/common/DiagnosticDataProviderImpl.cpp b/src/platform/nxp/common/DiagnosticDataProviderImpl.cpp index 0dd9b52f6a0aba..93a73d2767b8d3 100644 --- a/src/platform/nxp/common/DiagnosticDataProviderImpl.cpp +++ b/src/platform/nxp/common/DiagnosticDataProviderImpl.cpp @@ -29,7 +29,10 @@ #include #include + +#if CHIP_SYSTEM_CONFIG_USE_LWIP #include +#endif #if CHIP_DEVICE_CONFIG_ENABLE_WPA extern "C" { diff --git a/src/platform/nxp/common/ThreadStackManagerImpl.cpp b/src/platform/nxp/common/ThreadStackManagerImpl.cpp index b15ad60f0e9578..5667eefc7650ed 100644 --- a/src/platform/nxp/common/ThreadStackManagerImpl.cpp +++ b/src/platform/nxp/common/ThreadStackManagerImpl.cpp @@ -20,8 +20,7 @@ /** * @file * Provides an implementation of the ThreadStackManager object for - * NXP platforms using the NXP SDK and the OpenThread - * stack. + * NXP platforms using the NXP SDK and the OpenThread stack. * */ @@ -32,7 +31,11 @@ #include #include +#if CHIP_SYSTEM_CONFIG_USE_LWIP #include +#else +#include +#endif #include @@ -59,21 +62,44 @@ CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack(void) { CHIP_ERROR err = CHIP_NO_ERROR; +#if CHIP_DEVICE_CONFIG_INIT_OT_PLAT_ALARM /* Initialize the OpenThread Alarm module to make sure that if calling otInstance, * it can schedule events */ otPlatAlarmInit(); +#endif // Initialize the generic implementation base classes. err = GenericThreadStackManagerImpl_FreeRTOS::DoInit(); SuccessOrExit(err); +#if CHIP_SYSTEM_CONFIG_USE_LWIP err = GenericThreadStackManagerImpl_OpenThread_LwIP::DoInit(NULL); +#else + err = GenericThreadStackManagerImpl_OpenThread::DoInit(NULL); +#endif SuccessOrExit(err); exit: return err; } +#if CHIP_DEVICE_CONFIG_PROCESS_BLE_IN_THREAD +void ThreadStackManagerImpl::ProcessThreadActivity() +{ + /* reuse thread task for ble processing. + * by doing this, we avoid allocating a new stack for short-lived + * BLE processing (e.g.: only during Matter commissioning) + */ +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + auto * bleManager = &chip::DeviceLayer::Internal::BLEMgrImpl(); + bleManager->DoBleProcessing(); +#endif + + otTaskletsProcess(OTInstance()); + otSysProcessDrivers(OTInstance()); +} +#endif + bool ThreadStackManagerImpl::IsInitialized() { return sInstance.mThreadStackLock != NULL; @@ -112,3 +138,8 @@ extern "C" void otPlatFree(void * aPtr) { return CHIPPlatformMemoryFree(aPtr); } + +extern "C" void * otPlatRealloc(void * p, size_t aSize) +{ + return CHIPPlatformMemoryRealloc(p, aSize); +} diff --git a/src/platform/nxp/common/ThreadStackManagerImpl.h b/src/platform/nxp/common/ThreadStackManagerImpl.h index 6f9fae80950670..83990db21569dc 100644 --- a/src/platform/nxp/common/ThreadStackManagerImpl.h +++ b/src/platform/nxp/common/ThreadStackManagerImpl.h @@ -28,7 +28,11 @@ #include #include #include +#if CHIP_SYSTEM_CONFIG_USE_LWIP #include +#else +#include +#endif extern "C" void otSysEventSignalPending(void); @@ -43,7 +47,11 @@ class ThreadStackManagerImpl; * using the NXP SDK and the OpenThread stack. */ class ThreadStackManagerImpl final : public ThreadStackManager, +#if CHIP_SYSTEM_CONFIG_USE_LWIP public Internal::GenericThreadStackManagerImpl_OpenThread_LwIP, +#else + public Internal::GenericThreadStackManagerImpl_OpenThread, +#endif public Internal::GenericThreadStackManagerImpl_FreeRTOS { // Allow the ThreadStackManager interface class to delegate method calls to @@ -53,8 +61,11 @@ class ThreadStackManagerImpl final : public ThreadStackManager, // Allow the generic implementation base classes to call helper methods on // this class. #ifndef DOXYGEN_SHOULD_SKIP_THIS - friend Internal::GenericThreadStackManagerImpl_OpenThread; +#if CHIP_SYSTEM_CONFIG_USE_LWIP friend Internal::GenericThreadStackManagerImpl_OpenThread_LwIP; +#else + friend Internal::GenericThreadStackManagerImpl_OpenThread; +#endif friend Internal::GenericThreadStackManagerImpl_FreeRTOS; #endif @@ -66,6 +77,11 @@ class ThreadStackManagerImpl final : public ThreadStackManager, public: // ===== Platform-specific members that may be accessed directly by the application. +#if CHIP_DEVICE_CONFIG_PROCESS_BLE_IN_THREAD + using ThreadStackManager::ProcessThreadActivity; + void ProcessThreadActivity(); +#endif + protected: // ===== Methods that implement the ThreadStackManager abstract interface. CHIP_ERROR _InitThreadStack(void); diff --git a/src/platform/silabs/KeyValueStoreManagerImpl.cpp b/src/platform/silabs/KeyValueStoreManagerImpl.cpp index 8f886dba84ba67..012c951aaaa729 100644 --- a/src/platform/silabs/KeyValueStoreManagerImpl.cpp +++ b/src/platform/silabs/KeyValueStoreManagerImpl.cpp @@ -164,15 +164,9 @@ void KeyValueStoreManagerImpl::ScheduleKeyMapSave(void) During commissioning, the key map will be modified multiples times subsequently. Commit the key map in nvm once it as stabilized. */ -#if SLI_SI91X_MCU_INTERFACE && CHIP_CONFIG_ENABLE_ICD_SERVER - // TODO: Remove this when RTC timer is added MATTER-2705 - SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_KvsStringKeyMap, reinterpret_cast(mKvsKeyMap), - sizeof(mKvsKeyMap)); -#else SystemLayer().StartTimer( std::chrono::duration_cast(System::Clock::Seconds32(SILABS_KVS_SAVE_DELAY_SECONDS)), KeyValueStoreManagerImpl::OnScheduledKeyMapSave, NULL); -#endif // defined(SLI_SI91X_MCU_INTERFACE) && CHIP_CONFIG_ENABLE_ICD_SERVER } CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size, diff --git a/src/python_testing/spec_parsing_support.py b/src/python_testing/spec_parsing_support.py index bc36049de54cd5..c2819960146ed3 100644 --- a/src/python_testing/spec_parsing_support.py +++ b/src/python_testing/spec_parsing_support.py @@ -130,7 +130,8 @@ class CommandType(Enum): 0x042F: 'RNCONC', 0x0071: 'HEPAFREMON', 0x0072: 'ACFREMON', - 0x0405: 'RH'} + 0x0405: 'RH', + 0x001C: 'PWM'} class ClusterParser: diff --git a/src/python_testing/test_testing/example_pics_xml_basic_info.xml b/src/python_testing/test_testing/example_pics_xml_basic_info.xml index 96f1a34f3e9557..3d488c3ae90ace 100644 --- a/src/python_testing/test_testing/example_pics_xml_basic_info.xml +++ b/src/python_testing/test_testing/example_pics_xml_basic_info.xml @@ -22,6 +22,14 @@ Draft O true + + + LVL.S + Does the device implement the Level Control Cluster as a server? + 9.1. Role - index.html[pdf] + O + true + diff --git a/src/python_testing/test_testing/test_IDM_10_4.py b/src/python_testing/test_testing/test_IDM_10_4.py index ccf713450e2348..8634e94129b86a 100644 --- a/src/python_testing/test_testing/test_IDM_10_4.py +++ b/src/python_testing/test_testing/test_IDM_10_4.py @@ -38,40 +38,48 @@ def create_read(include_reachable: bool = False, include_max_paths: bool = False, include_vendor_id: bool = True) -> Attribute.AsyncReadTransaction.ReadResponse: # Attribute read here is set to match the example_pics_xml_basic_info.xml in this directory bi = Clusters.BasicInformation.Attributes - attrs = {bi.DataModelRevision: 1, - bi.VendorName: 'testVendor', - bi.ProductName: 'testProduct', - bi.ProductID: 0x8000, - bi.NodeLabel: 'label', - bi.Location: 'XX', - bi.HardwareVersion: 1, - bi.HardwareVersionString: 'one', - bi.SoftwareVersion: 2, - bi.SoftwareVersionString: 'two', - bi.ManufacturingDate: 'today', - bi.PartNumber: 'three', - bi.ProductURL: 'example.com', - bi.ProductLabel: 'myProduct', - bi.SerialNumber: 'ABCD1234', - bi.LocalConfigDisabled: False, - bi.UniqueID: 'Hashy-McHashface'} + lvl = Clusters.LevelControl.Attributes + attrs_bi = {bi.DataModelRevision: 1, + bi.VendorName: 'testVendor', + bi.ProductName: 'testProduct', + bi.ProductID: 0x8000, + bi.NodeLabel: 'label', + bi.Location: 'XX', + bi.HardwareVersion: 1, + bi.HardwareVersionString: 'one', + bi.SoftwareVersion: 2, + bi.SoftwareVersionString: 'two', + bi.ManufacturingDate: 'today', + bi.PartNumber: 'three', + bi.ProductURL: 'example.com', + bi.ProductLabel: 'myProduct', + bi.SerialNumber: 'ABCD1234', + bi.LocalConfigDisabled: False, + bi.UniqueID: 'Hashy-McHashface'} if include_reachable: - attrs[bi.Reachable] = True + attrs_bi[bi.Reachable] = True if include_max_paths: - attrs[bi.MaxPathsPerInvoke] = 2 + attrs_bi[bi.MaxPathsPerInvoke] = 2 if include_vendor_id: - attrs[bi.VendorID] = 0xFFF1 + attrs_bi[bi.VendorID] = 0xFFF1 - attrs[bi.AttributeList] = [a.attribute_id for a in attrs.keys()] - attrs[bi.AcceptedCommandList] = [] - attrs[bi.GeneratedCommandList] = [] - attrs[bi.FeatureMap] = 0 + attrs_bi[bi.AttributeList] = [a.attribute_id for a in attrs_bi.keys()] + attrs_bi[bi.AcceptedCommandList] = [] + attrs_bi[bi.GeneratedCommandList] = [] + attrs_bi[bi.FeatureMap] = 0 + + attrs_lvl = {} + attrs_lvl[lvl.AttributeList] = [] + attrs_lvl[lvl.AcceptedCommandList] = [] + attrs_lvl[lvl.GeneratedCommandList] = [] + attrs_lvl[lvl.FeatureMap] = 0 resp = Attribute.AsyncReadTransaction.ReadResponse({}, [], {}) - resp.attributes = {0: {Clusters.BasicInformation: attrs}} + resp.attributes = {0: {Clusters.BasicInformation: attrs_bi, Clusters.LevelControl: attrs_lvl}} - tlv_attrs = {a.attribute_id: value for a, value in attrs.items()} - resp.tlvAttributes = {0: {Clusters.BasicInformation.id: tlv_attrs}} + tlv_attrs_bi = {a.attribute_id: value for a, value in attrs_bi.items()} + tlv_attrs_lvl = {a.attribute_id: value for a, value in attrs_lvl.items()} + resp.tlvAttributes = {0: {Clusters.BasicInformation.id: tlv_attrs_bi, Clusters.LevelControl.id: tlv_attrs_lvl}} return resp diff --git a/third_party/silabs/SiWx917_sdk.gni b/third_party/silabs/SiWx917_sdk.gni index a7bfe1456c0b4d..5faba08acd3d3b 100644 --- a/third_party/silabs/SiWx917_sdk.gni +++ b/third_party/silabs/SiWx917_sdk.gni @@ -291,14 +291,20 @@ template("siwx917_sdk") { if (invoker.enable_dic) { _include_dirs += [ "${chip_root}/third_party/silabs/mqtt/stack" ] } + + if (chip_enable_icd_server || !disable_lcd) { + defines += [ + "SL_SLEEP_TIMER=1", + "SI91X_SYSRTC_COUNT=1", + ] + } + if (!disable_lcd) { defines += [ "CONFIG_ENABLE_UART", - "SI91X_SYSRTC_COUNT=1", "SYSCALLS_WRITE", "SPI_MULTI_SLAVE", "SL_ULP_TIMER", - "SL_SLEEP_TIMER", ] } @@ -755,6 +761,14 @@ template("siwx917_sdk") { ] } + if (chip_enable_icd_server || !disable_lcd) { + sources += [ + "${efr32_sdk_root}/platform/service/sleeptimer/src/sl_sleeptimer.c", + "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/rsi_sysrtc.c", + "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/service/sleeptimer/src/sl_sleeptimer_hal_si91x_sysrtc.c", + ] + } + if (!disable_lcd) { sources += [ "${efr32_sdk_root}/platform/middleware/glib/dmd/display/dmd_memlcd.c", @@ -769,13 +783,10 @@ template("siwx917_sdk") { "${efr32_sdk_root}/platform/middleware/glib/glib/glib_polygon.c", "${efr32_sdk_root}/platform/middleware/glib/glib/glib_rectangle.c", "${efr32_sdk_root}/platform/middleware/glib/glib/glib_string.c", - "${efr32_sdk_root}/platform/service/sleeptimer/src/sl_sleeptimer.c", "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/cmsis_driver/SPI.c", "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/hardware_drivers/memlcd/src/memlcd_917/sl_memlcd_spi.c", "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/hardware_drivers/memlcd/src/sl_memlcd.c", "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/hardware_drivers/memlcd/src/sl_memlcd_display.c", - "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/rsi_sysrtc.c", - "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/service/sleeptimer/src/sl_sleeptimer_hal_si91x_sysrtc.c", "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/unified_api/src/sl_si91x_ulp_timer.c", ] } diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp index 780c47550b30c2..5ea642c2490387 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp @@ -38645,6 +38645,154 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t valu } // namespace Attributes } // namespace ContentAppObserver +namespace CommissionerControl { +namespace Attributes { + +namespace SupportedDeviceCategories { + +Protocols::InteractionModel::Status +Get(chip::EndpointId endpoint, chip::BitMask * value) +{ + using Traits = NumericAttributeTraits>; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + Protocols::InteractionModel::Status status = + emberAfReadAttribute(endpoint, Clusters::CommissionerControl::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + *value = Traits::StorageToWorking(temp); + return status; +} + +Protocols::InteractionModel::Status +Set(chip::EndpointId endpoint, chip::BitMask value, + MarkAttributeDirty markDirty) +{ + using Traits = NumericAttributeTraits>; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::CommissionerControl::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE, markDirty); +} + +Protocols::InteractionModel::Status +Set(chip::EndpointId endpoint, chip::BitMask value) +{ + using Traits = NumericAttributeTraits>; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::CommissionerControl::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE); +} + +} // namespace SupportedDeviceCategories + +namespace FeatureMap { + +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint32_t * value) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + Protocols::InteractionModel::Status status = + emberAfReadAttribute(endpoint, Clusters::CommissionerControl::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + *value = Traits::StorageToWorking(temp); + return status; +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value, MarkAttributeDirty markDirty) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::CommissionerControl::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE, markDirty); +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::CommissionerControl::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE); +} + +} // namespace FeatureMap + +namespace ClusterRevision { + +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint16_t * value) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + Protocols::InteractionModel::Status status = + emberAfReadAttribute(endpoint, Clusters::CommissionerControl::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + *value = Traits::StorageToWorking(temp); + return status; +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::CommissionerControl::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE, markDirty); +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::CommissionerControl::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE); +} + +} // namespace ClusterRevision + +} // namespace Attributes +} // namespace CommissionerControl + namespace ElectricalMeasurement { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h index fc4bd864dac3e6..2e9f20115c2738 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h @@ -5961,6 +5961,35 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t valu } // namespace Attributes } // namespace ContentAppObserver +namespace CommissionerControl { +namespace Attributes { + +namespace SupportedDeviceCategories { +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, + chip::BitMask * + value); // SupportedDeviceCategoryBitmap +Protocols::InteractionModel::Status +Set(chip::EndpointId endpoint, chip::BitMask value); +Protocols::InteractionModel::Status +Set(chip::EndpointId endpoint, chip::BitMask value, + MarkAttributeDirty markDirty); +} // namespace SupportedDeviceCategories + +namespace FeatureMap { +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint32_t * value); // bitmap32 +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value); +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value, MarkAttributeDirty markDirty); +} // namespace FeatureMap + +namespace ClusterRevision { +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint16_t * value); // int16u +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value); +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty); +} // namespace ClusterRevision + +} // namespace Attributes +} // namespace CommissionerControl + namespace ElectricalMeasurement { namespace Attributes { 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 8276f84a1128a7..7be9f882fd37ef 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -628,6 +628,11 @@ void emberAfContentControlClusterInitCallback(chip::EndpointId endpoint); */ void emberAfContentAppObserverClusterInitCallback(chip::EndpointId endpoint); +/** + * @param endpoint Endpoint that is being initialized + */ +void emberAfCommissionerControlClusterInitCallback(chip::EndpointId endpoint); + /** * @param endpoint Endpoint that is being initialized */ @@ -5249,6 +5254,44 @@ chip::Protocols::InteractionModel::Status MatterContentAppObserverClusterServerP */ void emberAfContentAppObserverClusterServerTickCallback(chip::EndpointId endpoint); +// +// Commissioner Control Cluster +// + +/** + * @param endpoint Endpoint that is being initialized + */ +void emberAfCommissionerControlClusterServerInitCallback(chip::EndpointId endpoint); + +/** + * @param endpoint Endpoint that is being shutdown + */ +void MatterCommissionerControlClusterServerShutdownCallback(chip::EndpointId endpoint); + +/** + * @param endpoint Endpoint that is being initialized + */ +void emberAfCommissionerControlClusterClientInitCallback(chip::EndpointId endpoint); + +/** + * @param attributePath Concrete attribute path that changed + */ +void MatterCommissionerControlClusterServerAttributeChangedCallback(const chip::app::ConcreteAttributePath & attributePath); + +/** + * @param attributePath Concrete attribute path to be changed + * @param attributeType Attribute type + * @param size Attribute size + * @param value Attribute value + */ +chip::Protocols::InteractionModel::Status MatterCommissionerControlClusterServerPreAttributeChangedCallback( + const chip::app::ConcreteAttributePath & attributePath, EmberAfAttributeType attributeType, uint16_t size, uint8_t * value); + +/** + * @param endpoint Endpoint that is being served + */ +void emberAfCommissionerControlClusterServerTickCallback(chip::EndpointId endpoint); + // // Electrical Measurement Cluster // @@ -6685,6 +6728,18 @@ bool emberAfContentControlClusterSetScheduledContentRatingThresholdCallback( bool emberAfContentAppObserverClusterContentAppMessageCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::ContentAppObserver::Commands::ContentAppMessage::DecodableType & commandData); +/** + * @brief Commissioner Control Cluster RequestCommissioningApproval Command callback (from client) + */ +bool emberAfCommissionerControlClusterRequestCommissioningApprovalCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::CommissionerControl::Commands::RequestCommissioningApproval::DecodableType & commandData); +/** + * @brief Commissioner Control Cluster CommissionNode Command callback (from client) + */ +bool emberAfCommissionerControlClusterCommissionNodeCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::CommissionerControl::Commands::CommissionNode::DecodableType & commandData); /** * @brief Electrical Measurement Cluster GetProfileInfoCommand Command callback (from client) */ diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index 54b6469552b8fc..65e540c8bbcb2f 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -5179,6 +5179,15 @@ enum class StatusEnum : uint8_t }; } // namespace ContentAppObserver +namespace CommissionerControl { + +// Bitmap for SupportedDeviceCategoryBitmap +enum class SupportedDeviceCategoryBitmap : uint32_t +{ + kFabricSynchronization = 0x1, +}; +} // namespace CommissionerControl + namespace ElectricalMeasurement {} // namespace ElectricalMeasurement namespace UnitTesting { 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 f2f6869b217ffb..d821d185f11272 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 @@ -27947,6 +27947,242 @@ CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const Concre namespace Events {} // namespace Events } // namespace ContentAppObserver +namespace CommissionerControl { + +namespace Commands { +namespace RequestCommissioningApproval { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + encoder.Encode(to_underlying(Fields::kRequestId), requestId); + encoder.Encode(to_underlying(Fields::kVendorId), vendorId); + encoder.Encode(to_underlying(Fields::kProductId), productId); + encoder.Encode(to_underlying(Fields::kLabel), label); + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kRequestId)) + { + err = DataModel::Decode(reader, requestId); + } + else if (__context_tag == to_underlying(Fields::kVendorId)) + { + err = DataModel::Decode(reader, vendorId); + } + else if (__context_tag == to_underlying(Fields::kProductId)) + { + err = DataModel::Decode(reader, productId); + } + else if (__context_tag == to_underlying(Fields::kLabel)) + { + err = DataModel::Decode(reader, label); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} +} // namespace RequestCommissioningApproval. +namespace CommissionNode { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + encoder.Encode(to_underlying(Fields::kRequestId), requestId); + encoder.Encode(to_underlying(Fields::kResponseTimeoutSeconds), responseTimeoutSeconds); + encoder.Encode(to_underlying(Fields::kIpAddress), ipAddress); + encoder.Encode(to_underlying(Fields::kPort), port); + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kRequestId)) + { + err = DataModel::Decode(reader, requestId); + } + else if (__context_tag == to_underlying(Fields::kResponseTimeoutSeconds)) + { + err = DataModel::Decode(reader, responseTimeoutSeconds); + } + else if (__context_tag == to_underlying(Fields::kIpAddress)) + { + err = DataModel::Decode(reader, ipAddress); + } + else if (__context_tag == to_underlying(Fields::kPort)) + { + err = DataModel::Decode(reader, port); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} +} // namespace CommissionNode. +namespace ReverseOpenCommissioningWindow { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + encoder.Encode(to_underlying(Fields::kCommissioningTimeout), commissioningTimeout); + encoder.Encode(to_underlying(Fields::kPAKEPasscodeVerifier), PAKEPasscodeVerifier); + encoder.Encode(to_underlying(Fields::kDiscriminator), discriminator); + encoder.Encode(to_underlying(Fields::kIterations), iterations); + encoder.Encode(to_underlying(Fields::kSalt), salt); + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kCommissioningTimeout)) + { + err = DataModel::Decode(reader, commissioningTimeout); + } + else if (__context_tag == to_underlying(Fields::kPAKEPasscodeVerifier)) + { + err = DataModel::Decode(reader, PAKEPasscodeVerifier); + } + else if (__context_tag == to_underlying(Fields::kDiscriminator)) + { + err = DataModel::Decode(reader, discriminator); + } + else if (__context_tag == to_underlying(Fields::kIterations)) + { + err = DataModel::Decode(reader, iterations); + } + else if (__context_tag == to_underlying(Fields::kSalt)) + { + err = DataModel::Decode(reader, salt); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} +} // namespace ReverseOpenCommissioningWindow. +} // namespace Commands + +namespace Attributes { +CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path) +{ + switch (path.mAttributeId) + { + case Attributes::SupportedDeviceCategories::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, supportedDeviceCategories); + case Attributes::GeneratedCommandList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, generatedCommandList); + case Attributes::AcceptedCommandList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, acceptedCommandList); + case Attributes::EventList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, eventList); + case Attributes::AttributeList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, attributeList); + case Attributes::FeatureMap::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, featureMap); + case Attributes::ClusterRevision::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, clusterRevision); + default: + return CHIP_NO_ERROR; + } +} +} // namespace Attributes + +namespace Events { +namespace CommissioningRequestResult { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + TLV::TLVType outer; + ReturnErrorOnFailure(aWriter.StartContainer(aTag, TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(Fields::kRequestId), requestId)); + ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(Fields::kClientNodeId), clientNodeId)); + ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(Fields::kStatusCode), statusCode)); + ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(Fields::kFabricIndex), fabricIndex)); + return aWriter.EndContainer(outer); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kRequestId)) + { + err = DataModel::Decode(reader, requestId); + } + else if (__context_tag == to_underlying(Fields::kClientNodeId)) + { + err = DataModel::Decode(reader, clientNodeId); + } + else if (__context_tag == to_underlying(Fields::kStatusCode)) + { + err = DataModel::Decode(reader, statusCode); + } + else if (__context_tag == to_underlying(Fields::kFabricIndex)) + { + err = DataModel::Decode(reader, fabricIndex); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} +} // namespace CommissioningRequestResult. +} // namespace Events + +} // namespace CommissionerControl namespace ElectricalMeasurement { namespace Commands { @@ -31766,6 +32002,13 @@ bool CommandIsFabricScoped(ClusterId aCluster, CommandId aCommand) return false; } } + case Clusters::CommissionerControl::Id: { + switch (aCommand) + { + default: + return false; + } + } case Clusters::ElectricalMeasurement::Id: { switch (aCommand) { 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 338820b159e47b..a32e52a5c072f8 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 @@ -40989,6 +40989,274 @@ struct TypeInfo }; } // namespace Attributes } // namespace ContentAppObserver +namespace CommissionerControl { + +namespace Commands { +// Forward-declarations so we can reference these later. + +namespace RequestCommissioningApproval { +struct Type; +struct DecodableType; +} // namespace RequestCommissioningApproval + +namespace CommissionNode { +struct Type; +struct DecodableType; +} // namespace CommissionNode + +namespace ReverseOpenCommissioningWindow { +struct Type; +struct DecodableType; +} // namespace ReverseOpenCommissioningWindow + +} // namespace Commands + +namespace Commands { +namespace RequestCommissioningApproval { +enum class Fields : uint8_t +{ + kRequestId = 0, + kVendorId = 1, + kProductId = 2, + kLabel = 3, +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return Commands::RequestCommissioningApproval::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } + + uint64_t requestId = static_cast(0); + chip::VendorId vendorId = static_cast(0); + uint16_t productId = static_cast(0); + Optional label; + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; + + using ResponseType = DataModel::NullObjectType; + + static constexpr bool MustUseTimedInvoke() { return false; } +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return Commands::RequestCommissioningApproval::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } + + uint64_t requestId = static_cast(0); + chip::VendorId vendorId = static_cast(0); + uint16_t productId = static_cast(0); + Optional label; + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace RequestCommissioningApproval +namespace CommissionNode { +enum class Fields : uint8_t +{ + kRequestId = 0, + kResponseTimeoutSeconds = 1, + kIpAddress = 2, + kPort = 3, +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return Commands::CommissionNode::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } + + uint64_t requestId = static_cast(0); + uint16_t responseTimeoutSeconds = static_cast(0); + Optional ipAddress; + Optional port; + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; + + using ResponseType = Clusters::CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType; + + static constexpr bool MustUseTimedInvoke() { return false; } +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return Commands::CommissionNode::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } + + uint64_t requestId = static_cast(0); + uint16_t responseTimeoutSeconds = static_cast(0); + Optional ipAddress; + Optional port; + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace CommissionNode +namespace ReverseOpenCommissioningWindow { +enum class Fields : uint8_t +{ + kCommissioningTimeout = 0, + kPAKEPasscodeVerifier = 1, + kDiscriminator = 2, + kIterations = 3, + kSalt = 4, +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return Commands::ReverseOpenCommissioningWindow::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } + + uint16_t commissioningTimeout = static_cast(0); + chip::ByteSpan PAKEPasscodeVerifier; + uint16_t discriminator = static_cast(0); + uint32_t iterations = static_cast(0); + chip::ByteSpan salt; + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; + + using ResponseType = DataModel::NullObjectType; + + static constexpr bool MustUseTimedInvoke() { return false; } +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return Commands::ReverseOpenCommissioningWindow::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } + + uint16_t commissioningTimeout = static_cast(0); + chip::ByteSpan PAKEPasscodeVerifier; + uint16_t discriminator = static_cast(0); + uint32_t iterations = static_cast(0); + chip::ByteSpan salt; + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace ReverseOpenCommissioningWindow +} // namespace Commands + +namespace Attributes { + +namespace SupportedDeviceCategories { +struct TypeInfo +{ + using Type = chip::BitMask; + using DecodableType = chip::BitMask; + using DecodableArgType = chip::BitMask; + + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::SupportedDeviceCategories::Id; } + static constexpr bool MustUseTimedWrite() { return false; } +}; +} // namespace SupportedDeviceCategories +namespace GeneratedCommandList { +struct TypeInfo : public Clusters::Globals::Attributes::GeneratedCommandList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } +}; +} // namespace GeneratedCommandList +namespace AcceptedCommandList { +struct TypeInfo : public Clusters::Globals::Attributes::AcceptedCommandList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } +}; +} // namespace AcceptedCommandList +namespace EventList { +struct TypeInfo : public Clusters::Globals::Attributes::EventList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } +}; +} // namespace EventList +namespace AttributeList { +struct TypeInfo : public Clusters::Globals::Attributes::AttributeList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } +}; +} // namespace AttributeList +namespace FeatureMap { +struct TypeInfo : public Clusters::Globals::Attributes::FeatureMap::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } +}; +} // namespace FeatureMap +namespace ClusterRevision { +struct TypeInfo : public Clusters::Globals::Attributes::ClusterRevision::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } +}; +} // namespace ClusterRevision + +struct TypeInfo +{ + struct DecodableType + { + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } + + CHIP_ERROR Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path); + + Attributes::SupportedDeviceCategories::TypeInfo::DecodableType supportedDeviceCategories = + static_cast>(0); + Attributes::GeneratedCommandList::TypeInfo::DecodableType generatedCommandList; + Attributes::AcceptedCommandList::TypeInfo::DecodableType acceptedCommandList; + Attributes::EventList::TypeInfo::DecodableType eventList; + Attributes::AttributeList::TypeInfo::DecodableType attributeList; + Attributes::FeatureMap::TypeInfo::DecodableType featureMap = static_cast(0); + Attributes::ClusterRevision::TypeInfo::DecodableType clusterRevision = static_cast(0); + }; +}; +} // namespace Attributes +namespace Events { +namespace CommissioningRequestResult { +static constexpr PriorityLevel kPriorityLevel = PriorityLevel::Info; + +enum class Fields : uint8_t +{ + kRequestId = 0, + kClientNodeId = 1, + kStatusCode = 2, + kFabricIndex = 254, +}; + +struct Type +{ +public: + static constexpr PriorityLevel GetPriorityLevel() { return kPriorityLevel; } + static constexpr EventId GetEventId() { return Events::CommissioningRequestResult::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } + static constexpr bool kIsFabricScoped = true; + + uint64_t requestId = static_cast(0); + chip::NodeId clientNodeId = static_cast(0); + uint8_t statusCode = static_cast(0); + chip::FabricIndex fabricIndex = static_cast(0); + + auto GetFabricIndex() const { return fabricIndex; } + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; +}; + +struct DecodableType +{ +public: + static constexpr PriorityLevel GetPriorityLevel() { return kPriorityLevel; } + static constexpr EventId GetEventId() { return Events::CommissioningRequestResult::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::CommissionerControl::Id; } + + uint64_t requestId = static_cast(0); + chip::NodeId clientNodeId = static_cast(0); + uint8_t statusCode = static_cast(0); + chip::FabricIndex fabricIndex = static_cast(0); + + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +} // namespace CommissioningRequestResult +} // namespace Events +} // namespace CommissionerControl namespace ElectricalMeasurement { namespace Commands { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h index f45a7cb875af24..b025f1ccf57811 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h @@ -7413,6 +7413,40 @@ static constexpr AttributeId Id = Globals::Attributes::ClusterRevision::Id; } // namespace Attributes } // namespace ContentAppObserver +namespace CommissionerControl { +namespace Attributes { + +namespace SupportedDeviceCategories { +static constexpr AttributeId Id = 0x00000000; +} // namespace SupportedDeviceCategories + +namespace GeneratedCommandList { +static constexpr AttributeId Id = Globals::Attributes::GeneratedCommandList::Id; +} // namespace GeneratedCommandList + +namespace AcceptedCommandList { +static constexpr AttributeId Id = Globals::Attributes::AcceptedCommandList::Id; +} // namespace AcceptedCommandList + +namespace EventList { +static constexpr AttributeId Id = Globals::Attributes::EventList::Id; +} // namespace EventList + +namespace AttributeList { +static constexpr AttributeId Id = Globals::Attributes::AttributeList::Id; +} // namespace AttributeList + +namespace FeatureMap { +static constexpr AttributeId Id = Globals::Attributes::FeatureMap::Id; +} // namespace FeatureMap + +namespace ClusterRevision { +static constexpr AttributeId Id = Globals::Attributes::ClusterRevision::Id; +} // namespace ClusterRevision + +} // namespace Attributes +} // namespace CommissionerControl + namespace ElectricalMeasurement { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h b/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h index 8aec311faafcff..ba42f10b50ffae 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h @@ -382,6 +382,9 @@ static constexpr ClusterId Id = 0x0000050F; namespace ContentAppObserver { static constexpr ClusterId Id = 0x00000510; } // namespace ContentAppObserver +namespace CommissionerControl { +static constexpr ClusterId Id = 0x00000751; +} // namespace CommissionerControl namespace ElectricalMeasurement { static constexpr ClusterId Id = 0x00000B04; } // namespace ElectricalMeasurement 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 0e58f97f149575..608b7d7c7565a7 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 @@ -1783,6 +1783,24 @@ static constexpr CommandId Id = 0x00000001; } // namespace Commands } // namespace ContentAppObserver +namespace CommissionerControl { +namespace Commands { + +namespace RequestCommissioningApproval { +static constexpr CommandId Id = 0x00000000; +} // namespace RequestCommissioningApproval + +namespace CommissionNode { +static constexpr CommandId Id = 0x00000001; +} // namespace CommissionNode + +namespace ReverseOpenCommissioningWindow { +static constexpr CommandId Id = 0x00000002; +} // namespace ReverseOpenCommissioningWindow + +} // namespace Commands +} // namespace CommissionerControl + namespace ElectricalMeasurement { namespace Commands { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Events.h b/zzz_generated/app-common/app-common/zap-generated/ids/Events.h index 1592020a008379..cc619b581dc3e6 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Events.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Events.h @@ -661,6 +661,16 @@ static constexpr EventId Id = 0x00000000; } // namespace Events } // namespace ContentControl +namespace CommissionerControl { +namespace Events { + +namespace CommissioningRequestResult { +static constexpr EventId Id = 0x00000000; +} // namespace CommissioningRequestResult + +} // namespace Events +} // namespace CommissionerControl + namespace UnitTesting { namespace Events { diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index 74e8b95d769ab7..63b07843fd2703 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -154,6 +154,7 @@ | AccountLogin | 0x050E | | ContentControl | 0x050F | | ContentAppObserver | 0x0510 | +| CommissionerControl | 0x0751 | | ElectricalMeasurement | 0x0B04 | | UnitTesting | 0xFFF1FC05| | FaultInjection | 0xFFF1FC06| @@ -13755,6 +13756,108 @@ class ContentAppObserverContentAppMessage : public ClusterCommand chip::app::Clusters::ContentAppObserver::Commands::ContentAppMessage::Type mRequest; }; +/*----------------------------------------------------------------------------*\ +| Cluster CommissionerControl | 0x0751 | +|------------------------------------------------------------------------------| +| Commands: | | +| * RequestCommissioningApproval | 0x00 | +| * CommissionNode | 0x01 | +|------------------------------------------------------------------------------| +| Attributes: | | +| * SupportedDeviceCategories | 0x0000 | +| * GeneratedCommandList | 0xFFF8 | +| * AcceptedCommandList | 0xFFF9 | +| * EventList | 0xFFFA | +| * AttributeList | 0xFFFB | +| * FeatureMap | 0xFFFC | +| * ClusterRevision | 0xFFFD | +|------------------------------------------------------------------------------| +| Events: | | +| * CommissioningRequestResult | 0x0000 | +\*----------------------------------------------------------------------------*/ + +/* + * Command RequestCommissioningApproval + */ +class CommissionerControlRequestCommissioningApproval : public ClusterCommand +{ +public: + CommissionerControlRequestCommissioningApproval(CredentialIssuerCommands * credsIssuerConfig) : + ClusterCommand("request-commissioning-approval", credsIssuerConfig) + { + AddArgument("RequestId", 0, UINT64_MAX, &mRequest.requestId); + AddArgument("VendorId", 0, UINT16_MAX, &mRequest.vendorId); + AddArgument("ProductId", 0, UINT16_MAX, &mRequest.productId); + AddArgument("Label", &mRequest.label); + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::CommissionerControl::Commands::RequestCommissioningApproval::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, + commandId, endpointIds.at(0)); + return ClusterCommand::SendCommand(device, endpointIds.at(0), clusterId, commandId, mRequest); + } + + CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::CommissionerControl::Commands::RequestCommissioningApproval::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, + groupId); + + return ClusterCommand::SendGroupCommand(groupId, fabricIndex, clusterId, commandId, mRequest); + } + +private: + chip::app::Clusters::CommissionerControl::Commands::RequestCommissioningApproval::Type mRequest; +}; + +/* + * Command CommissionNode + */ +class CommissionerControlCommissionNode : public ClusterCommand +{ +public: + CommissionerControlCommissionNode(CredentialIssuerCommands * credsIssuerConfig) : + ClusterCommand("commission-node", credsIssuerConfig) + { + AddArgument("RequestId", 0, UINT64_MAX, &mRequest.requestId); + AddArgument("ResponseTimeoutSeconds", 0, UINT16_MAX, &mRequest.responseTimeoutSeconds); + AddArgument("IpAddress", &mRequest.ipAddress); + AddArgument("Port", 0, UINT16_MAX, &mRequest.port); + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::CommissionerControl::Commands::CommissionNode::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, + commandId, endpointIds.at(0)); + return ClusterCommand::SendCommand(device, endpointIds.at(0), clusterId, commandId, mRequest); + } + + CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::CommissionerControl::Commands::CommissionNode::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, + groupId); + + return ClusterCommand::SendGroupCommand(groupId, fabricIndex, clusterId, commandId, mRequest); + } + +private: + chip::app::Clusters::CommissionerControl::Commands::CommissionNode::Type mRequest; +}; + /*----------------------------------------------------------------------------*\ | Cluster ElectricalMeasurement | 0x0B04 | |------------------------------------------------------------------------------| @@ -26471,6 +26574,69 @@ void registerClusterContentAppObserver(Commands & commands, CredentialIssuerComm commands.RegisterCluster(clusterName, clusterCommands); } +void registerClusterCommissionerControl(Commands & commands, CredentialIssuerCommands * credsIssuerConfig) +{ + using namespace chip::app::Clusters::CommissionerControl; + + const char * clusterName = "CommissionerControl"; + + commands_list clusterCommands = { + // + // Commands + // + make_unique(Id, credsIssuerConfig), // + make_unique(credsIssuerConfig), // + make_unique(credsIssuerConfig), // + // + // Attributes + // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, "supported-device-categories", Attributes::SupportedDeviceCategories::Id, + credsIssuerConfig), // + make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // + make_unique(Id, "attribute-list", Attributes::AttributeList::Id, credsIssuerConfig), // + make_unique(Id, "feature-map", Attributes::FeatureMap::Id, credsIssuerConfig), // + make_unique(Id, "cluster-revision", Attributes::ClusterRevision::Id, credsIssuerConfig), // + make_unique>(Id, credsIssuerConfig), // + make_unique>>( + Id, "supported-device-categories", 0, UINT32_MAX, Attributes::SupportedDeviceCategories::Id, + WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "generated-command-list", Attributes::GeneratedCommandList::Id, WriteCommandType::kForceWrite, + credsIssuerConfig), // + make_unique>>( + Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "event-list", Attributes::EventList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "attribute-list", Attributes::AttributeList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>(Id, "feature-map", 0, UINT32_MAX, Attributes::FeatureMap::Id, + WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>(Id, "cluster-revision", 0, UINT16_MAX, Attributes::ClusterRevision::Id, + WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, "supported-device-categories", Attributes::SupportedDeviceCategories::Id, + credsIssuerConfig), // + make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // + make_unique(Id, "attribute-list", Attributes::AttributeList::Id, credsIssuerConfig), // + make_unique(Id, "feature-map", Attributes::FeatureMap::Id, credsIssuerConfig), // + make_unique(Id, "cluster-revision", Attributes::ClusterRevision::Id, credsIssuerConfig), // + // + // Events + // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, "commissioning-request-result", Events::CommissioningRequestResult::Id, credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, "commissioning-request-result", Events::CommissioningRequestResult::Id, + credsIssuerConfig), // + }; + + commands.RegisterCluster(clusterName, clusterCommands); +} void registerClusterElectricalMeasurement(Commands & commands, CredentialIssuerCommands * credsIssuerConfig) { using namespace chip::app::Clusters::ElectricalMeasurement; @@ -27880,6 +28046,7 @@ void registerClusters(Commands & commands, CredentialIssuerCommands * credsIssue registerClusterAccountLogin(commands, credsIssuerConfig); registerClusterContentControl(commands, credsIssuerConfig); registerClusterContentAppObserver(commands, credsIssuerConfig); + registerClusterCommissionerControl(commands, credsIssuerConfig); registerClusterElectricalMeasurement(commands, credsIssuerConfig); registerClusterUnitTesting(commands, credsIssuerConfig); registerClusterFaultInjection(commands, credsIssuerConfig); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index c41f5734712528..1bf30e655ab661 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -7468,6 +7468,46 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } +CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, + const CommissionerControl::Events::CommissioningRequestResult::DecodableType & value) +{ + DataModelLogger::LogString(label, indent, "{"); + { + CHIP_ERROR err = DataModelLogger::LogValue("RequestId", indent + 1, value.requestId); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Event truncated due to invalid value for 'RequestId'"); + return err; + } + } + { + CHIP_ERROR err = DataModelLogger::LogValue("ClientNodeId", indent + 1, value.clientNodeId); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Event truncated due to invalid value for 'ClientNodeId'"); + return err; + } + } + { + CHIP_ERROR err = DataModelLogger::LogValue("StatusCode", indent + 1, value.statusCode); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Event truncated due to invalid value for 'StatusCode'"); + return err; + } + } + { + CHIP_ERROR err = DataModelLogger::LogValue("FabricIndex", indent + 1, value.fabricIndex); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Event truncated due to invalid value for 'FabricIndex'"); + return err; + } + } + DataModelLogger::LogString(indent, "}"); + + return CHIP_NO_ERROR; +} CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const UnitTesting::Events::TestEvent::DecodableType & value) { DataModelLogger::LogString(label, indent, "{"); @@ -8212,6 +8252,18 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, DataModelLogger::LogString(indent, "}"); return CHIP_NO_ERROR; } +CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, + const CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType & value) +{ + DataModelLogger::LogString(label, indent, "{"); + ReturnErrorOnFailure(DataModelLogger::LogValue("commissioningTimeout", indent + 1, value.commissioningTimeout)); + ReturnErrorOnFailure(DataModelLogger::LogValue("PAKEPasscodeVerifier", indent + 1, value.PAKEPasscodeVerifier)); + ReturnErrorOnFailure(DataModelLogger::LogValue("discriminator", indent + 1, value.discriminator)); + ReturnErrorOnFailure(DataModelLogger::LogValue("iterations", indent + 1, value.iterations)); + ReturnErrorOnFailure(DataModelLogger::LogValue("salt", indent + 1, value.salt)); + DataModelLogger::LogString(indent, "}"); + return CHIP_NO_ERROR; +} CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const ElectricalMeasurement::Commands::GetProfileInfoResponseCommand::DecodableType & value) { @@ -17526,6 +17578,47 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP } break; } + case CommissionerControl::Id: { + switch (path.mAttributeId) + { + case CommissionerControl::Attributes::SupportedDeviceCategories::Id: { + chip::BitMask value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("SupportedDeviceCategories", 1, value); + } + case CommissionerControl::Attributes::GeneratedCommandList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("GeneratedCommandList", 1, value); + } + case CommissionerControl::Attributes::AcceptedCommandList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("AcceptedCommandList", 1, value); + } + case CommissionerControl::Attributes::EventList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("EventList", 1, value); + } + case CommissionerControl::Attributes::AttributeList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("AttributeList", 1, value); + } + case CommissionerControl::Attributes::FeatureMap::Id: { + uint32_t value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("FeatureMap", 1, value); + } + case CommissionerControl::Attributes::ClusterRevision::Id: { + uint16_t value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("ClusterRevision", 1, value); + } + } + break; + } case ElectricalMeasurement::Id: { switch (path.mAttributeId) { @@ -19305,6 +19398,17 @@ CHIP_ERROR DataModelLogger::LogCommand(const chip::app::ConcreteCommandPath & pa } break; } + case CommissionerControl::Id: { + switch (path.mCommandId) + { + case CommissionerControl::Commands::ReverseOpenCommissioningWindow::Id: { + CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("ReverseOpenCommissioningWindow", 1, value); + } + } + break; + } case ElectricalMeasurement::Id: { switch (path.mCommandId) { @@ -20192,6 +20296,17 @@ CHIP_ERROR DataModelLogger::LogEvent(const chip::app::EventHeader & header, chip } break; } + case CommissionerControl::Id: { + switch (header.mPath.mEventId) + { + case CommissionerControl::Events::CommissioningRequestResult::Id: { + chip::app::Clusters::CommissionerControl::Events::CommissioningRequestResult::DecodableType value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("CommissioningRequestResult", 1, value); + } + } + break; + } case UnitTesting::Id: { switch (header.mPath.mEventId) { diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h index 922ae495192512..7aecdf187d7a49 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h @@ -637,6 +637,9 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::AccountLogin::Events::LoggedOut::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::ContentControl::Events::RemainingScreenTimeExpired::DecodableType & value); +static CHIP_ERROR +LogValue(const char * label, size_t indent, + const chip::app::Clusters::CommissionerControl::Events::CommissioningRequestResult::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::UnitTesting::Events::TestEvent::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, @@ -797,6 +800,9 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::ContentAppObserver::Commands::ContentAppMessageResponse::DecodableType & value); static CHIP_ERROR +LogValue(const char * label, size_t indent, + const chip::app::Clusters::CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType & value); +static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::ElectricalMeasurement::Commands::GetProfileInfoResponseCommand::DecodableType & value); static CHIP_ERROR diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index 493b8a45376696..9d6610f69f3faf 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -156,6 +156,7 @@ | AccountLogin | 0x050E | | ContentControl | 0x050F | | ContentAppObserver | 0x0510 | +| CommissionerControl | 0x0751 | | ElectricalMeasurement | 0x0B04 | | UnitTesting | 0xFFF1FC05| | FaultInjection | 0xFFF1FC06| @@ -162276,6 +162277,784 @@ class SubscribeAttributeContentAppObserverClusterRevision : public SubscribeAttr } }; +#endif // MTR_ENABLE_PROVISIONAL +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL +/*----------------------------------------------------------------------------*\ +| Cluster CommissionerControl | 0x0751 | +|------------------------------------------------------------------------------| +| Commands: | | +| * RequestCommissioningApproval | 0x00 | +| * CommissionNode | 0x01 | +|------------------------------------------------------------------------------| +| Attributes: | | +| * SupportedDeviceCategories | 0x0000 | +| * GeneratedCommandList | 0xFFF8 | +| * AcceptedCommandList | 0xFFF9 | +| * EventList | 0xFFFA | +| * AttributeList | 0xFFFB | +| * FeatureMap | 0xFFFC | +| * ClusterRevision | 0xFFFD | +|------------------------------------------------------------------------------| +| Events: | | +| * CommissioningRequestResult | 0x0000 | +\*----------------------------------------------------------------------------*/ + +#if MTR_ENABLE_PROVISIONAL +/* + * Command RequestCommissioningApproval + */ +class CommissionerControlRequestCommissioningApproval : public ClusterCommand { +public: + CommissionerControlRequestCommissioningApproval() + : ClusterCommand("request-commissioning-approval") + { +#if MTR_ENABLE_PROVISIONAL + AddArgument("RequestId", 0, UINT64_MAX, &mRequest.requestId); +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + AddArgument("VendorId", 0, UINT16_MAX, &mRequest.vendorId); +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + AddArgument("ProductId", 0, UINT16_MAX, &mRequest.productId); +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + AddArgument("Label", &mRequest.label); +#endif // MTR_ENABLE_PROVISIONAL + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::CommissionerControl::Commands::RequestCommissioningApproval::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRCommissionerControlClusterRequestCommissioningApprovalParams alloc] init]; + params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; +#if MTR_ENABLE_PROVISIONAL + params.requestId = [NSNumber numberWithUnsignedLongLong:mRequest.requestId]; +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + params.vendorId = [NSNumber numberWithUnsignedShort:chip::to_underlying(mRequest.vendorId)]; +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + params.productId = [NSNumber numberWithUnsignedShort:mRequest.productId]; +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + if (mRequest.label.HasValue()) { + params.label = [[NSString alloc] initWithBytes:mRequest.label.Value().data() length:mRequest.label.Value().size() encoding:NSUTF8StringEncoding]; + } else { + params.label = nil; + } +#endif // MTR_ENABLE_PROVISIONAL + uint16_t repeatCount = mRepeatCount.ValueOr(1); + uint16_t __block responsesNeeded = repeatCount; + while (repeatCount--) { + [cluster requestCommissioningApprovalWithParams:params completion: + ^(NSError * _Nullable error) { + responsesNeeded--; + if (error != nil) { + mError = error; + LogNSError("Error", error); + RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(commandId), error); + } + if (responsesNeeded == 0) { + SetCommandExitStatus(mError); + } + }]; + } + return CHIP_NO_ERROR; + } + +private: + chip::app::Clusters::CommissionerControl::Commands::RequestCommissioningApproval::Type mRequest; +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL +/* + * Command CommissionNode + */ +class CommissionerControlCommissionNode : public ClusterCommand { +public: + CommissionerControlCommissionNode() + : ClusterCommand("commission-node") + { +#if MTR_ENABLE_PROVISIONAL + AddArgument("RequestId", 0, UINT64_MAX, &mRequest.requestId); +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + AddArgument("ResponseTimeoutSeconds", 0, UINT16_MAX, &mRequest.responseTimeoutSeconds); +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + AddArgument("IpAddress", &mRequest.ipAddress); +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + AddArgument("Port", 0, UINT16_MAX, &mRequest.port); +#endif // MTR_ENABLE_PROVISIONAL + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::CommissionerControl::Commands::CommissionNode::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRCommissionerControlClusterCommissionNodeParams alloc] init]; + params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; +#if MTR_ENABLE_PROVISIONAL + params.requestId = [NSNumber numberWithUnsignedLongLong:mRequest.requestId]; +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + params.responseTimeoutSeconds = [NSNumber numberWithUnsignedShort:mRequest.responseTimeoutSeconds]; +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + if (mRequest.ipAddress.HasValue()) { + params.ipAddress = [NSData dataWithBytes:mRequest.ipAddress.Value().data() length:mRequest.ipAddress.Value().size()]; + } else { + params.ipAddress = nil; + } +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + if (mRequest.port.HasValue()) { + params.port = [NSNumber numberWithUnsignedShort:mRequest.port.Value()]; + } else { + params.port = nil; + } +#endif // MTR_ENABLE_PROVISIONAL + uint16_t repeatCount = mRepeatCount.ValueOr(1); + uint16_t __block responsesNeeded = repeatCount; + while (repeatCount--) { + [cluster commissionNodeWithParams:params completion: + ^(MTRCommissionerControlClusterReverseOpenCommissioningWindowParams * _Nullable values, NSError * _Nullable error) { + NSLog(@"Values: %@", values); + if (error == nil) { + constexpr chip::CommandId responseId = chip::app::Clusters::CommissionerControl::Commands::ReverseOpenCommissioningWindow::Id; + RemoteDataModelLogger::LogCommandAsJSON(@(endpointId), @(clusterId), @(responseId), values); + } + responsesNeeded--; + if (error != nil) { + mError = error; + LogNSError("Error", error); + constexpr chip::CommandId responseId = chip::app::Clusters::CommissionerControl::Commands::ReverseOpenCommissioningWindow::Id; + RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(responseId), error); + } + if (responsesNeeded == 0) { + SetCommandExitStatus(mError); + } + }]; + } + return CHIP_NO_ERROR; + } + +private: + chip::app::Clusters::CommissionerControl::Commands::CommissionNode::Type mRequest; +}; + +#endif // MTR_ENABLE_PROVISIONAL + +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute SupportedDeviceCategories + */ +class ReadCommissionerControlSupportedDeviceCategories : public ReadAttribute { +public: + ReadCommissionerControlSupportedDeviceCategories() + : ReadAttribute("supported-device-categories") + { + } + + ~ReadCommissionerControlSupportedDeviceCategories() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::CommissionerControl::Attributes::SupportedDeviceCategories::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeSupportedDeviceCategoriesWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.SupportedDeviceCategories response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("CommissionerControl SupportedDeviceCategories read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeCommissionerControlSupportedDeviceCategories : public SubscribeAttribute { +public: + SubscribeAttributeCommissionerControlSupportedDeviceCategories() + : SubscribeAttribute("supported-device-categories") + { + } + + ~SubscribeAttributeCommissionerControlSupportedDeviceCategories() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::CommissionerControl::Attributes::SupportedDeviceCategories::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeSupportedDeviceCategoriesWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.SupportedDeviceCategories response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute GeneratedCommandList + */ +class ReadCommissionerControlGeneratedCommandList : public ReadAttribute { +public: + ReadCommissionerControlGeneratedCommandList() + : ReadAttribute("generated-command-list") + { + } + + ~ReadCommissionerControlGeneratedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::CommissionerControl::Attributes::GeneratedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeGeneratedCommandListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.GeneratedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("CommissionerControl GeneratedCommandList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeCommissionerControlGeneratedCommandList : public SubscribeAttribute { +public: + SubscribeAttributeCommissionerControlGeneratedCommandList() + : SubscribeAttribute("generated-command-list") + { + } + + ~SubscribeAttributeCommissionerControlGeneratedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::CommissionerControl::Attributes::GeneratedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeGeneratedCommandListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.GeneratedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute AcceptedCommandList + */ +class ReadCommissionerControlAcceptedCommandList : public ReadAttribute { +public: + ReadCommissionerControlAcceptedCommandList() + : ReadAttribute("accepted-command-list") + { + } + + ~ReadCommissionerControlAcceptedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::CommissionerControl::Attributes::AcceptedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeAcceptedCommandListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.AcceptedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("CommissionerControl AcceptedCommandList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeCommissionerControlAcceptedCommandList : public SubscribeAttribute { +public: + SubscribeAttributeCommissionerControlAcceptedCommandList() + : SubscribeAttribute("accepted-command-list") + { + } + + ~SubscribeAttributeCommissionerControlAcceptedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::CommissionerControl::Attributes::AcceptedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeAcceptedCommandListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.AcceptedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute EventList + */ +class ReadCommissionerControlEventList : public ReadAttribute { +public: + ReadCommissionerControlEventList() + : ReadAttribute("event-list") + { + } + + ~ReadCommissionerControlEventList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::CommissionerControl::Attributes::EventList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeEventListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.EventList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("CommissionerControl EventList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeCommissionerControlEventList : public SubscribeAttribute { +public: + SubscribeAttributeCommissionerControlEventList() + : SubscribeAttribute("event-list") + { + } + + ~SubscribeAttributeCommissionerControlEventList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::CommissionerControl::Attributes::EventList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeEventListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.EventList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute AttributeList + */ +class ReadCommissionerControlAttributeList : public ReadAttribute { +public: + ReadCommissionerControlAttributeList() + : ReadAttribute("attribute-list") + { + } + + ~ReadCommissionerControlAttributeList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::CommissionerControl::Attributes::AttributeList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeAttributeListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.AttributeList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("CommissionerControl AttributeList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeCommissionerControlAttributeList : public SubscribeAttribute { +public: + SubscribeAttributeCommissionerControlAttributeList() + : SubscribeAttribute("attribute-list") + { + } + + ~SubscribeAttributeCommissionerControlAttributeList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::CommissionerControl::Attributes::AttributeList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeAttributeListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.AttributeList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute FeatureMap + */ +class ReadCommissionerControlFeatureMap : public ReadAttribute { +public: + ReadCommissionerControlFeatureMap() + : ReadAttribute("feature-map") + { + } + + ~ReadCommissionerControlFeatureMap() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::CommissionerControl::Attributes::FeatureMap::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeFeatureMapWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.FeatureMap response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("CommissionerControl FeatureMap read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeCommissionerControlFeatureMap : public SubscribeAttribute { +public: + SubscribeAttributeCommissionerControlFeatureMap() + : SubscribeAttribute("feature-map") + { + } + + ~SubscribeAttributeCommissionerControlFeatureMap() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::CommissionerControl::Attributes::FeatureMap::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeFeatureMapWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.FeatureMap response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute ClusterRevision + */ +class ReadCommissionerControlClusterRevision : public ReadAttribute { +public: + ReadCommissionerControlClusterRevision() + : ReadAttribute("cluster-revision") + { + } + + ~ReadCommissionerControlClusterRevision() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::CommissionerControl::Attributes::ClusterRevision::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeClusterRevisionWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.ClusterRevision response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("CommissionerControl ClusterRevision read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeCommissionerControlClusterRevision : public SubscribeAttribute { +public: + SubscribeAttributeCommissionerControlClusterRevision() + : SubscribeAttribute("cluster-revision") + { + } + + ~SubscribeAttributeCommissionerControlClusterRevision() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::CommissionerControl::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::CommissionerControl::Attributes::ClusterRevision::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterCommissionerControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeClusterRevisionWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"CommissionerControl.ClusterRevision response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + #endif // MTR_ENABLE_PROVISIONAL #endif // MTR_ENABLE_PROVISIONAL /*----------------------------------------------------------------------------*\ @@ -194405,6 +195184,59 @@ void registerClusterContentAppObserver(Commands & commands) commands.RegisterCluster(clusterName, clusterCommands); #endif // MTR_ENABLE_PROVISIONAL } +void registerClusterCommissionerControl(Commands & commands) +{ +#if MTR_ENABLE_PROVISIONAL + using namespace chip::app::Clusters::CommissionerControl; + + const char * clusterName = "CommissionerControl"; + + commands_list clusterCommands = { + make_unique(Id), // +#if MTR_ENABLE_PROVISIONAL + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL + make_unique(Id), // + make_unique(Id), // + make_unique(Id), // +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL + make_unique(Id), // + make_unique(Id), // + }; + + commands.RegisterCluster(clusterName, clusterCommands); +#endif // MTR_ENABLE_PROVISIONAL +} void registerClusterElectricalMeasurement(Commands & commands) { using namespace chip::app::Clusters::ElectricalMeasurement; @@ -195207,6 +196039,7 @@ void registerClusters(Commands & commands) registerClusterAccountLogin(commands); registerClusterContentControl(commands); registerClusterContentAppObserver(commands); + registerClusterCommissionerControl(commands); registerClusterElectricalMeasurement(commands); registerClusterUnitTesting(commands); registerClusterSampleMei(commands);