diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 94ad9314b9a56c..4d5be76434e8f8 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -14,7 +14,7 @@ "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ], - "initializeCommand": ".devcontainer/build.sh --tag matter-dev-environment:local --version 22", + "initializeCommand": "bash .devcontainer/build.sh --tag matter-dev-environment:local --version 22", "image": "matter-dev-environment:local", "remoteUser": "vscode", "customizations": { diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt index 58a06086679e06..155e909a43f526 100644 --- a/.github/.wordlist.txt +++ b/.github/.wordlist.txt @@ -523,6 +523,7 @@ epochStartTime eq errorValue esd +espcoredump ESPPORT Espressif esptool @@ -1621,4 +1622,4 @@ zephyrproject zhengyaohan Zigbee zigbeealliance -zigbeethread \ No newline at end of file +zigbeethread diff --git a/.github/workflows/cherry-picks.yaml b/.github/workflows/cherry-picks.yaml index 6d9b5339b40b9e..a062aa5fcf9b87 100644 --- a/.github/workflows/cherry-picks.yaml +++ b/.github/workflows/cherry-picks.yaml @@ -14,7 +14,6 @@ jobs: (github.event.pull_request.merged == true) && ( (contains(github.event.pull_request.labels.*.name, 'sve')) - || (contains(github.event.pull_request.labels.*.name, 'spec')) || (contains(github.event.pull_request.labels.*.name, 'request sve')) || (contains(github.event.pull_request.labels.*.name, 'cert blocker')) ) @@ -27,11 +26,12 @@ jobs: uses: carloscastrojumo/github-cherry-pick-action@v1.0.9 with: token: ${{ secrets.MATTER_PAT }} - branch: sve-2 + branch: 1.3-sve labels: | sve cherry pick reviewers: | woody-apple andy31415 + raju-apple env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/darwin-tests.yaml b/.github/workflows/darwin-tests.yaml index 05943be5b0e155..e6e14ec4929a11 100644 --- a/.github/workflows/darwin-tests.yaml +++ b/.github/workflows/darwin-tests.yaml @@ -100,6 +100,7 @@ jobs: --target darwin-x64-bridge-${BUILD_VARIANT} \ --target darwin-x64-lit-icd-${BUILD_VARIANT} \ --target darwin-x64-microwave-oven-${BUILD_VARIANT} \ + --target darwin-x64-rvc-${BUILD_VARIANT} \ build \ --copy-artifacts-to objdir-clone \ " @@ -120,6 +121,7 @@ jobs: --tv-app ./out/darwin-x64-tv-app-${BUILD_VARIANT}/chip-tv-app \ --bridge-app ./out/darwin-x64-bridge-${BUILD_VARIANT}/chip-bridge-app \ --microwave-oven-app ./out/darwin-x64-microwave-oven-${BUILD_VARIANT}/chip-microwave-oven-app \ + --rvc-app ./out/darwin-x64-rvc-${BUILD_VARIANT}/chip-rvc-app \ " - name: Run OTA Test run: | diff --git a/.github/workflows/examples-efr32.yaml b/.github/workflows/examples-efr32.yaml index 36c490956d9ae8..1dae68ced0f4a7 100644 --- a/.github/workflows/examples-efr32.yaml +++ b/.github/workflows/examples-efr32.yaml @@ -38,7 +38,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: ghcr.io/project-chip/chip-build-efr32:35 + image: ghcr.io/project-chip/chip-build-efr32:36 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/.github/workflows/examples-tv-app.yaml b/.github/workflows/examples-tv-app.yaml new file mode 100644 index 00000000000000..fff6cbb39d1acb --- /dev/null +++ b/.github/workflows/examples-tv-app.yaml @@ -0,0 +1,72 @@ +# 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. + +name: Build example - TV App and TV Casting App + +on: + push: + pull_request: + merge_group: + +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: + tv-app: + name: TV App + + env: + BUILD_TYPE: tv_app + + runs-on: ubuntu-latest + if: github.actor != 'restyled-io[bot]' + + container: + image: ghcr.io/project-chip/chip-build-android:35 + volumes: + - "/tmp/bloat_reports:/tmp/bloat_reports" + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Checkout submodules & Bootstrap + uses: ./.github/actions/checkout-submodules-and-bootstrap + with: + platform: android + - name: Set up environment for size reports + uses: ./.github/actions/setup-size-reports + if: ${{ !env.ACT }} + with: + gh-context: ${{ toJson(github) }} + - name: Build Android arm64-tv-casting-app + run: | + ./scripts/run_in_build_env.sh \ + "./scripts/build/build_examples.py --target android-arm64-tv-casting-app build" + - name: Clean out build output + run: rm -rf ./out examples/tv-casting-app/android/App/app/libs/jniLibs/* examples/tv-casting-app/android/App/app/libs/*.jar + - name: Build Android arm64-tv-server + run: | + ./scripts/run_in_build_env.sh \ + "./scripts/build/build_examples.py --target android-arm64-tv-server build" + - name: Clean out build output + run: rm -rf ./out examples/tv-app/android/App/app/libs/jniLibs/* examples/tv-app/android/App/app/libs/*.jar + - name: Uploading Size Reports + uses: ./.github/actions/upload-size-reports + if: ${{ !env.ACT }} + with: + platform-name: TVApp diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 189f63837c841e..d811fe05fa888f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -93,35 +93,25 @@ jobs: --known-failure app/AttributeAccessInterface.h \ --known-failure app/AttributeAccessToken.h \ --known-failure app/att-storage.h \ - --known-failure app/BufferedReadCallback.h \ --known-failure app/CommandHandler.h \ --known-failure app/CommandHandlerInterface.h \ - --known-failure app/CommandPathParams.h \ - --known-failure app/CommandPathRegistry.h \ - --known-failure app/CommandResponseSender.h \ --known-failure app/CommandSender.h \ --known-failure app/CommandSenderLegacyCallback.h \ --known-failure app/CompatEnumNames.h \ - --known-failure app/ConcreteAttributePath.h \ - --known-failure app/ConcreteCommandPath.h \ --known-failure app/data-model/ListLargeSystemExtensions.h \ --known-failure app/EventHeader.h \ --known-failure app/EventLoggingDelegate.h \ --known-failure app/EventLogging.h \ --known-failure app/EventLoggingTypes.h \ - --known-failure app/EventManagement.h \ --known-failure app/InteractionModelHelper.h \ - --known-failure app/ObjectList.h \ --known-failure app/ReadClient.h \ --known-failure app/ReadHandler.h \ --known-failure app/ReadPrepareParams.h \ --known-failure app/reporting/tests/MockReportScheduler.cpp \ --known-failure app/reporting/tests/MockReportScheduler.h \ - --known-failure app/server/AppDelegate.h \ --known-failure app/TestEventTriggerDelegate.h \ --known-failure app/util/af.h \ --known-failure app/util/af-types.h \ - --known-failure app/util/attribute-metadata.h \ --known-failure app/util/attribute-storage.cpp \ --known-failure app/util/attribute-storage.h \ --known-failure app/util/attribute-storage-null-handling.h \ @@ -141,11 +131,7 @@ jobs: --known-failure app/util/im-client-callbacks.h \ --known-failure app/util/MatterCallbacks.h \ --known-failure app/util/message.cpp \ - --known-failure app/util/mock/Constants.h \ - --known-failure app/util/mock/Functions.h \ - --known-failure app/util/mock/MockNodeConfig.h \ --known-failure app/util/odd-sized-integers.h \ - --known-failure app/util/types_stub.h \ --known-failure app/util/util.cpp \ --known-failure app/util/util.h \ --known-failure app/WriteClient.h \ diff --git a/.github/workflows/release_artifacts.yaml b/.github/workflows/release_artifacts.yaml index c82e9f59a27674..65896c73b3faca 100644 --- a/.github/workflows/release_artifacts.yaml +++ b/.github/workflows/release_artifacts.yaml @@ -68,7 +68,7 @@ jobs: runs-on: ubuntu-latest container: - image: ghcr.io/project-chip/chip-build-efr32:35 + image: ghcr.io/project-chip/chip-build-efr32:36 steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 05d2670edd665e..83d921c2fa4188 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -213,6 +213,7 @@ jobs: --target linux-x64-bridge-${BUILD_VARIANT} \ --target linux-x64-lit-icd-${BUILD_VARIANT} \ --target linux-x64-microwave-oven-${BUILD_VARIANT} \ + --target linux-x64-rvc-${BUILD_VARIANT} \ build \ --copy-artifacts-to objdir-clone \ " @@ -234,6 +235,7 @@ jobs: --bridge-app ./out/linux-x64-bridge-${BUILD_VARIANT}/chip-bridge-app \ --lit-icd-app ./out/linux-x64-lit-icd-${BUILD_VARIANT}/lit-icd-app \ --microwave-oven-app ./out/linux-x64-microwave-oven-${BUILD_VARIANT}/chip-microwave-oven-app \ + --rvc-app ./out/linux-x64-rvc-${BUILD_VARIANT}/chip-rvc-app \ " - name: Run purposeful failure tests using the python parser sending commands to chip-tool @@ -274,6 +276,7 @@ jobs: --bridge-app ./out/linux-x64-bridge-${BUILD_VARIANT}/chip-bridge-app \ --lit-icd-app ./out/linux-x64-lit-icd-${BUILD_VARIANT}/lit-icd-app \ --microwave-oven-app ./out/linux-x64-microwave-oven-${BUILD_VARIANT}/chip-microwave-oven-app \ + --rvc-app ./out/linux-x64-rvc-${BUILD_VARIANT}/chip-rvc-app \ " - name: Run Tests using chip-repl (including slow) if: github.event_name == 'push' @@ -292,6 +295,7 @@ jobs: --bridge-app ./out/linux-x64-bridge-${BUILD_VARIANT}/chip-bridge-app \ --lit-icd-app ./out/linux-x64-lit-icd-${BUILD_VARIANT}/lit-icd-app \ --microwave-oven-app ./out/linux-x64-microwave-oven-${BUILD_VARIANT}/chip-microwave-oven-app \ + --rvc-app ./out/linux-x64-rvc-${BUILD_VARIANT}/chip-rvc-app \ " - name: Uploading core files uses: actions/upload-artifact@v4 @@ -359,6 +363,7 @@ jobs: --target darwin-x64-bridge-${BUILD_VARIANT} \ --target darwin-x64-lit-icd-${BUILD_VARIANT} \ --target darwin-x64-microwave-oven-${BUILD_VARIANT} \ + --target darwin-x64-rvc-${BUILD_VARIANT} \ build \ --copy-artifacts-to objdir-clone \ " @@ -381,6 +386,7 @@ jobs: --bridge-app ./out/darwin-x64-bridge-${BUILD_VARIANT}/chip-bridge-app \ --lit-icd-app ./out/darwin-x64-lit-icd-${BUILD_VARIANT}/lit-icd-app \ --microwave-oven-app ./out/darwin-x64-microwave-oven-${BUILD_VARIANT}/chip-microwave-oven-app \ + --rvc-app ./out/darwin-x64-rvc-${BUILD_VARIANT}/chip-rvc-app \ " - name: Run purposeful failure tests using the python parser sending commands to chip-tool @@ -460,6 +466,7 @@ jobs: --target linux-x64-lit-icd-ipv6only-no-ble-no-wifi-tsan-clang-test \ --target linux-x64-energy-management-ipv6only-no-ble-no-wifi-tsan-clang-test \ --target linux-x64-microwave-oven-ipv6only-no-ble-no-wifi-tsan-clang-test \ + --target linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test \ --target linux-x64-python-bindings \ build \ --copy-artifacts-to objdir-clone \ @@ -502,9 +509,8 @@ jobs: 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 --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_IDM_1_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json --enable-key 000102030405060708090a0b0c0d0e0f" --script "src/python_testing/TC_IDM_1_4.py" --script-args "--hex-arg PIXIT.DGGEN.TEST_EVENT_TRIGGER_KEY:000102030405060708090a0b0c0d0e0f --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_IDM_4_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_PWRTL_2_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RR_1_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCCLEANM_1_2.py" --script-args "--int-arg PIXIT_ENDPOINT:1 --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCRUNM_1_2.py" --script-args "--int-arg PIXIT_ENDPOINT:1 --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_SC_3_6.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_TIMESYNC_2_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values --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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_TIMESYNC_2_10.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' @@ -542,6 +548,15 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-microwave-oven-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-microwave-oven-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_MWOCTRL_2_3.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-microwave-oven-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-microwave-oven-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_MWOCTRL_2_4.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-microwave-oven-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-microwave-oven-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_MWOM_1_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCRUNM_1_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --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 --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCRUNM_2_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto --int-arg PIXIT.RVCRUNM.MODE_CHANGE_OK:0 PIXIT.RVCRUNM.MODE_CHANGE_FAIL:2"' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCRUNM_2_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto --int-arg PIXIT.RVCRUNM.MODE_A:1 PIXIT.RVCRUNM.MODE_B:2"' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCCLEANM_1_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --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 --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCCLEANM_2_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto --int-arg PIXIT.RVCCLEANM.MODE_CHANGE_FAIL:1 PIXIT.RVCCLEANM.MODE_CHANGE_OK:2"' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCCLEANM_2_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --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 --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCOPSTATE_2_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --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 --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCOPSTATE_2_3.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --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 --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCOPSTATE_2_4.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' - name: Uploading core files uses: actions/upload-artifact@v4 if: ${{ failure() && !env.ACT }} diff --git a/.gitmodules b/.gitmodules index 61e34cfafd6e94..06fb7f0e347951 100644 --- a/.gitmodules +++ b/.gitmodules @@ -239,7 +239,7 @@ [submodule "third_party/silabs/gecko_sdk"] path = third_party/silabs/gecko_sdk url = https://github.com/SiliconLabs/gecko_sdk.git - branch = v4.4.0 + branch = v4.4.1 platforms = silabs [submodule "third_party/silabs/wiseconnect-wifi-bt-sdk"] path = third_party/silabs/wiseconnect-wifi-bt-sdk @@ -249,7 +249,7 @@ [submodule "third_party/silabs/wifi_sdk"] path = third_party/silabs/wifi_sdk url = https://github.com/SiliconLabs/wiseconnect.git - branch = v3.1.1 + branch = v3.1.3 platforms = silabs [submodule "editline"] path = third_party/editline/repo diff --git a/BUILD.gn b/BUILD.gn index 838ea743f348c8..a96f2a2e67265a 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -363,6 +363,10 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") { enable_linux_lit_icd_app_build = enable_default_builds && (host_os == "linux" || host_os == "mac") + # Build the Linux RVC app example. + enable_linux_rvc_app_build = + enable_default_builds && (host_os == "linux" || host_os == "mac") + # Build the cc13x2x7_26x2x7 lock app example. enable_cc13x2x7_26x2x7_lock_app_build = enable_ti_simplelink_builds @@ -744,6 +748,14 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") { extra_build_deps += [ ":genio_shell_app" ] } + if (enable_linux_rvc_app_build) { + group("linux_rvc_app") { + deps = [ "${chip_root}/examples/rvc-app/linux(${standalone_toolchain})" ] + } + + extra_build_deps += [ ":linux_rvc_app" ] + } + group("default") { deps = extra_build_deps + builds } diff --git a/data_model/README.md b/data_model/README.md index 36f38cae0ff1f8..a26b1c4ff65558 100644 --- a/data_model/README.md +++ b/data_model/README.md @@ -17,7 +17,7 @@ update the spec XML files, however this is not done automatically. You will require access to the following tools locally: - `scraper`. A binary copy generally available - [here](https://github.com/csa-data-model/projects/tree/main/DM-Editor/bin/1.2.0/scrape) + [here](https://github.com/csa-data-model/projects/tree/main/DM-Editor/bin/scrape) - Specification repository checkout from https://github.com/CHIP-Specifications/connectedhomeip-spec diff --git a/data_model/clusters/ACL-Cluster.xml b/data_model/clusters/ACL-Cluster.xml index 9ef2f500e96e01..b965eb84234e0d 100644 --- a/data_model/clusters/ACL-Cluster.xml +++ b/data_model/clusters/ACL-Cluster.xml @@ -55,10 +55,13 @@ Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA --> - + + + + @@ -112,25 +115,27 @@ Davis, CA 95616, USA - + + - + - + + - + - + - + @@ -150,12 +155,14 @@ Davis, CA 95616, USA - + + - + + diff --git a/data_model/clusters/AccountLogin.xml b/data_model/clusters/AccountLogin.xml index 91f675eaba693b..db87d05dc74902 100644 --- a/data_model/clusters/AccountLogin.xml +++ b/data_model/clusters/AccountLogin.xml @@ -54,14 +54,20 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> - + + + + + - + @@ -70,14 +76,14 @@ Davis, CA 95616, USA - + - + @@ -86,12 +92,27 @@ Davis, CA 95616, USA - + + + + - + + + + + + + + + + + + + \ No newline at end of file diff --git a/data_model/clusters/AdminCommissioningCluster.xml b/data_model/clusters/AdminCommissioningCluster.xml index b94b25ec5520c2..eea41bc65b6e2c 100644 --- a/data_model/clusters/AdminCommissioningCluster.xml +++ b/data_model/clusters/AdminCommissioningCluster.xml @@ -1,7 +1,5 @@ + + + diff --git a/data_model/clusters/AlarmBase.xml b/data_model/clusters/AlarmBase.xml index 9ba73c14ab6e63..f4ffc6344a8b90 100644 --- a/data_model/clusters/AlarmBase.xml +++ b/data_model/clusters/AlarmBase.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -91,7 +96,7 @@ Davis, CA 95616, USA - + @@ -100,7 +105,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/ApplicationBasic.xml b/data_model/clusters/ApplicationBasic.xml index 086839a2338cfc..fa197a8d1e5cca 100644 --- a/data_model/clusters/ApplicationBasic.xml +++ b/data_model/clusters/ApplicationBasic.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/ApplicationLauncher.xml b/data_model/clusters/ApplicationLauncher.xml index 5d716981a55d38..6b84436e73d42d 100644 --- a/data_model/clusters/ApplicationLauncher.xml +++ b/data_model/clusters/ApplicationLauncher.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -111,7 +116,7 @@ Davis, CA 95616, USA - + @@ -124,7 +129,7 @@ Davis, CA 95616, USA - + @@ -134,7 +139,7 @@ Davis, CA 95616, USA - + @@ -145,7 +150,6 @@ Davis, CA 95616, USA - diff --git a/data_model/clusters/AudioOutput.xml b/data_model/clusters/AudioOutput.xml index 176e75b16c19c9..468ba2750152a6 100644 --- a/data_model/clusters/AudioOutput.xml +++ b/data_model/clusters/AudioOutput.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -111,14 +116,14 @@ Davis, CA 95616, USA - + - + diff --git a/data_model/clusters/BallastConfiguration.xml b/data_model/clusters/BallastConfiguration.xml index 416b8cd7014beb..f25bef22cb4b6c 100644 --- a/data_model/clusters/BallastConfiguration.xml +++ b/data_model/clusters/BallastConfiguration.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -62,6 +64,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/BasicInformationCluster.xml b/data_model/clusters/BasicInformationCluster.xml index 87fa765f65b2f5..82b9283b0d21d6 100644 --- a/data_model/clusters/BasicInformationCluster.xml +++ b/data_model/clusters/BasicInformationCluster.xml @@ -59,8 +59,11 @@ Davis, CA 95616, USA - + + + + @@ -175,50 +178,50 @@ Davis, CA 95616, USA - + - + - + - + - + - + - + - + - + - + - + @@ -226,41 +229,41 @@ Davis, CA 95616, USA - + - + - + - + - + - + - + - + - + - + - + - + @@ -271,11 +274,11 @@ Davis, CA 95616, USA - + - + @@ -293,6 +296,12 @@ Davis, CA 95616, USA + + + + + + diff --git a/data_model/clusters/Binding-Cluster.xml b/data_model/clusters/Binding-Cluster.xml index 95f68f1d6ff995..eca291a7d895ff 100644 --- a/data_model/clusters/Binding-Cluster.xml +++ b/data_model/clusters/Binding-Cluster.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/BooleanState.xml b/data_model/clusters/BooleanState.xml index 5b298075fbaefc..9205310c58f2be 100644 --- a/data_model/clusters/BooleanState.xml +++ b/data_model/clusters/BooleanState.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/BooleanStateConfiguration.xml b/data_model/clusters/BooleanStateConfiguration.xml index 160cb7fadb7a93..dc17f93a7295f0 100644 --- a/data_model/clusters/BooleanStateConfiguration.xml +++ b/data_model/clusters/BooleanStateConfiguration.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -164,7 +169,7 @@ Davis, CA 95616, USA - + @@ -173,7 +178,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/Channel.xml b/data_model/clusters/Channel.xml index 9ace62ca720a53..1809f5262e7166 100644 --- a/data_model/clusters/Channel.xml +++ b/data_model/clusters/Channel.xml @@ -54,11 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> - + + + + + @@ -67,8 +73,28 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + @@ -85,6 +111,17 @@ Davis, CA 95616, USA + + + + + + + + + + + @@ -101,6 +138,22 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + @@ -117,6 +170,132 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -142,7 +321,7 @@ Davis, CA 95616, USA - + @@ -155,7 +334,6 @@ Davis, CA 95616, USA - @@ -170,7 +348,7 @@ Davis, CA 95616, USA - + @@ -180,12 +358,108 @@ Davis, CA 95616, USA - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data_model/clusters/ColorControl.xml b/data_model/clusters/ColorControl.xml index c0b0655261b10b..b913009f852761 100644 --- a/data_model/clusters/ColorControl.xml +++ b/data_model/clusters/ColorControl.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -64,6 +66,9 @@ Davis, CA 95616, USA + + + @@ -123,19 +128,19 @@ Davis, CA 95616, USA - + - + - + - + - + @@ -158,13 +163,13 @@ Davis, CA 95616, USA - + - + - + @@ -356,16 +361,16 @@ Davis, CA 95616, USA - + - + - + - + @@ -434,7 +439,7 @@ Davis, CA 95616, USA - + @@ -449,7 +454,7 @@ Davis, CA 95616, USA - + @@ -460,16 +465,16 @@ Davis, CA 95616, USA - + - + - + - + @@ -489,23 +494,23 @@ Davis, CA 95616, USA - + - + - + - + - + @@ -524,23 +529,23 @@ Davis, CA 95616, USA - + - + - + - + - + @@ -562,7 +567,7 @@ Davis, CA 95616, USA - + @@ -584,23 +589,23 @@ Davis, CA 95616, USA - + - + - + - + - + @@ -619,23 +624,23 @@ Davis, CA 95616, USA - + - + - + - + - + @@ -657,7 +662,7 @@ Davis, CA 95616, USA - + @@ -683,7 +688,7 @@ Davis, CA 95616, USA - + @@ -709,7 +714,7 @@ Davis, CA 95616, USA - + @@ -729,7 +734,7 @@ Davis, CA 95616, USA - + @@ -753,7 +758,7 @@ Davis, CA 95616, USA - + @@ -775,7 +780,7 @@ Davis, CA 95616, USA - + @@ -800,7 +805,7 @@ Davis, CA 95616, USA - + @@ -821,7 +826,7 @@ Davis, CA 95616, USA - + @@ -846,7 +851,7 @@ Davis, CA 95616, USA - + @@ -871,7 +876,7 @@ Davis, CA 95616, USA - + @@ -899,13 +904,13 @@ Davis, CA 95616, USA - + - + - + @@ -914,10 +919,10 @@ Davis, CA 95616, USA - + - + @@ -939,7 +944,7 @@ Davis, CA 95616, USA - + @@ -957,7 +962,7 @@ Davis, CA 95616, USA - + @@ -986,7 +991,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/ContentAppObserver.xml b/data_model/clusters/ContentAppObserver.xml index b426daa5ec3379..184cce14924cda 100644 --- a/data_model/clusters/ContentAppObserver.xml +++ b/data_model/clusters/ContentAppObserver.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -71,7 +76,7 @@ Davis, CA 95616, USA - + @@ -84,7 +89,6 @@ Davis, CA 95616, USA - diff --git a/data_model/clusters/ContentControl.xml b/data_model/clusters/ContentControl.xml index b51bdff9397448..14996a7c28011a 100644 --- a/data_model/clusters/ContentControl.xml +++ b/data_model/clusters/ContentControl.xml @@ -59,6 +59,9 @@ Davis, CA 95616, USA + + + @@ -255,7 +258,7 @@ Davis, CA 95616, USA - + @@ -269,14 +272,13 @@ Davis, CA 95616, USA - + - @@ -285,15 +287,15 @@ Davis, CA 95616, USA - + - + - + @@ -307,7 +309,7 @@ Davis, CA 95616, USA - + @@ -317,19 +319,19 @@ Davis, CA 95616, USA - + - + - + @@ -339,7 +341,7 @@ Davis, CA 95616, USA - + @@ -349,7 +351,7 @@ Davis, CA 95616, USA - + @@ -359,7 +361,7 @@ Davis, CA 95616, USA - + @@ -369,7 +371,7 @@ Davis, CA 95616, USA - + @@ -379,7 +381,7 @@ Davis, CA 95616, USA - + @@ -389,7 +391,7 @@ Davis, CA 95616, USA - + @@ -398,7 +400,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/ContentLauncher.xml b/data_model/clusters/ContentLauncher.xml index 2c310c6f2ccb3d..b8f80de2e51ea7 100644 --- a/data_model/clusters/ContentLauncher.xml +++ b/data_model/clusters/ContentLauncher.xml @@ -54,11 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> - + + + + + @@ -67,6 +73,15 @@ Davis, CA 95616, USA + + + + + + + + + @@ -119,12 +134,21 @@ Davis, CA 95616, USA - + + + + + + + + + + @@ -136,6 +160,16 @@ Davis, CA 95616, USA + + + + + + + + + + @@ -206,6 +240,27 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + @@ -220,6 +275,23 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + @@ -242,7 +314,7 @@ Davis, CA 95616, USA - + @@ -258,8 +330,15 @@ Davis, CA 95616, USA + + + + + + + - + @@ -273,9 +352,11 @@ Davis, CA 95616, USA + + + - diff --git a/data_model/clusters/DemandResponseLoadControl.xml b/data_model/clusters/DemandResponseLoadControl.xml index a5322bfb4f7206..206201b347612c 100644 --- a/data_model/clusters/DemandResponseLoadControl.xml +++ b/data_model/clusters/DemandResponseLoadControl.xml @@ -55,13 +55,16 @@ Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA --> - + + + + @@ -192,6 +195,59 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -222,6 +278,41 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -361,14 +452,14 @@ Davis, CA 95616, USA - + - + @@ -376,14 +467,14 @@ Davis, CA 95616, USA - + - + @@ -394,7 +485,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/Descriptor-Cluster.xml b/data_model/clusters/Descriptor-Cluster.xml index 9944d8a3f6ea4c..1b17fb4fdfdaea 100644 --- a/data_model/clusters/Descriptor-Cluster.xml +++ b/data_model/clusters/Descriptor-Cluster.xml @@ -54,12 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/DeviceEnergyManagement.xml b/data_model/clusters/DeviceEnergyManagement.xml index 21f74a737d52cb..e493c5b332182e 100644 --- a/data_model/clusters/DeviceEnergyManagement.xml +++ b/data_model/clusters/DeviceEnergyManagement.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -61,6 +63,9 @@ Davis, CA 95616, USA + + + + @@ -487,13 +492,13 @@ Davis, CA 95616, USA - + - + @@ -507,7 +512,7 @@ Davis, CA 95616, USA - + @@ -521,13 +526,13 @@ Davis, CA 95616, USA - + - + @@ -545,7 +550,7 @@ Davis, CA 95616, USA - + @@ -560,7 +565,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/DiagnosticLogsCluster.xml b/data_model/clusters/DiagnosticLogsCluster.xml index 14f995ca1855a6..5b67564b18f298 100644 --- a/data_model/clusters/DiagnosticLogsCluster.xml +++ b/data_model/clusters/DiagnosticLogsCluster.xml @@ -1,7 +1,5 @@ - + + + + @@ -138,11 +139,11 @@ Davis, CA 95616, USA - + - + @@ -221,7 +222,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/DishwasherAlarm.xml b/data_model/clusters/DishwasherAlarm.xml index 7fda78ad163116..b3b67e2bffb500 100644 --- a/data_model/clusters/DishwasherAlarm.xml +++ b/data_model/clusters/DishwasherAlarm.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance + 508 Second Street, Suite 206 + Davis, CA 95616, USA + +:xrefstyle: short --> + + + diff --git a/data_model/clusters/DoorLock.xml b/data_model/clusters/DoorLock.xml index 4f84afca85ff1e..6284b973eb63e1 100644 --- a/data_model/clusters/DoorLock.xml +++ b/data_model/clusters/DoorLock.xml @@ -54,8 +54,10 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> - + @@ -64,7 +66,11 @@ Davis, CA 95616, USA + + + + @@ -98,14 +104,19 @@ Davis, CA 95616, USA - - - - - - - - + + + + + + + + + + + + + @@ -119,6 +130,14 @@ Davis, CA 95616, USA + + + + + + + + @@ -201,6 +220,23 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + @@ -334,6 +370,21 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + @@ -482,6 +533,11 @@ Davis, CA 95616, USA + + + + + @@ -1053,9 +1109,84 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -1067,7 +1198,7 @@ Davis, CA 95616, USA - + @@ -1079,11 +1210,11 @@ Davis, CA 95616, USA - + - + @@ -1098,7 +1229,7 @@ Davis, CA 95616, USA - + @@ -1109,7 +1240,6 @@ Davis, CA 95616, USA - @@ -1138,7 +1268,7 @@ Davis, CA 95616, USA - + @@ -1165,7 +1295,7 @@ Davis, CA 95616, USA - + @@ -1181,7 +1311,6 @@ Davis, CA 95616, USA - @@ -1209,7 +1338,7 @@ Davis, CA 95616, USA - + @@ -1225,7 +1354,7 @@ Davis, CA 95616, USA - + @@ -1236,7 +1365,7 @@ Davis, CA 95616, USA - + @@ -1259,7 +1388,7 @@ Davis, CA 95616, USA - + @@ -1279,7 +1408,6 @@ Davis, CA 95616, USA - @@ -1293,7 +1421,7 @@ Davis, CA 95616, USA - + @@ -1326,7 +1454,7 @@ Davis, CA 95616, USA - + @@ -1341,7 +1469,6 @@ Davis, CA 95616, USA - @@ -1377,7 +1504,7 @@ Davis, CA 95616, USA - + @@ -1392,7 +1519,7 @@ Davis, CA 95616, USA - + @@ -1412,7 +1539,7 @@ Davis, CA 95616, USA - + @@ -1427,7 +1554,6 @@ Davis, CA 95616, USA - @@ -1450,7 +1576,7 @@ Davis, CA 95616, USA - + @@ -1465,7 +1591,7 @@ Davis, CA 95616, USA - + @@ -1484,7 +1610,7 @@ Davis, CA 95616, USA - + @@ -1495,7 +1621,6 @@ Davis, CA 95616, USA - @@ -1520,7 +1645,7 @@ Davis, CA 95616, USA - + @@ -1531,7 +1656,7 @@ Davis, CA 95616, USA - + @@ -1553,7 +1678,7 @@ Davis, CA 95616, USA - + @@ -1573,7 +1698,6 @@ Davis, CA 95616, USA - @@ -1587,7 +1711,7 @@ Davis, CA 95616, USA - + @@ -1615,7 +1739,7 @@ Davis, CA 95616, USA - + @@ -1631,7 +1755,6 @@ Davis, CA 95616, USA - @@ -1659,7 +1782,7 @@ Davis, CA 95616, USA - + @@ -1675,7 +1798,7 @@ Davis, CA 95616, USA - + @@ -1686,7 +1809,7 @@ Davis, CA 95616, USA - + @@ -1731,7 +1854,7 @@ Davis, CA 95616, USA - + @@ -1742,7 +1865,6 @@ Davis, CA 95616, USA - @@ -1792,7 +1914,7 @@ Davis, CA 95616, USA - + @@ -1844,7 +1966,7 @@ Davis, CA 95616, USA - + @@ -1885,7 +2007,6 @@ Davis, CA 95616, USA - @@ -1904,7 +2025,7 @@ Davis, CA 95616, USA - + @@ -1914,7 +2035,6 @@ Davis, CA 95616, USA - @@ -1939,8 +2059,15 @@ Davis, CA 95616, USA + + + + + + + - + @@ -1951,7 +2078,7 @@ Davis, CA 95616, USA - + @@ -1965,6 +2092,36 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data_model/clusters/EVSE-Attributes.xml b/data_model/clusters/EVSE-Attributes.xml deleted file mode 100644 index 2d492a27c4c0a1..00000000000000 --- a/data_model/clusters/EVSE-Attributes.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/data_model/clusters/EVSE-Classification.xml b/data_model/clusters/EVSE-Classification.xml deleted file mode 100644 index 22df357be3e9d0..00000000000000 --- a/data_model/clusters/EVSE-Classification.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/data_model/clusters/EVSE-ClusterID.xml b/data_model/clusters/EVSE-ClusterID.xml deleted file mode 100644 index 6f84afeb8d04bc..00000000000000 --- a/data_model/clusters/EVSE-ClusterID.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/data_model/clusters/EVSE-Commands.xml b/data_model/clusters/EVSE-Commands.xml deleted file mode 100644 index 030565e20f8f96..00000000000000 --- a/data_model/clusters/EVSE-Commands.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/data_model/clusters/EVSE-DataTypes.xml b/data_model/clusters/EVSE-DataTypes.xml deleted file mode 100644 index 790d66143c7025..00000000000000 --- a/data_model/clusters/EVSE-DataTypes.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/data_model/clusters/EVSE-Definitions.xml b/data_model/clusters/EVSE-Definitions.xml deleted file mode 100644 index 7ff6135a3d2976..00000000000000 --- a/data_model/clusters/EVSE-Definitions.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/data_model/clusters/EVSE-Dependencies.xml b/data_model/clusters/EVSE-Dependencies.xml deleted file mode 100644 index a87cb67a4623ae..00000000000000 --- a/data_model/clusters/EVSE-Dependencies.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/data_model/clusters/EVSE-Events.xml b/data_model/clusters/EVSE-Events.xml deleted file mode 100644 index 51401775a6fe59..00000000000000 --- a/data_model/clusters/EVSE-Events.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/data_model/clusters/EVSE-Features.xml b/data_model/clusters/EVSE-Features.xml deleted file mode 100644 index a8b48a53b401e9..00000000000000 --- a/data_model/clusters/EVSE-Features.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/data_model/clusters/EVSE-RevisionHistory.xml b/data_model/clusters/EVSE-RevisionHistory.xml deleted file mode 100644 index 89ca30f749e5e1..00000000000000 --- a/data_model/clusters/EVSE-RevisionHistory.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/data_model/clusters/ElectricalEnergyMeasurement.xml b/data_model/clusters/ElectricalEnergyMeasurement.xml index c6bf8e73863c41..98020764397116 100644 --- a/data_model/clusters/ElectricalEnergyMeasurement.xml +++ b/data_model/clusters/ElectricalEnergyMeasurement.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -74,7 +79,59 @@ Davis, CA 95616, USA - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data_model/clusters/ElectricalPowerMeasurement.xml b/data_model/clusters/ElectricalPowerMeasurement.xml index aa5baeaf368cbb..c695e8db031790 100644 --- a/data_model/clusters/ElectricalPowerMeasurement.xml +++ b/data_model/clusters/ElectricalPowerMeasurement.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -95,6 +100,68 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data_model/clusters/EnergyCalendar.xml b/data_model/clusters/EnergyCalendar.xml index a21845d92c47c4..8d3f1b343bb4a7 100644 --- a/data_model/clusters/EnergyCalendar.xml +++ b/data_model/clusters/EnergyCalendar.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: short --> @@ -61,6 +63,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/EnergyEVSE.xml b/data_model/clusters/EnergyEVSE.xml index f59d41807d43e6..fa15692e78896d 100644 --- a/data_model/clusters/EnergyEVSE.xml +++ b/data_model/clusters/EnergyEVSE.xml @@ -54,12 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -395,7 +400,6 @@ Davis, CA 95616, USA - @@ -405,11 +409,11 @@ Davis, CA 95616, USA - + - + @@ -425,7 +429,7 @@ Davis, CA 95616, USA - + @@ -439,11 +443,11 @@ Davis, CA 95616, USA - + - + @@ -454,13 +458,13 @@ Davis, CA 95616, USA - + - + diff --git a/data_model/clusters/EnergyPreference.xml b/data_model/clusters/EnergyPreference.xml index 7156be8eafe025..c3676520ed6d01 100644 --- a/data_model/clusters/EnergyPreference.xml +++ b/data_model/clusters/EnergyPreference.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/EnergyPrice.xml b/data_model/clusters/EnergyPrice.xml index 23072a6a99ead5..1683fe1bbc13cf 100644 --- a/data_model/clusters/EnergyPrice.xml +++ b/data_model/clusters/EnergyPrice.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: short --> @@ -62,6 +64,9 @@ Davis, CA 95616, USA + + + @@ -173,7 +178,7 @@ Davis, CA 95616, USA - + @@ -188,7 +193,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/FanControl.xml b/data_model/clusters/FanControl.xml index acf1d59e54d91e..756a7bd27466b3 100644 --- a/data_model/clusters/FanControl.xml +++ b/data_model/clusters/FanControl.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: short --> @@ -62,6 +64,9 @@ Davis, CA 95616, USA + + + @@ -277,7 +282,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/FlowMeasurement.xml b/data_model/clusters/FlowMeasurement.xml index 66ad022c2c64ef..29f9d9d7ae58f9 100644 --- a/data_model/clusters/FlowMeasurement.xml +++ b/data_model/clusters/FlowMeasurement.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -61,6 +63,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/GeneralCommissioningCluster.xml b/data_model/clusters/GeneralCommissioningCluster.xml index a25cdfc6ac934e..635a6635990654 100644 --- a/data_model/clusters/GeneralCommissioningCluster.xml +++ b/data_model/clusters/GeneralCommissioningCluster.xml @@ -1,7 +1,5 @@ - + + + + @@ -86,21 +89,22 @@ Davis, CA 95616, USA - + - + + - + - + - + - + @@ -117,35 +121,35 @@ Davis, CA 95616, USA - + - + - + - + - + - + - + - + - + @@ -160,13 +164,15 @@ Davis, CA 95616, USA - + + - + + @@ -184,14 +190,14 @@ Davis, CA 95616, USA - + - + @@ -199,20 +205,19 @@ Davis, CA 95616, USA - - + - + @@ -220,7 +225,6 @@ Davis, CA 95616, USA - diff --git a/data_model/clusters/Groups.xml b/data_model/clusters/Groups.xml index 175c9caf26a435..72902e878cbe9f 100644 --- a/data_model/clusters/Groups.xml +++ b/data_model/clusters/Groups.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -62,6 +64,9 @@ Davis, CA 95616, USA + + + @@ -84,7 +89,7 @@ Davis, CA 95616, USA - + @@ -97,7 +102,6 @@ Davis, CA 95616, USA - @@ -108,7 +112,7 @@ Davis, CA 95616, USA - + @@ -117,7 +121,6 @@ Davis, CA 95616, USA - @@ -132,7 +135,7 @@ Davis, CA 95616, USA - + @@ -143,7 +146,6 @@ Davis, CA 95616, USA - @@ -156,7 +158,7 @@ Davis, CA 95616, USA - + @@ -165,7 +167,6 @@ Davis, CA 95616, USA - @@ -176,11 +177,11 @@ Davis, CA 95616, USA - + - + diff --git a/data_model/clusters/ICDManagement.xml b/data_model/clusters/ICDManagement.xml index 3cc6c9bfab4416..2a770a4f97f2b4 100644 --- a/data_model/clusters/ICDManagement.xml +++ b/data_model/clusters/ICDManagement.xml @@ -54,21 +54,41 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +// Update Name --> - + + + + + - + + + + + + + + + + + + + + + @@ -133,9 +153,28 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + - + @@ -156,7 +195,6 @@ Davis, CA 95616, USA - @@ -164,7 +202,7 @@ Davis, CA 95616, USA - + @@ -177,7 +215,7 @@ Davis, CA 95616, USA - + @@ -190,7 +228,6 @@ Davis, CA 95616, USA - diff --git a/data_model/clusters/Identify.xml b/data_model/clusters/Identify.xml index 379e684e51297d..1cdc33aa0df727 100644 --- a/data_model/clusters/Identify.xml +++ b/data_model/clusters/Identify.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -62,6 +64,9 @@ Davis, CA 95616, USA + + + @@ -127,14 +132,14 @@ Davis, CA 95616, USA - + - + diff --git a/data_model/clusters/IlluminanceMeasurement.xml b/data_model/clusters/IlluminanceMeasurement.xml index c9be9fa6879293..c39daa0e6bdc4d 100644 --- a/data_model/clusters/IlluminanceMeasurement.xml +++ b/data_model/clusters/IlluminanceMeasurement.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -61,6 +63,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/KeypadInput.xml b/data_model/clusters/KeypadInput.xml index f0459e6b1bff1a..4cfb509b06d0be 100644 --- a/data_model/clusters/KeypadInput.xml +++ b/data_model/clusters/KeypadInput.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -345,7 +350,7 @@ Davis, CA 95616, USA - + @@ -353,7 +358,6 @@ Davis, CA 95616, USA - diff --git a/data_model/clusters/Label-Cluster-FixedLabel.xml b/data_model/clusters/Label-Cluster-FixedLabelCluster.xml similarity index 96% rename from data_model/clusters/Label-Cluster-FixedLabel.xml rename to data_model/clusters/Label-Cluster-FixedLabelCluster.xml index 558664a5d69f72..e73bfc274a9da4 100644 --- a/data_model/clusters/Label-Cluster-FixedLabel.xml +++ b/data_model/clusters/Label-Cluster-FixedLabelCluster.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/Label-Cluster-Label.xml b/data_model/clusters/Label-Cluster-LabelCluster.xml similarity index 96% rename from data_model/clusters/Label-Cluster-Label.xml rename to data_model/clusters/Label-Cluster-LabelCluster.xml index ee64da775b05cd..f107a0a7b3f12b 100644 --- a/data_model/clusters/Label-Cluster-Label.xml +++ b/data_model/clusters/Label-Cluster-LabelCluster.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/Label-Cluster-UserLabel.xml b/data_model/clusters/Label-Cluster-UserLabelCluster.xml similarity index 96% rename from data_model/clusters/Label-Cluster-UserLabel.xml rename to data_model/clusters/Label-Cluster-UserLabelCluster.xml index bca4b1453f22de..f7e809ab785c00 100644 --- a/data_model/clusters/Label-Cluster-UserLabel.xml +++ b/data_model/clusters/Label-Cluster-UserLabelCluster.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/LaundryDryerControls.xml b/data_model/clusters/LaundryDryerControls.xml index 461f08666093b8..a3f7b911fc9e9c 100644 --- a/data_model/clusters/LaundryDryerControls.xml +++ b/data_model/clusters/LaundryDryerControls.xml @@ -59,6 +59,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/LaundryWasherControls.xml b/data_model/clusters/LaundryWasherControls.xml index 5a9d108ccc1b01..16879842721473 100644 --- a/data_model/clusters/LaundryWasherControls.xml +++ b/data_model/clusters/LaundryWasherControls.xml @@ -59,6 +59,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/LevelControl.xml b/data_model/clusters/LevelControl.xml index 8a348a2dc05cbd..6b2b3cace52ec3 100644 --- a/data_model/clusters/LevelControl.xml +++ b/data_model/clusters/LevelControl.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -65,6 +67,7 @@ Davis, CA 95616, USA + @@ -210,7 +213,7 @@ Davis, CA 95616, USA - + @@ -230,7 +233,7 @@ Davis, CA 95616, USA - + @@ -250,7 +253,7 @@ Davis, CA 95616, USA - + @@ -273,7 +276,7 @@ Davis, CA 95616, USA - + @@ -285,23 +288,23 @@ Davis, CA 95616, USA - + - + - + - + - + diff --git a/data_model/clusters/LocalizationConfiguration.xml b/data_model/clusters/LocalizationConfiguration.xml index b264698b6d5393..f3c2d5b2d7662b 100644 --- a/data_model/clusters/LocalizationConfiguration.xml +++ b/data_model/clusters/LocalizationConfiguration.xml @@ -59,18 +59,25 @@ Davis, CA 95616, USA + + + - + - + - + + + + + \ No newline at end of file diff --git a/data_model/clusters/LocalizationTimeFormat.xml b/data_model/clusters/LocalizationTimeFormat.xml index 204f145f9c8b07..fb8ceea3ee17a8 100644 --- a/data_model/clusters/LocalizationTimeFormat.xml +++ b/data_model/clusters/LocalizationTimeFormat.xml @@ -59,6 +59,9 @@ Davis, CA 95616, USA + + + @@ -132,7 +135,8 @@ Davis, CA 95616, USA - + + diff --git a/data_model/clusters/LocalizationUnit.xml b/data_model/clusters/LocalizationUnit.xml index 24c54638b4ffd7..be7ea6a0aa2d78 100644 --- a/data_model/clusters/LocalizationUnit.xml +++ b/data_model/clusters/LocalizationUnit.xml @@ -59,6 +59,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/LowPower.xml b/data_model/clusters/LowPower.xml index f8ee432eef58a7..4c228d3154dfa1 100644 --- a/data_model/clusters/LowPower.xml +++ b/data_model/clusters/LowPower.xml @@ -54,14 +54,19 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + - + diff --git a/data_model/clusters/MediaInput.xml b/data_model/clusters/MediaInput.xml index 9ca0f351d1f59f..b7d9d2ef017035 100644 --- a/data_model/clusters/MediaInput.xml +++ b/data_model/clusters/MediaInput.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -132,22 +137,22 @@ Davis, CA 95616, USA - + - + - + - + diff --git a/data_model/clusters/MediaPlayback.xml b/data_model/clusters/MediaPlayback.xml index f2cdf5c4a7c851..0a457a446208dd 100644 --- a/data_model/clusters/MediaPlayback.xml +++ b/data_model/clusters/MediaPlayback.xml @@ -54,11 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> - + + + + + @@ -67,8 +73,73 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -118,6 +189,30 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + @@ -172,52 +267,96 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + + + + + + - + + + + + + - + - + @@ -225,7 +364,6 @@ Davis, CA 95616, USA - @@ -235,7 +373,7 @@ Davis, CA 95616, USA - + @@ -244,5 +382,92 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data_model/clusters/Messages.xml b/data_model/clusters/Messages.xml index 9dd223d9a63f46..cea28ac15f54c9 100644 --- a/data_model/clusters/Messages.xml +++ b/data_model/clusters/Messages.xml @@ -55,6 +55,8 @@ Connectivity Standards Alliance + 508 Second Street, Suite 206 + Davis, CA 95616, USA +:xrefstyle: short + Copyright (C) Connectivity Standards Alliance (2021). All rights reserved. This information within this document is the property of the Connectivity Standards Alliance and its use and disclosure are restricted. @@ -91,6 +93,8 @@ are made. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -98,6 +102,9 @@ Davis, CA 95616, USA + + + @@ -245,7 +252,7 @@ Davis, CA 95616, USA - + @@ -275,7 +282,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/MicrowaveOvenControl.xml b/data_model/clusters/MicrowaveOvenControl.xml index c95d713714854f..d7c6f72f740d3d 100644 --- a/data_model/clusters/MicrowaveOvenControl.xml +++ b/data_model/clusters/MicrowaveOvenControl.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -114,7 +119,7 @@ Davis, CA 95616, USA - + @@ -139,7 +144,7 @@ Davis, CA 95616, USA - + @@ -166,7 +171,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/ModeBase.xml b/data_model/clusters/ModeBase.xml index 5774a7fec0c5a5..2a11f85d343b39 100644 --- a/data_model/clusters/ModeBase.xml +++ b/data_model/clusters/ModeBase.xml @@ -61,6 +61,9 @@ Davis, CA 95616, USA + + + @@ -122,7 +125,7 @@ Require at least one standard mode tag. Define reserved ranges for base/derived - + diff --git a/data_model/clusters/ModeSelect.xml b/data_model/clusters/ModeSelect.xml index 19fe502c1fcfe2..a30a5b9bf8eca5 100644 --- a/data_model/clusters/ModeSelect.xml +++ b/data_model/clusters/ModeSelect.xml @@ -60,6 +60,9 @@ Davis, CA 95616, USA + + + @@ -133,7 +136,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/Mode_DeviceEnergyManagement.xml b/data_model/clusters/Mode_DeviceEnergyManagement.xml index 4181b9b60ead42..592c7d4290a342 100644 --- a/data_model/clusters/Mode_DeviceEnergyManagement.xml +++ b/data_model/clusters/Mode_DeviceEnergyManagement.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/Mode_Dishwasher.xml b/data_model/clusters/Mode_Dishwasher.xml index 22d0fab7897696..4ff6e78714f648 100644 --- a/data_model/clusters/Mode_Dishwasher.xml +++ b/data_model/clusters/Mode_Dishwasher.xml @@ -54,12 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/Mode_EVSE.xml b/data_model/clusters/Mode_EVSE.xml index 2a600e3e381325..de88cb3717c8bf 100644 --- a/data_model/clusters/Mode_EVSE.xml +++ b/data_model/clusters/Mode_EVSE.xml @@ -54,10 +54,15 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + \ No newline at end of file diff --git a/data_model/clusters/Mode_LaundryWasher.xml b/data_model/clusters/Mode_LaundryWasher.xml index e89778fa9ea579..c59b2c3fef9051 100644 --- a/data_model/clusters/Mode_LaundryWasher.xml +++ b/data_model/clusters/Mode_LaundryWasher.xml @@ -54,12 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/Mode_MicrowaveOven.xml b/data_model/clusters/Mode_MicrowaveOven.xml index cd98c189c12844..6e8a129444b9fd 100644 --- a/data_model/clusters/Mode_MicrowaveOven.xml +++ b/data_model/clusters/Mode_MicrowaveOven.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -75,12 +80,10 @@ Davis, CA 95616, USA - - + - - + diff --git a/data_model/clusters/Mode_Oven.xml b/data_model/clusters/Mode_Oven.xml index 56a369dd425572..f6c7111bb844cd 100644 --- a/data_model/clusters/Mode_Oven.xml +++ b/data_model/clusters/Mode_Oven.xml @@ -54,10 +54,15 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + \ No newline at end of file diff --git a/data_model/clusters/Mode_RVCClean.xml b/data_model/clusters/Mode_RVCClean.xml index 64118517a03c1b..d1b2272fc7e756 100644 --- a/data_model/clusters/Mode_RVCClean.xml +++ b/data_model/clusters/Mode_RVCClean.xml @@ -54,12 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/Mode_RVCRun.xml b/data_model/clusters/Mode_RVCRun.xml index 8f49741f7cfeb8..8e19b45a8385fc 100644 --- a/data_model/clusters/Mode_RVCRun.xml +++ b/data_model/clusters/Mode_RVCRun.xml @@ -54,12 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/Mode_Refrigerator.xml b/data_model/clusters/Mode_Refrigerator.xml index cf6a65721e0efd..d51e30b68d1320 100644 --- a/data_model/clusters/Mode_Refrigerator.xml +++ b/data_model/clusters/Mode_Refrigerator.xml @@ -54,12 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + diff --git a/data_model/clusters/Mode_WaterHeater.xml b/data_model/clusters/Mode_WaterHeater.xml index 69fba08b940293..56f1a1e9a66951 100644 --- a/data_model/clusters/Mode_WaterHeater.xml +++ b/data_model/clusters/Mode_WaterHeater.xml @@ -54,10 +54,15 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + \ No newline at end of file diff --git a/data_model/clusters/NetworkCommissioningCluster.xml b/data_model/clusters/NetworkCommissioningCluster.xml index 0153146c149d26..86c7a01ce9f951 100644 --- a/data_model/clusters/NetworkCommissioningCluster.xml +++ b/data_model/clusters/NetworkCommissioningCluster.xml @@ -1,7 +1,5 @@ - + + + + @@ -73,6 +76,11 @@ Davis, CA 95616, USA + + + + + @@ -169,15 +177,34 @@ Davis, CA 95616, USA + + + - + - + + + + + + + + + + + + + + + + + @@ -191,11 +218,11 @@ Davis, CA 95616, USA - + - + @@ -229,17 +256,17 @@ Davis, CA 95616, USA - + - + - + - + @@ -265,10 +292,11 @@ Davis, CA 95616, USA - + + - + @@ -302,24 +330,25 @@ Davis, CA 95616, USA - + - + - + + - + @@ -337,7 +366,7 @@ Davis, CA 95616, USA - + @@ -345,19 +374,18 @@ Davis, CA 95616, USA - + - + - @@ -368,54 +396,68 @@ Davis, CA 95616, USA - + - + - + + - + + - + - + - + - + - + + + + + + + + + + + + + - + - + - + - + @@ -423,16 +465,15 @@ Davis, CA 95616, USA - + - + - @@ -443,16 +484,28 @@ Davis, CA 95616, USA - + - + - + + + + + + + + + + + + + - + @@ -460,16 +513,15 @@ Davis, CA 95616, USA - + - + - @@ -479,7 +531,7 @@ Davis, CA 95616, USA - + @@ -487,7 +539,7 @@ Davis, CA 95616, USA - + @@ -495,9 +547,9 @@ Davis, CA 95616, USA - + - + @@ -507,5 +559,32 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/data_model/clusters/NetworkIdentityManagement.xml b/data_model/clusters/NetworkIdentityManagement.xml index 08bee6af5871ff..8769b68583e4b9 100644 --- a/data_model/clusters/NetworkIdentityManagement.xml +++ b/data_model/clusters/NetworkIdentityManagement.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -119,7 +124,7 @@ Davis, CA 95616, USA - + @@ -130,7 +135,7 @@ Davis, CA 95616, USA - + @@ -141,7 +146,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/OTAProvider.xml b/data_model/clusters/OTAProvider.xml index 73157662cd6f6e..baf3996d3b911f 100644 --- a/data_model/clusters/OTAProvider.xml +++ b/data_model/clusters/OTAProvider.xml @@ -1,7 +1,5 @@ @@ -62,6 +64,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/OnOff.xml b/data_model/clusters/OnOff.xml index 0d64837ea57fbb..0b1e32af50cddb 100644 --- a/data_model/clusters/OnOff.xml +++ b/data_model/clusters/OnOff.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -64,6 +66,9 @@ Davis, CA 95616, USA + + + @@ -171,11 +176,11 @@ Davis, CA 95616, USA - + - + @@ -183,7 +188,7 @@ Davis, CA 95616, USA - + @@ -191,7 +196,7 @@ Davis, CA 95616, USA - + @@ -205,13 +210,13 @@ Davis, CA 95616, USA - + - + diff --git a/data_model/clusters/OperationalCredentialCluster.xml b/data_model/clusters/OperationalCredentialCluster.xml index ec523ba33671d1..1a2becd5c478a2 100644 --- a/data_model/clusters/OperationalCredentialCluster.xml +++ b/data_model/clusters/OperationalCredentialCluster.xml @@ -1,7 +1,5 @@ - + + + + @@ -98,10 +99,10 @@ Davis, CA 95616, USA - + - + @@ -115,11 +116,11 @@ Davis, CA 95616, USA - + - + - + @@ -136,32 +137,34 @@ Davis, CA 95616, USA - + - + - + - + - + + - + - + + - + @@ -175,10 +178,14 @@ Davis, CA 95616, USA - + + + + + @@ -186,7 +193,7 @@ Davis, CA 95616, USA - + @@ -195,7 +202,6 @@ Davis, CA 95616, USA - @@ -206,7 +212,7 @@ Davis, CA 95616, USA - + @@ -215,14 +221,13 @@ Davis, CA 95616, USA - - + @@ -234,7 +239,6 @@ Davis, CA 95616, USA - @@ -245,29 +249,29 @@ Davis, CA 95616, USA - + - + - + - + - + - + - + - + - + @@ -280,7 +284,6 @@ Davis, CA 95616, USA - @@ -294,7 +297,7 @@ Davis, CA 95616, USA - + @@ -302,7 +305,7 @@ Davis, CA 95616, USA - + @@ -310,12 +313,12 @@ Davis, CA 95616, USA - + - + - + diff --git a/data_model/clusters/OperationalState.xml b/data_model/clusters/OperationalState.xml index dcb5753b2c1998..0062b38b4b3981 100644 --- a/data_model/clusters/OperationalState.xml +++ b/data_model/clusters/OperationalState.xml @@ -60,6 +60,9 @@ Davis, CA 95616, USA + + + @@ -143,6 +146,53 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data_model/clusters/OperationalState_Oven.xml b/data_model/clusters/OperationalState_Oven.xml index 947e93f8ec2348..c44ac37b7ccac9 100644 --- a/data_model/clusters/OperationalState_Oven.xml +++ b/data_model/clusters/OperationalState_Oven.xml @@ -54,10 +54,15 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance + 508 Second Street, Suite 206 + Davis, CA 95616, USA + +:xrefstyle: basic --> + + + \ No newline at end of file diff --git a/data_model/clusters/OperationalState_RVC.xml b/data_model/clusters/OperationalState_RVC.xml index bc4e5505e45d6d..6426e2639a7b83 100644 --- a/data_model/clusters/OperationalState_RVC.xml +++ b/data_model/clusters/OperationalState_RVC.xml @@ -54,32 +54,29 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance + 508 Second Street, Suite 206 + Davis, CA 95616, USA + +:xrefstyle: basic --> + + + - - - - - + + - - + - - - - - - - + + + diff --git a/data_model/clusters/PowerSourceCluster.xml b/data_model/clusters/PowerSourceCluster.xml index 16d6f0ac98cad5..ffd628de6686b8 100644 --- a/data_model/clusters/PowerSourceCluster.xml +++ b/data_model/clusters/PowerSourceCluster.xml @@ -61,6 +61,9 @@ Davis, CA 95616, USA + + + @@ -911,13 +914,13 @@ Davis, CA 95616, USA - + - + @@ -928,12 +931,14 @@ Davis, CA 95616, USA + + - + @@ -944,9 +949,10 @@ Davis, CA 95616, USA + - + @@ -957,13 +963,15 @@ Davis, CA 95616, USA - + + - + - + + - + @@ -971,13 +979,15 @@ Davis, CA 95616, USA - + + - + - + + - + @@ -985,13 +995,15 @@ Davis, CA 95616, USA - + + - + - + + - + diff --git a/data_model/clusters/PowerSourceConfigurationCluster.xml b/data_model/clusters/PowerSourceConfigurationCluster.xml index 5548bf6ad8e6b5..11e3bd47dd9186 100644 --- a/data_model/clusters/PowerSourceConfigurationCluster.xml +++ b/data_model/clusters/PowerSourceConfigurationCluster.xml @@ -59,10 +59,13 @@ Davis, CA 95616, USA + + + - + diff --git a/data_model/clusters/PowerTopology.xml b/data_model/clusters/PowerTopology.xml index c8d90baeeded19..d8c8a50d22a3a6 100644 --- a/data_model/clusters/PowerTopology.xml +++ b/data_model/clusters/PowerTopology.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: short --> + + + diff --git a/data_model/clusters/PressureMeasurement.xml b/data_model/clusters/PressureMeasurement.xml index 70093485639090..d9c4a4584404fe 100644 --- a/data_model/clusters/PressureMeasurement.xml +++ b/data_model/clusters/PressureMeasurement.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -61,6 +63,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/PumpConfigurationControl.xml b/data_model/clusters/PumpConfigurationControl.xml index f3fc98a52cee9e..cfd2971a395ecb 100644 --- a/data_model/clusters/PumpConfigurationControl.xml +++ b/data_model/clusters/PumpConfigurationControl.xml @@ -62,6 +62,9 @@ Davis, CA 95616, USA + + + @@ -169,7 +172,206 @@ Davis, CA 95616, USA - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data_model/clusters/RefrigeratorAlarm.xml b/data_model/clusters/RefrigeratorAlarm.xml index c987c3860a4f52..caad94da1f6fad 100644 --- a/data_model/clusters/RefrigeratorAlarm.xml +++ b/data_model/clusters/RefrigeratorAlarm.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: short --> + + + @@ -73,8 +78,7 @@ Davis, CA 95616, USA - - + diff --git a/data_model/clusters/ResourceMonitoring.xml b/data_model/clusters/ResourceMonitoring.xml index 17fc7554ac41f0..6b0e8f3a203ded 100644 --- a/data_model/clusters/ResourceMonitoring.xml +++ b/data_model/clusters/ResourceMonitoring.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -164,7 +166,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/Scenes.xml b/data_model/clusters/Scenes.xml index 0c4347c4e8be8a..5d9be300d1abbc 100644 --- a/data_model/clusters/Scenes.xml +++ b/data_model/clusters/Scenes.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -116,17 +121,14 @@ Davis, CA 95616, USA - - - @@ -177,7 +179,7 @@ Davis, CA 95616, USA - + @@ -189,7 +191,7 @@ Davis, CA 95616, USA - + @@ -202,7 +204,6 @@ Davis, CA 95616, USA - @@ -216,7 +217,7 @@ Davis, CA 95616, USA - + @@ -228,7 +229,6 @@ Davis, CA 95616, USA - @@ -242,7 +242,7 @@ Davis, CA 95616, USA - + @@ -251,7 +251,7 @@ Davis, CA 95616, USA - + @@ -263,7 +263,6 @@ Davis, CA 95616, USA - @@ -277,7 +276,7 @@ Davis, CA 95616, USA - + @@ -285,7 +284,6 @@ Davis, CA 95616, USA - @@ -295,7 +293,7 @@ Davis, CA 95616, USA - + @@ -307,7 +305,6 @@ Davis, CA 95616, USA - @@ -321,7 +318,7 @@ Davis, CA 95616, USA - + @@ -337,7 +334,7 @@ Davis, CA 95616, USA - + @@ -345,7 +342,6 @@ Davis, CA 95616, USA - @@ -362,7 +358,7 @@ Davis, CA 95616, USA - + @@ -383,9 +379,8 @@ Davis, CA 95616, USA - - + diff --git a/data_model/clusters/SmokeCOAlarm.xml b/data_model/clusters/SmokeCOAlarm.xml index 0db5c78f4e947f..d3d35f13f15f25 100644 --- a/data_model/clusters/SmokeCOAlarm.xml +++ b/data_model/clusters/SmokeCOAlarm.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -226,7 +231,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/Switch.xml b/data_model/clusters/Switch.xml index 30602c35bf794f..e7170049ac051f 100644 --- a/data_model/clusters/Switch.xml +++ b/data_model/clusters/Switch.xml @@ -59,6 +59,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/TargetNavigator.xml b/data_model/clusters/TargetNavigator.xml index 343f1427176e41..cfb3a0c17a6f99 100644 --- a/data_model/clusters/TargetNavigator.xml +++ b/data_model/clusters/TargetNavigator.xml @@ -54,11 +54,17 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> - + + + + + @@ -95,7 +101,7 @@ Davis, CA 95616, USA - + @@ -106,7 +112,6 @@ Davis, CA 95616, USA - @@ -116,4 +121,22 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data_model/clusters/TemperatureControl.xml b/data_model/clusters/TemperatureControl.xml index f457238bab1d8a..70fc100d83bbab 100644 --- a/data_model/clusters/TemperatureControl.xml +++ b/data_model/clusters/TemperatureControl.xml @@ -59,6 +59,9 @@ Davis, CA 95616, USA + + + @@ -73,9 +76,58 @@ Davis, CA 95616, USA - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/data_model/clusters/TemperatureMeasurement.xml b/data_model/clusters/TemperatureMeasurement.xml index e1603fd3358bc3..540af82bcedd18 100644 --- a/data_model/clusters/TemperatureMeasurement.xml +++ b/data_model/clusters/TemperatureMeasurement.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -62,6 +64,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/Thermostat.xml b/data_model/clusters/Thermostat.xml index 400d55a048a116..756e27940c2cba 100644 --- a/data_model/clusters/Thermostat.xml +++ b/data_model/clusters/Thermostat.xml @@ -55,7 +55,7 @@ Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA --> - + @@ -63,7 +63,11 @@ Davis, CA 95616, USA + + + + @@ -102,6 +106,17 @@ Davis, CA 95616, USA + + + + + + + + + + + @@ -212,13 +227,36 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + - + + + + @@ -297,7 +335,7 @@ Davis, CA 95616, USA - + @@ -372,6 +410,14 @@ Davis, CA 95616, USA + + + + + + + + @@ -451,6 +497,149 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -823,9 +1012,110 @@ Davis, CA 95616, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -837,7 +1127,6 @@ Davis, CA 95616, USA - @@ -858,7 +1147,7 @@ Davis, CA 95616, USA - + @@ -881,9 +1170,8 @@ Davis, CA 95616, USA - - + @@ -909,7 +1197,7 @@ Davis, CA 95616, USA - + @@ -923,17 +1211,79 @@ Davis, CA 95616, USA - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data_model/clusters/ThermostatUserInterfaceConfiguration.xml b/data_model/clusters/ThermostatUserInterfaceConfiguration.xml index 6c8d1d920e6ef7..63fdba001c67a9 100644 --- a/data_model/clusters/ThermostatUserInterfaceConfiguration.xml +++ b/data_model/clusters/ThermostatUserInterfaceConfiguration.xml @@ -60,6 +60,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/ThreadBorderRouterDiagnostics.xml b/data_model/clusters/ThreadBorderRouterDiagnostics.xml index 29b5da9b8511f0..5527c486a0cc51 100644 --- a/data_model/clusters/ThreadBorderRouterDiagnostics.xml +++ b/data_model/clusters/ThreadBorderRouterDiagnostics.xml @@ -54,19 +54,23 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + - + - @@ -75,12 +79,11 @@ Davis, CA 95616, USA - + - diff --git a/data_model/clusters/TimeSync.xml b/data_model/clusters/TimeSync.xml index 096e0ff2798261..99ec173bc7e6e1 100644 --- a/data_model/clusters/TimeSync.xml +++ b/data_model/clusters/TimeSync.xml @@ -1,7 +1,5 @@ + + + @@ -112,19 +116,19 @@ Davis, CA 95616, USA - + - + - + - + @@ -133,22 +137,22 @@ Davis, CA 95616, USA - + - + - + - + - + - + @@ -178,9 +182,9 @@ Davis, CA 95616, USA - + - + @@ -192,10 +196,6 @@ Davis, CA 95616, USA - - - - \ No newline at end of file diff --git a/data_model/clusters/Timer.xml b/data_model/clusters/Timer.xml deleted file mode 100644 index ad0d864f016e92..00000000000000 --- a/data_model/clusters/Timer.xml +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/data_model/clusters/ValveConfigurationControl.xml b/data_model/clusters/ValveConfigurationControl.xml index 32620ad9cce97d..548fed7d7357c2 100644 --- a/data_model/clusters/ValveConfigurationControl.xml +++ b/data_model/clusters/ValveConfigurationControl.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -171,7 +176,7 @@ Davis, CA 95616, USA - + @@ -186,7 +191,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/WakeOnLAN.xml b/data_model/clusters/WakeOnLAN.xml index 799c92a03fd9b8..deb5af5a75ac7d 100644 --- a/data_model/clusters/WakeOnLAN.xml +++ b/data_model/clusters/WakeOnLAN.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> - + + + + diff --git a/data_model/clusters/WaterContentMeasurement.xml b/data_model/clusters/WaterContentMeasurement.xml index 8b1ff6a9a049bc..85d44793c93ae4 100644 --- a/data_model/clusters/WaterContentMeasurement.xml +++ b/data_model/clusters/WaterContentMeasurement.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -61,6 +63,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/WaterHeaterManagement.xml b/data_model/clusters/WaterHeaterManagement.xml index 073da0094b0b4b..4b6368555bf1d6 100644 --- a/data_model/clusters/WaterHeaterManagement.xml +++ b/data_model/clusters/WaterHeaterManagement.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> + + + @@ -129,7 +134,7 @@ Davis, CA 95616, USA - + @@ -151,7 +156,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/WiFiNetworkManagement.xml b/data_model/clusters/WiFiNetworkManagement.xml index 6308eca7e4b184..fbb7a84a4e17b2 100644 --- a/data_model/clusters/WiFiNetworkManagement.xml +++ b/data_model/clusters/WiFiNetworkManagement.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> - + + + + @@ -69,12 +74,11 @@ Davis, CA 95616, USA - + - diff --git a/data_model/clusters/WindowCovering.xml b/data_model/clusters/WindowCovering.xml index 3ee6d43ded8bce..7b0afd461fcb96 100644 --- a/data_model/clusters/WindowCovering.xml +++ b/data_model/clusters/WindowCovering.xml @@ -54,6 +54,8 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:xrefstyle: basic --> @@ -63,6 +65,9 @@ Davis, CA 95616, USA + + + @@ -608,19 +613,19 @@ Davis, CA 95616, USA - + - + - + - + @@ -633,7 +638,7 @@ Davis, CA 95616, USA - + @@ -655,7 +660,7 @@ Davis, CA 95616, USA - + @@ -668,7 +673,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/bridge-clusters-Actions.xml b/data_model/clusters/bridge-clusters-ActionsCluster.xml similarity index 87% rename from data_model/clusters/bridge-clusters-Actions.xml rename to data_model/clusters/bridge-clusters-ActionsCluster.xml index 51f7ee79bb4bad..e02b12e43d64a4 100644 --- a/data_model/clusters/bridge-clusters-Actions.xml +++ b/data_model/clusters/bridge-clusters-ActionsCluster.xml @@ -54,11 +54,16 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:sectnums: --> + + + @@ -159,7 +164,7 @@ Davis, CA 95616, USA - + @@ -181,7 +186,7 @@ Davis, CA 95616, USA - + @@ -189,32 +194,35 @@ Davis, CA 95616, USA - + + - + - + + - + - + + - + - + - + - + @@ -223,7 +231,7 @@ Davis, CA 95616, USA - + @@ -235,7 +243,7 @@ Davis, CA 95616, USA - + @@ -244,7 +252,7 @@ Davis, CA 95616, USA - + @@ -256,7 +264,7 @@ Davis, CA 95616, USA - + @@ -265,7 +273,7 @@ Davis, CA 95616, USA - + @@ -274,7 +282,7 @@ Davis, CA 95616, USA - + @@ -286,7 +294,7 @@ Davis, CA 95616, USA - + @@ -295,7 +303,7 @@ Davis, CA 95616, USA - + @@ -304,7 +312,7 @@ Davis, CA 95616, USA - + @@ -316,7 +324,7 @@ Davis, CA 95616, USA - + @@ -325,7 +333,7 @@ Davis, CA 95616, USA - + diff --git a/data_model/clusters/bridge-clusters-BridgedDeviceBasicInformation.xml b/data_model/clusters/bridge-clusters-BridgedDeviceBasicInformationCluster.xml similarity index 95% rename from data_model/clusters/bridge-clusters-BridgedDeviceBasicInformation.xml rename to data_model/clusters/bridge-clusters-BridgedDeviceBasicInformationCluster.xml index 5c4bd86b9ab7e4..1dd336ef3656a3 100644 --- a/data_model/clusters/bridge-clusters-BridgedDeviceBasicInformation.xml +++ b/data_model/clusters/bridge-clusters-BridgedDeviceBasicInformationCluster.xml @@ -54,13 +54,18 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:sectnums: --> - + + + + @@ -129,6 +134,9 @@ Davis, CA 95616, USA + + + diff --git a/data_model/clusters/energy_management.xml b/data_model/clusters/energy_management.xml index 792560796cdd4d..93858d1d1b3c89 100644 --- a/data_model/clusters/energy_management.xml +++ b/data_model/clusters/energy_management.xml @@ -54,5 +54,7 @@ This notice and disclaimer must be included on all copies of this document. Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA + +:toc: --> \ No newline at end of file diff --git a/data_model/clusters/network_infrastructure.xml b/data_model/clusters/network_infrastructure.xml index 181ee350003454..7e75cc0af8229f 100644 --- a/data_model/clusters/network_infrastructure.xml +++ b/data_model/clusters/network_infrastructure.xml @@ -59,4 +59,4 @@ Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA --> - \ No newline at end of file + diff --git a/data_model/device_types/BaseDeviceType.xml b/data_model/device_types/BaseDeviceType.xml index a92816ac49d6e1..22cec956aa6061 100644 --- a/data_model/device_types/BaseDeviceType.xml +++ b/data_model/device_types/BaseDeviceType.xml @@ -62,23 +62,4 @@ Davis, CA 95616, USA - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/data_model/device_types/Cooktop.xml b/data_model/device_types/Cooktop.xml index 233c72ed37590a..ea94653008d25a 100644 --- a/data_model/device_types/Cooktop.xml +++ b/data_model/device_types/Cooktop.xml @@ -71,9 +71,6 @@ Davis, CA 95616, USA - - - diff --git a/data_model/clusters/Mode_Laundry.xml b/data_model/device_types/DeviceEnergyManagement.xml similarity index 73% rename from data_model/clusters/Mode_Laundry.xml rename to data_model/device_types/DeviceEnergyManagement.xml index 63108a01aa876b..9d993a9454ea15 100644 --- a/data_model/clusters/Mode_Laundry.xml +++ b/data_model/device_types/DeviceEnergyManagement.xml @@ -55,38 +55,17 @@ Connectivity Standards Alliance 508 Second Street, Suite 206 Davis, CA 95616, USA --> - + - - + - - - - - - - - - - - - - - - - - + + + - - + + - - - - - - - - - \ No newline at end of file + + + \ No newline at end of file diff --git a/data_model/device_types/EVSE.xml b/data_model/device_types/EVSE.xml index f15b1db770b454..9e6ce7be28f301 100644 --- a/data_model/device_types/EVSE.xml +++ b/data_model/device_types/EVSE.xml @@ -65,28 +65,6 @@ Davis, CA 95616, USA - - - - - - - - - - - - - - - - - - - - - - diff --git a/data_model/device_types/Thermostat.xml b/data_model/device_types/Thermostat.xml index fc154468e97c5f..cbdedb7c039ed5 100644 --- a/data_model/device_types/Thermostat.xml +++ b/data_model/device_types/Thermostat.xml @@ -82,13 +82,13 @@ Davis, CA 95616, USA - + - + diff --git a/data_model/scraper_version b/data_model/scraper_version index 0495c4a88caed0..e8ea05db81420d 100644 --- a/data_model/scraper_version +++ b/data_model/scraper_version @@ -1 +1 @@ -1.2.3 +1.2.4 diff --git a/data_model/spec_sha b/data_model/spec_sha index ec683a1872fc3e..97f7f06deb9fe9 100644 --- a/data_model/spec_sha +++ b/data_model/spec_sha @@ -1 +1 @@ -72ce960f71810d6ca96125aea54e4fb0a9631e34 +b0310bae0264a29665f23a8f3d4dc4f742be6075 diff --git a/docs/guides/README.md b/docs/guides/README.md index 30356c72273747..4f4ddb231f577b 100644 --- a/docs/guides/README.md +++ b/docs/guides/README.md @@ -34,7 +34,6 @@ ## Development Guides - [Access Control](./access-control-guide.md) -- [IP Commissioning](./ip_commissioning.md) ## Setup Guides diff --git a/docs/guides/index.md b/docs/guides/index.md index 8813376f7e3e81..2a5d3a64f5afe7 100644 --- a/docs/guides/index.md +++ b/docs/guides/index.md @@ -55,7 +55,6 @@ ti/ti_platform_overview ## Development Guides - [Access Control](./access-control-guide.md) -- [IP Commissioning](./ip_commissioning.md) - [Matter IDL tooling and validation](./matter_idl_tooling.md) ## Setup Guides diff --git a/docs/guides/ip_commissioning.md b/docs/guides/ip_commissioning.md deleted file mode 100644 index d1e44d087be435..00000000000000 --- a/docs/guides/ip_commissioning.md +++ /dev/null @@ -1,82 +0,0 @@ -# IP commissioning - -## Devices - -### ESP32 (M5 stack) - all-clusters-app - -The M5 doesn’t have an ethernet port, but we can simulate IP connection by -giving the device wifi credentials. The device will start up advertising as a -commissionable device. - -Compile the device image as follows - -``` -Demo->Device Type = -Component config-> Chip Device Layer -> WiFi Station Options - set up ssid and password -``` - -### linux builds - -```bash -gn gen out/debug -ninja -C out/debug -``` - -These devices start in commissioning mode if they do not have stored Matter -credentials. Linux devices store credentials in the /tmp directory, so to -re-commission the device from scratch, remove the chip\_\* files from /tmp. - -## Controller - -### chip-device-ctrl - -There are two ways to connect via IP: - -**Discover then connect ip** - -``` -discover -all -``` - -or - -``` -discover -qr “[qrcode]” -``` - -then - -``` -connect -ip
[] -``` - -It is no longer necessary to run resolve after connect - this is done as part of -the commissioning process - -**Connect using the QR code** - -``` -connect -qr “[qr code]” -``` - -This will discover, connect over IP with the code from the QR and resolve. - -### chip-tool - -You can connect using chip-tool either using the setup codes or by discovering -the device on the network using one of the mDNS sub types. To get a list of the -available options run - -``` -chip-tool pairing -``` - -For example, to discover, connect and commission using the long discriminator - -``` -chip-tool pairing onnetwork-long -``` - -where the node id is set to a value of your choice (used to id devices for -future communication), and the setup pin code and long discriminator are set by -the device and are normally logged at startup. diff --git a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter index a801aac5943356..caedd98bf1be48 100644 --- a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter +++ b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter @@ -1595,7 +1595,7 @@ cluster Thermostat = 513 { } /** An interface for controlling a fan in a heating/cooling system. */ -provisional cluster FanControl = 514 { +cluster FanControl = 514 { revision 4; enum AirflowDirectionEnum : enum8 { diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index ebb9b3da83929b..62dc0d7d84c3fa 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -4455,6 +4455,27 @@ provisional cluster EnergyEvse = 153 { timed command ClearTargets(): DefaultSuccess = 7; } +/** The Power Topology Cluster provides a mechanism for expressing how power is flowing between endpoints. */ +provisional cluster PowerTopology = 156 { + revision 1; + + bitmap Feature : bitmap32 { + kNodeTopology = 0x1; + kTreeTopology = 0x2; + kSetTopology = 0x4; + kDynamicPowerFlow = 0x8; + } + + readonly attribute optional endpoint_no availableEndpoints[] = 0; + readonly attribute optional endpoint_no activeEndpoints[] = 1; + 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; +} + /** Attributes and commands for selecting a mode from a list of supported options. */ provisional cluster EnergyEvseMode = 157 { revision 1; @@ -5247,7 +5268,7 @@ cluster Thermostat = 513 { } /** An interface for controlling a fan in a heating/cooling system. */ -provisional cluster FanControl = 514 { +cluster FanControl = 514 { revision 4; enum AirflowDirectionEnum : enum8 { @@ -8340,6 +8361,17 @@ endpoint 1 { handle command ClearTargets; } + server cluster PowerTopology { + callback attribute availableEndpoints; + callback attribute activeEndpoints; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + } + server cluster EnergyEvseMode { callback attribute supportedModes; callback attribute currentMode; diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index 1666cef4adc1b8..0a2a3faf1b37e8 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -14240,6 +14240,144 @@ } ] }, + { + "name": "Power Topology", + "code": 156, + "mfgCode": null, + "define": "POWER_TOPOLOGY_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "AvailableEndpoints", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveEndpoints", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Energy EVSE Mode", "code": 157, diff --git a/examples/all-clusters-app/all-clusters-common/src/power-topology-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/power-topology-stub.cpp new file mode 100644 index 00000000000000..af2042bd58504d --- /dev/null +++ b/examples/all-clusters-app/all-clusters-common/src/power-topology-stub.cpp @@ -0,0 +1,72 @@ +/* + * + * 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 + +using namespace chip; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::PowerTopology; + +namespace chip { +namespace app { +namespace Clusters { +namespace PowerTopology { + +class PowerTopologyDelegate : public Delegate +{ +public: + ~PowerTopologyDelegate() = default; + + CHIP_ERROR GetAvailableEndpointAtIndex(size_t index, EndpointId & endpointId) override; + CHIP_ERROR GetActiveEndpointAtIndex(size_t index, EndpointId & endpointId) override; +}; + +CHIP_ERROR PowerTopologyDelegate::GetAvailableEndpointAtIndex(size_t index, EndpointId & endpointId) +{ + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; +} + +CHIP_ERROR PowerTopologyDelegate::GetActiveEndpointAtIndex(size_t index, EndpointId & endpointId) +{ + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; +} + +} // namespace PowerTopology +} // namespace Clusters +} // namespace app +} // namespace chip + +static std::unique_ptr gDelegate; +static std::unique_ptr gInstance; + +void emberAfPowerTopologyClusterInitCallback(chip::EndpointId endpointId) +{ + VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1. + VerifyOrDie(!gInstance); + + gDelegate = std::make_unique(); + if (gDelegate) + { + gInstance = std::make_unique( + endpointId, *gDelegate, BitMask(Feature::kSetTopology, Feature::kDynamicPowerFlow), + BitMask(OptionalAttributes::kOptionalAttributeAvailableEndpoints, + OptionalAttributes::kOptionalAttributeActiveEndpoints)); + + gInstance->Init(); + } +} diff --git a/examples/all-clusters-app/esp32/main/CMakeLists.txt b/examples/all-clusters-app/esp32/main/CMakeLists.txt index 641cbca7b55af0..238f0e899c340d 100644 --- a/examples/all-clusters-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-app/esp32/main/CMakeLists.txt @@ -90,6 +90,7 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/pump-configuration-and-control-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/power-source-configuration-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/power-source-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/power-topology-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/resource-monitoring-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/temperature-control-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/time-synchronization-server" diff --git a/examples/all-clusters-app/linux/BUILD.gn b/examples/all-clusters-app/linux/BUILD.gn index b0fdcd4e0af68f..998f98a19cd3de 100644 --- a/examples/all-clusters-app/linux/BUILD.gn +++ b/examples/all-clusters-app/linux/BUILD.gn @@ -48,6 +48,7 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/operational-state-delegate-impl.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-modes.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-operational-state-delegate.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/power-topology-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/resource-monitoring-delegates.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/rvc-modes.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/rvc-operational-state-delegate-impl.cpp", diff --git a/examples/all-clusters-app/tizen/BUILD.gn b/examples/all-clusters-app/tizen/BUILD.gn index 4a60be79bc1e49..364e9ce857d5da 100644 --- a/examples/all-clusters-app/tizen/BUILD.gn +++ b/examples/all-clusters-app/tizen/BUILD.gn @@ -33,6 +33,7 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-modes.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/power-topology-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/resource-monitoring-delegates.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", diff --git a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter index fe32702e2c847d..dbb244cf6265b3 100644 --- a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter +++ b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter @@ -3861,7 +3861,7 @@ cluster Thermostat = 513 { } /** An interface for controlling a fan in a heating/cooling system. */ -provisional cluster FanControl = 514 { +cluster FanControl = 514 { revision 4; enum AirflowDirectionEnum : enum8 { diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt index 0662ec08dc2146..f38cacbd259073 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt @@ -17,6 +17,7 @@ import chip.devicecontroller.model.AttributeWriteRequest import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.NodeState +import chip.devicecontroller.model.Status import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R @@ -191,8 +192,8 @@ class BasicClientFragment : Fragment() { Log.e(TAG, "Write ${attribute.name} failure", ex) } - override fun onResponse(attributePath: ChipAttributePath?) { - showMessage("Write ${attribute.name} success") + override fun onResponse(attributePath: ChipAttributePath, status: Status) { + showMessage("Write ${attribute.name} response: $status") } }, devicePtr, diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OtaProviderClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OtaProviderClientFragment.kt index 87735856fa4844..c27159193ed2dc 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OtaProviderClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OtaProviderClientFragment.kt @@ -32,6 +32,7 @@ import chip.devicecontroller.model.AttributeWriteRequest import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.NodeState +import chip.devicecontroller.model.Status import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R @@ -223,9 +224,9 @@ class OtaProviderClientFragment : Fragment() { showMessage("Error : ${e.toString()}") } - override fun onResponse(attributePath: ChipAttributePath?) { + override fun onResponse(attributePath: ChipAttributePath, status: Status) { Log.d(TAG, "onResponse") - showMessage("write Success") + showMessage("$attributePath : Write response: $status") } }, ChipClient.getConnectedDevicePointer(requireContext(), addressUpdateFragment.deviceId), @@ -350,9 +351,9 @@ class OtaProviderClientFragment : Fragment() { showMessage("error : ${e.toString()}") } - override fun onResponse(attributePath: ChipAttributePath?) { + override fun onResponse(attributePath: ChipAttributePath, status: Status) { Log.d(TAG, "onResponse") - showMessage("write success") + showMessage("$attributePath : Write response: $status") } }, ChipClient.getConnectedDevicePointer(requireContext(), addressUpdateFragment.deviceId), diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt index 1978951e02e210..af119581a7047f 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt @@ -27,6 +27,7 @@ import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.ChipPathId import chip.devicecontroller.model.InvokeElement import chip.devicecontroller.model.NodeState +import chip.devicecontroller.model.Status import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.R import com.google.chip.chiptool.databinding.WildcardFragmentBinding @@ -92,8 +93,8 @@ class WildcardFragment : Fragment() { Log.e(TAG, "Report error for $attributePath: $ex") } - override fun onResponse(attributePath: ChipAttributePath?) { - val text = "$attributePath : Write Success" + override fun onResponse(attributePath: ChipAttributePath, status: Status) { + val text = "$attributePath : Write response: $status" requireActivity().runOnUiThread { binding.outputTv.text = text } } diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterDetailFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterDetailFragment.kt index 50c33bd35c60ba..eb14eee23770bd 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterDetailFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterDetailFragment.kt @@ -199,10 +199,19 @@ class ClusterDetailFragment : Fragment() { private fun castStringToType(data: String, type: Class<*>, underlyingType: Class<*>): Any? { return when (type) { - Int::class.java -> data.toInt() - Boolean::class.java -> data.toBoolean() + Int::class.java, + java.lang.Integer::class.java -> data.toInt() + Boolean::class.java, + java.lang.Boolean::class.java -> data.toBoolean() ByteArray::class.java -> data.encodeToByteArray() - Long::class.java -> data.toLong() + Long::class.java, + java.lang.Long::class.java -> data.toLong() + Short::class.java, + java.lang.Short::class.java -> data.toShort() + Double::class.java, + java.lang.Double::class.java -> data.toDouble() + Float::class.java, + java.lang.Float::class.java -> data.toFloat() Optional::class.java -> if (data.isEmpty()) Optional.empty() else Optional.of(castStringToType(data, underlyingType, underlyingType)!!) diff --git a/examples/chef/chef.py b/examples/chef/chef.py index 688bdfef490761..816840f8584a45 100755 --- a/examples/chef/chef.py +++ b/examples/chef/chef.py @@ -801,6 +801,7 @@ def main() -> int: 'import("${chip_root}/config/standalone/args.gni")', 'chip_shell_cmd_server = false', 'chip_build_libshell = true', + 'chip_enable_openthread = false', 'chip_config_network_layer_ble = false', 'chip_device_project_config_include = ""', 'chip_project_config_include = ""', diff --git a/examples/chef/common/chef-air-quality.h b/examples/chef/common/chef-air-quality.h index 2eaf3ef28fdf66..e7589488d41d74 100644 --- a/examples/chef/common/chef-air-quality.h +++ b/examples/chef/common/chef-air-quality.h @@ -22,10 +22,10 @@ #include #ifdef MATTER_DM_PLUGIN_AIR_QUALITY_SERVER -Protocols::InteractionModel::Status chefAirQualityWriteCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, - const EmberAfAttributeMetadata * attributeMetadata, - uint8_t * buffer); -Protocols::InteractionModel::Status chefAirQualityReadCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, - const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, - uint16_t maxReadLength); +chip::Protocols::InteractionModel::Status chefAirQualityWriteCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, + const EmberAfAttributeMetadata * attributeMetadata, + uint8_t * buffer); +chip::Protocols::InteractionModel::Status chefAirQualityReadCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, + const EmberAfAttributeMetadata * attributeMetadata, + uint8_t * buffer, uint16_t maxReadLength); #endif diff --git a/examples/chef/common/chef-channel-manager.cpp b/examples/chef/common/chef-channel-manager.cpp deleted file mode 100644 index 4a8d6de466d746..00000000000000 --- a/examples/chef/common/chef-channel-manager.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/** - * - * Copyright (c) 2021 Project CHIP Authors - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include - -using ChangeChannelResponseType = chip::app::Clusters::Channel::Commands::ChangeChannelResponse::Type; -using ChannelInfoType = chip::app::Clusters::Channel::Structs::ChannelInfoStruct::Type; -using LineupInfoType = chip::app::Clusters::Channel::Structs::LineupInfoStruct::Type; -// Include Channel Cluster Server callbacks only when the server is enabled -#ifdef MATTER_DM_PLUGIN_CHANNEL_SERVER -#include - -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters::Channel; -using namespace chip::Uint8; - -ChefChannelManager::ChefChannelManager() -{ - ChannelInfoType abc; - abc.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KAAL")); - abc.callSign = MakeOptional(chip::CharSpan::fromCharString("KAAL-TV")); - abc.name = MakeOptional(chip::CharSpan::fromCharString("ABC")); - abc.majorNumber = static_cast(6); - abc.minorNumber = static_cast(0); - mChannels[mTotalChannels++] = abc; - - ChannelInfoType pbs; - pbs.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS")); - pbs.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV")); - pbs.name = MakeOptional(chip::CharSpan::fromCharString("PBS")); - pbs.majorNumber = static_cast(9); - pbs.minorNumber = static_cast(1); - mChannels[mTotalChannels++] = pbs; - - ChannelInfoType pbsKids; - pbsKids.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS")); - pbsKids.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV")); - pbsKids.name = MakeOptional(chip::CharSpan::fromCharString("PBS Kids")); - pbsKids.majorNumber = static_cast(9); - pbsKids.minorNumber = static_cast(2); - mChannels[mTotalChannels++] = pbsKids; - - ChannelInfoType worldChannel; - worldChannel.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS")); - worldChannel.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV")); - worldChannel.name = MakeOptional(chip::CharSpan::fromCharString("World Channel")); - worldChannel.majorNumber = static_cast(9); - worldChannel.minorNumber = static_cast(3); - mChannels[mTotalChannels++] = worldChannel; -} - -static bool isChannelMatched(const ChannelInfoType & channel, const CharSpan & match) -{ - if (channel.name.HasValue() && channel.name.Value().data_equal(match)) - { - return true; - } - - if (channel.affiliateCallSign.HasValue() && channel.affiliateCallSign.Value().data_equal(match)) - { - return true; - } - - if (channel.callSign.HasValue() && channel.callSign.Value().data_equal(match)) - { - return true; - } - - StringBuilder<32> nr; - nr.AddFormat("%d.%d", channel.majorNumber, channel.minorNumber); - return match.data_equal(CharSpan::fromCharString(nr.c_str())); -} - -CHIP_ERROR ChefChannelManager::HandleGetChannelList(app::AttributeValueEncoder & aEncoder) -{ - return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { - int index = 0; - for (auto const & channel : ChefChannelManager().mChannels) - { - ReturnErrorOnFailure(encoder.Encode(channel)); - index++; - if (index >= ChefChannelManager().mTotalChannels) - break; - } - return CHIP_NO_ERROR; - }); -} - -CHIP_ERROR ChefChannelManager::HandleGetLineup(app::AttributeValueEncoder & aEncoder) -{ - LineupInfoType lineup; - lineup.operatorName = chip::CharSpan::fromCharString("Comcast"); - lineup.lineupName = MakeOptional(chip::CharSpan::fromCharString("Comcast King County")); - lineup.postalCode = MakeOptional(chip::CharSpan::fromCharString("98052")); - lineup.lineupInfoType = chip::app::Clusters::Channel::LineupInfoTypeEnum::kMso; - - return aEncoder.Encode(lineup); -} - -CHIP_ERROR ChefChannelManager::HandleGetCurrentChannel(app::AttributeValueEncoder & aEncoder) -{ - return aEncoder.Encode(mChannels[mCurrentChannelIndex]); -} - -void ChefChannelManager::HandleChangeChannel(CommandResponseHelper & helper, - const chip::CharSpan & match) -{ - std::array matchedChannels; - - uint16_t index = 0; - uint16_t totalMatchedChannels = 0; - for (auto const & channel : mChannels) - { - // verify if CharSpan matches channel name - // or callSign or affiliateCallSign or majorNumber.minorNumber - if (isChannelMatched(channel, match)) - { - matchedChannels[totalMatchedChannels++] = (channel); - } - else if (totalMatchedChannels == 0) - { - // "index" is only used when we end up with totalMatchedChannels == 1. - // In that case, we want it to be the number of non-matching channels we saw before - // the matching one. - index++; - } - } - - ChangeChannelResponseType response; - - // Error: Found multiple matches - if (totalMatchedChannels > 1) - { - response.status = chip::app::Clusters::Channel::StatusEnum::kMultipleMatches; - helper.Success(response); - } - else if (totalMatchedChannels == 0) - { - // Error: Found no match - response.status = chip::app::Clusters::Channel::StatusEnum::kNoMatches; - helper.Success(response); - } - else - { - response.status = chip::app::Clusters::Channel::StatusEnum::kSuccess; - response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); - mCurrentChannelIndex = index; - helper.Success(response); - } -} - -bool ChefChannelManager::HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) -{ - bool channelChanged = false; - uint16_t index = 0; - for (auto const & channel : mChannels) - { - - // verify if major & minor matches one of the channel from the list - if (channel.minorNumber == minorNumber && channel.majorNumber == majorNumber) - { - // verify if channel changed by comparing values of current channel with the requested channel - if (channel.minorNumber != mChannels[mCurrentChannelIndex].minorNumber || - channel.majorNumber != mChannels[mCurrentChannelIndex].majorNumber) - { - channelChanged = true; - mCurrentChannelIndex = index; - } - - // return since we've already found the unique matched channel - return channelChanged; - } - index++; - if (index >= mTotalChannels) - break; - } - return channelChanged; -} - -bool ChefChannelManager::HandleSkipChannel(const int16_t & count) -{ - int32_t newChannelIndex = static_cast(count) + static_cast(mCurrentChannelIndex); - uint16_t channelsSize = static_cast(mChannels.size()); - - // handle newChannelIndex out of range. - newChannelIndex = newChannelIndex % channelsSize; - - if (newChannelIndex < 0) - { - newChannelIndex = newChannelIndex + channelsSize; - } - - mCurrentChannelIndex = static_cast(newChannelIndex); - return true; -} - -uint32_t ChefChannelManager::GetFeatureMap(chip::EndpointId endpoint) -{ - if (endpoint > MATTER_DM_CHANNEL_CLUSTER_SERVER_ENDPOINT_COUNT) - { - return 0; - } - - uint32_t featureMap = 0; - Attributes::FeatureMap::Get(endpoint, &featureMap); - return featureMap; -} - -#endif /* MATTER_DM_PLUGIN_CHANNEL_SERVER */ diff --git a/examples/chef/common/chef-channel-manager.h b/examples/chef/common/chef-channel-manager.h deleted file mode 100644 index 53a1db529a9a4a..00000000000000 --- a/examples/chef/common/chef-channel-manager.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright (c) 2021 Project CHIP Authors - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -class ChefChannelManager : public chip::app::Clusters::Channel::Delegate -{ - -public: - ChefChannelManager(); - - CHIP_ERROR HandleGetChannelList(chip::app::AttributeValueEncoder & aEncoder); - CHIP_ERROR HandleGetLineup(chip::app::AttributeValueEncoder & aEncoder); - CHIP_ERROR HandleGetCurrentChannel(chip::app::AttributeValueEncoder & aEncoder); - - void HandleChangeChannel( - chip::app::CommandResponseHelper & helper, - const chip::CharSpan & match); - bool HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber); - bool HandleSkipChannel(const int16_t & count); - - static ChefChannelManager & Instance() - { - static ChefChannelManager instance; - return instance; - } - - // bool HasFeature(chip::EndpointId endpoint, Feature feature); - uint32_t GetFeatureMap(chip::EndpointId endpoint); - - ~ChefChannelManager() = default; - -protected: - static constexpr size_t kMaxChannels = 10; - uint16_t mCurrentChannelIndex{ 0 }; - uint16_t mTotalChannels{ 0 }; - std::array mChannels; -}; diff --git a/examples/chef/common/chef-concentration-measurement.h b/examples/chef/common/chef-concentration-measurement.h index 9b8fc571872c6b..887df7d943ee08 100644 --- a/examples/chef/common/chef-concentration-measurement.h +++ b/examples/chef/common/chef-concentration-measurement.h @@ -31,10 +31,11 @@ defined(MATTER_DM_PLUGIN_PM10_CONCENTRATION_MEASUREMENT_SERVER) || \ defined(MATTER_DM_PLUGIN_TOTAL_VOLATILE_ORGANIC_COMPOUNDS_CONCENTRATION_MEASUREMENT_SERVER) || \ defined(MATTER_DM_PLUGIN_RADON_CONCENTRATION_MEASUREMENT_SERVER) -Protocols::InteractionModel::Status chefConcentrationMeasurementWriteCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, - const EmberAfAttributeMetadata * attributeMetadata, - uint8_t * buffer); -Protocols::InteractionModel::Status chefConcentrationMeasurementReadCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, - const EmberAfAttributeMetadata * attributeMetadata, - uint8_t * buffer, uint16_t maxReadLength); +chip::Protocols::InteractionModel::Status +chefConcentrationMeasurementWriteCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, + const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer); +chip::Protocols::InteractionModel::Status +chefConcentrationMeasurementReadCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, + const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, + uint16_t maxReadLength); #endif diff --git a/examples/chef/common/clusters/audio-output/AudioOutputManager.cpp b/examples/chef/common/clusters/audio-output/AudioOutputManager.cpp new file mode 100644 index 00000000000000..06a123a6549679 --- /dev/null +++ b/examples/chef/common/clusters/audio-output/AudioOutputManager.cpp @@ -0,0 +1,83 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#ifdef MATTER_DM_PLUGIN_AUDIO_OUTPUT_SERVER +#include "AudioOutputManager.h" + +using namespace std; +using namespace chip::app; +using namespace chip::app::Clusters::AudioOutput; +using chip::app::AttributeValueEncoder; + +AudioOutputManager::AudioOutputManager() +{ + struct OutputData outputData1(1, chip::app::Clusters::AudioOutput::OutputTypeEnum::kHdmi, "HDMI 1"); + mOutputs.push_back(outputData1); + struct OutputData outputData2(2, chip::app::Clusters::AudioOutput::OutputTypeEnum::kHdmi, "HDMI 2"); + mOutputs.push_back(outputData2); + struct OutputData outputData3(3, chip::app::Clusters::AudioOutput::OutputTypeEnum::kHdmi, "HDMI 3"); + mOutputs.push_back(outputData3); + + mCurrentOutput = 1; +} + +uint8_t AudioOutputManager::HandleGetCurrentOutput() +{ + return mCurrentOutput; +} + +CHIP_ERROR AudioOutputManager::HandleGetOutputList(AttributeValueEncoder & aEncoder) +{ + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + for (auto const & outputData : mOutputs) + { + ReturnErrorOnFailure(encoder.Encode(outputData.GetEncodable())); + } + return CHIP_NO_ERROR; + }); +} + +bool AudioOutputManager::HandleRenameOutput(const uint8_t & index, const chip::CharSpan & newName) +{ + for (auto & outputData : mOutputs) + { + if (outputData.index == index) + { + outputData.Rename(newName); + return true; + } + } + + return false; +} + +bool AudioOutputManager::HandleSelectOutput(const uint8_t & index) +{ + for (auto & outputData : mOutputs) + { + if (outputData.index == index) + { + mCurrentOutput = index; + return true; + } + } + + return false; +} +#endif // MATTER_DM_PLUGIN_AUDIO_OUTPUT_SERVER diff --git a/examples/chef/common/clusters/audio-output/AudioOutputManager.h b/examples/chef/common/clusters/audio-output/AudioOutputManager.h new file mode 100644 index 00000000000000..5f9157de773ee7 --- /dev/null +++ b/examples/chef/common/clusters/audio-output/AudioOutputManager.h @@ -0,0 +1,58 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +class AudioOutputManager : public chip::app::Clusters::AudioOutput::Delegate +{ + using OutputInfoType = chip::app::Clusters::AudioOutput::Structs::OutputInfoStruct::Type; + +public: + AudioOutputManager(); + + uint8_t HandleGetCurrentOutput() override; + CHIP_ERROR HandleGetOutputList(chip::app::AttributeValueEncoder & aEncoder) override; + bool HandleRenameOutput(const uint8_t & index, const chip::CharSpan & name) override; + bool HandleSelectOutput(const uint8_t & index) override; + + struct OutputData + { + uint8_t index; + chip::app::Clusters::AudioOutput::OutputTypeEnum outputType; + std::string name; + + OutputData(uint8_t i, chip::app::Clusters::AudioOutput::OutputTypeEnum t, const char * n) : index(i), outputType(t), name(n) + {} + void Rename(const chip::CharSpan & newName) { name.assign(newName.data(), newName.size()); } + OutputInfoType GetEncodable() const + { + OutputInfoType result; + result.index = index; + result.outputType = outputType; + result.name = chip::CharSpan::fromCharString(name.c_str()); + return result; + } + }; + +protected: + uint8_t mCurrentOutput = 1; + std::vector mOutputs; +}; diff --git a/examples/chef/common/clusters/channel/ChannelManager.cpp b/examples/chef/common/clusters/channel/ChannelManager.cpp new file mode 100644 index 00000000000000..36df31af6de280 --- /dev/null +++ b/examples/chef/common/clusters/channel/ChannelManager.cpp @@ -0,0 +1,352 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#ifdef MATTER_DM_PLUGIN_CHANNEL_SERVER +#include "ChannelManager.h" +#include +#include + +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters::Channel; +using namespace chip::Uint8; + +ChannelManager::ChannelManager() +{ + ChannelInfoType abc; + abc.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KAAL")); + abc.callSign = MakeOptional(chip::CharSpan::fromCharString("KAAL-TV")); + abc.name = MakeOptional(chip::CharSpan::fromCharString("ABC")); + abc.majorNumber = static_cast(6); + abc.minorNumber = static_cast(0); + mChannels.push_back(abc); + + ChannelInfoType pbs; + pbs.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS")); + pbs.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV")); + pbs.name = MakeOptional(chip::CharSpan::fromCharString("PBS")); + pbs.majorNumber = static_cast(9); + pbs.minorNumber = static_cast(1); + mChannels.push_back(pbs); + + ChannelInfoType pbsKids; + pbsKids.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS")); + pbsKids.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV")); + pbsKids.name = MakeOptional(chip::CharSpan::fromCharString("PBS Kids")); + pbsKids.majorNumber = static_cast(9); + pbsKids.minorNumber = static_cast(2); + mChannels.push_back(pbsKids); + + ChannelInfoType worldChannel; + worldChannel.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS")); + worldChannel.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV")); + worldChannel.name = MakeOptional(chip::CharSpan::fromCharString("World Channel")); + worldChannel.majorNumber = static_cast(9); + worldChannel.minorNumber = static_cast(3); + mChannels.push_back(worldChannel); + + mCurrentChannelIndex = 0; + mCurrentChannel = mChannels[mCurrentChannelIndex]; + + ProgramType program1; + program1.identifier = chip::CharSpan::fromCharString("progid-abc1"); + program1.channel = abc; + program1.title = chip::CharSpan::fromCharString("ABC Title1"); + program1.subtitle = MakeOptional(chip::CharSpan::fromCharString("My Program Subtitle1")); + program1.startTime = 0; + program1.endTime = 30 * 60; + + mPrograms.push_back(program1); + + ProgramType program_pbs1; + program_pbs1.identifier = chip::CharSpan::fromCharString("progid-pbs1"); + program_pbs1.channel = pbs; + program_pbs1.title = chip::CharSpan::fromCharString("PBS Title1"); + program_pbs1.subtitle = MakeOptional(chip::CharSpan::fromCharString("My Program Subtitle1")); + program_pbs1.startTime = 0; + program_pbs1.endTime = 30 * 60; + + mPrograms.push_back(program_pbs1); + + ProgramType program2; + program2.identifier = chip::CharSpan::fromCharString("progid-abc2"); + program2.channel = abc; + program2.title = chip::CharSpan::fromCharString("My Program Title2"); + program2.subtitle = MakeOptional(chip::CharSpan::fromCharString("My Program Subtitle2")); + program2.startTime = 30 * 60; + program2.endTime = 60 * 60; + + mPrograms.push_back(program2); + + ProgramType program3; + program3.identifier = chip::CharSpan::fromCharString("progid-abc3"); + program3.channel = abc; + program3.title = chip::CharSpan::fromCharString("My Program Title3"); + program3.subtitle = MakeOptional(chip::CharSpan::fromCharString("My Program Subtitle3")); + program3.startTime = 0; + program3.endTime = 60 * 60; + + mPrograms.push_back(program3); +} + +CHIP_ERROR ChannelManager::HandleGetChannelList(AttributeValueEncoder & aEncoder) +{ + return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { + for (auto const & channel : ChannelManager().mChannels) + { + ReturnErrorOnFailure(encoder.Encode(channel)); + } + return CHIP_NO_ERROR; + }); +} + +CHIP_ERROR ChannelManager::HandleGetLineup(AttributeValueEncoder & aEncoder) +{ + LineupInfoType lineup; + lineup.operatorName = chip::CharSpan::fromCharString("Comcast"); + lineup.lineupName = MakeOptional(chip::CharSpan::fromCharString("Comcast King County")); + lineup.postalCode = MakeOptional(chip::CharSpan::fromCharString("98052")); + lineup.lineupInfoType = LineupInfoTypeEnum::kMso; + + return aEncoder.Encode(lineup); +} + +CHIP_ERROR ChannelManager::HandleGetCurrentChannel(AttributeValueEncoder & aEncoder) +{ + return aEncoder.Encode(mCurrentChannel); +} + +bool ChannelManager::isChannelMatched(const ChannelInfoType & channel, const chip::CharSpan & match) +{ + StringBuilder<16> channelNum; + channelNum.AddFormat("%d.%d", channel.majorNumber, channel.minorNumber); + + auto isMatch = [&match](const Optional & a) { return a.HasValue() && a.Value().data_equal(match); }; + + return isMatch(channel.name) || isMatch(channel.affiliateCallSign) || isMatch(channel.callSign) || + match.data_equal(chip::CharSpan::fromCharString(channelNum.c_str())); +} + +void ChannelManager::HandleChangeChannel(CommandResponseHelper & helper, const CharSpan & match) +{ + int iMatchedChannel = -1; + ChangeChannelResponseType response; + + for (uint16_t i = 0; i < mChannels.size(); i++) + { + // verify if CharSpan matches channel name + // or callSign or affiliateCallSign or majorNumber.minorNumber + if (isChannelMatched(mChannels[i], match)) + { + if (iMatchedChannel != -1) + { + // Error: Found multiple matches + response.status = StatusEnum::kMultipleMatches; + helper.Success(response); + return; + } + iMatchedChannel = i; + } + } + + if (iMatchedChannel == -1) + { + // Error: Found no match + response.status = StatusEnum::kNoMatches; + helper.Success(response); + } + else + { + response.status = StatusEnum::kSuccess; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + mCurrentChannel = mChannels[iMatchedChannel]; + mCurrentChannelIndex = iMatchedChannel; + helper.Success(response); + } +} + +bool ChannelManager::HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) +{ + uint16_t index = 0; + for (auto const & channel : mChannels) + { + // verify if major & minor matches one of the channel from the list + if (channel.minorNumber == minorNumber && channel.majorNumber == majorNumber) + { + // verify if channel changed by comparing values of current channel with the requested channel + if (channel.minorNumber != mCurrentChannel.minorNumber || channel.majorNumber != mCurrentChannel.majorNumber) + { + mCurrentChannelIndex = index; + mCurrentChannel = channel; + return true; + } + } + index++; + } + return false; +} + +bool ChannelManager::HandleSkipChannel(const int16_t & count) +{ + int32_t newChannelIndex = static_cast(count) + static_cast(mCurrentChannelIndex); + uint16_t channelsSize = static_cast(mChannels.size()); + + // handle newChannelIndex out of range. + newChannelIndex = newChannelIndex % channelsSize; + + if (newChannelIndex < 0) + { + newChannelIndex = newChannelIndex + channelsSize; + } + + mCurrentChannelIndex = static_cast(newChannelIndex); + mCurrentChannel = mChannels[mCurrentChannelIndex]; + return true; +} + +void ChannelManager::HandleGetProgramGuide(CommandResponseHelper & helper, + const chip::Optional & startTime, const chip::Optional & endTime, + const chip::Optional> & channelList, + const chip::Optional & pageToken, + const chip::Optional> & recordingFlag, + const chip::Optional> & externalIdList, + const chip::Optional & data) +{ + + // 1. Decode received parameters + // 2. Perform search + // 3. Return results + + // PageTokenType paging; + // paging.limit = MakeOptional(static_cast(10)); + // paging.after = MakeOptional(chip::CharSpan::fromCharString("after-token")); + // paging.before = MakeOptional(chip::CharSpan::fromCharString("before-token")); + + // ChannelPagingStructType channelPaging; + // channelPaging.nextToken = MakeOptional>(paging); + + std::vector matches; + for (auto const & program : mPrograms) + { + if (startTime.ValueOr(0) > program.startTime) + { + continue; + } + if (endTime.ValueOr(std::numeric_limits::max()) < program.endTime) + { + continue; + } + if (channelList.HasValue()) + { + auto iter = channelList.Value().begin(); + bool match = false; + int listCount = 0; + while (iter.Next() && !match) + { + listCount++; + auto & channel = iter.GetValue(); + if (channel.minorNumber != program.channel.minorNumber || channel.majorNumber != program.channel.majorNumber) + { + continue; + } + // this sample code does not currently check OTT + match = true; + } + if (!match && listCount > 0) + { + continue; + } + } + // this sample code does not currently filter on external id list + matches.push_back(program); + } + + ProgramGuideResponseType response; + response.programList = DataModel::List(matches.data(), matches.size()); + helper.Success(response); +} + +bool ChannelManager::HandleRecordProgram(const chip::CharSpan & programIdentifier, bool shouldRecordSeries, + const DataModel::DecodableList & externalIdList, + const chip::ByteSpan & data) +{ + // Start recording + std::string idString(programIdentifier.data(), programIdentifier.size()); + for (auto & program : mPrograms) + { + std::string nextIdString(program.identifier.data(), program.identifier.size()); + if (nextIdString == idString) + { + program.recordingFlag = MakeOptional(chip::BitMask( + shouldRecordSeries ? RecordingFlagBitmap::kRecordSeries : RecordingFlagBitmap::kScheduled)); + } + } + + return true; +} + +bool ChannelManager::HandleCancelRecordProgram(const chip::CharSpan & programIdentifier, bool shouldRecordSeries, + const DataModel::DecodableList & externalIdList, + const chip::ByteSpan & data) +{ + // Cancel recording + std::string idString(programIdentifier.data(), programIdentifier.size()); + for (auto & program : mPrograms) + { + std::string nextIdString(program.identifier.data(), program.identifier.size()); + if (nextIdString == idString) + { + program.recordingFlag = MakeOptional>(0); + } + } + return true; +} + +uint32_t ChannelManager::GetFeatureMap(chip::EndpointId endpoint) +{ + if (endpoint >= MATTER_DM_CHANNEL_CLUSTER_SERVER_ENDPOINT_COUNT) + { + return mDynamicEndpointFeatureMap; + } + + uint32_t featureMap = 0; + Attributes::FeatureMap::Get(endpoint, &featureMap); + return featureMap; +} + +uint16_t ChannelManager::GetClusterRevision(chip::EndpointId endpoint) +{ + if (endpoint >= MATTER_DM_CHANNEL_CLUSTER_SERVER_ENDPOINT_COUNT) + { + return kClusterRevision; + } + + uint16_t clusterRevision = 0; + bool success = + (Attributes::ClusterRevision::Get(endpoint, &clusterRevision) == chip::Protocols::InteractionModel::Status::Success); + if (!success) + { + ChipLogError(Zcl, "ChannelManager::GetClusterRevision error reading cluster revision"); + } + return clusterRevision; +} +#endif // MATTER_DM_PLUGIN_CHANNEL_SERVER diff --git a/examples/chef/common/clusters/channel/ChannelManager.h b/examples/chef/common/clusters/channel/ChannelManager.h new file mode 100644 index 00000000000000..54006c67caf031 --- /dev/null +++ b/examples/chef/common/clusters/channel/ChannelManager.h @@ -0,0 +1,78 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +class ChannelManager : public chip::app::Clusters::Channel::Delegate +{ + using RecordingFlagBitmap = chip::app::Clusters::Channel::RecordingFlagBitmap; + using ChangeChannelResponseType = chip::app::Clusters::Channel::Commands::ChangeChannelResponse::Type; + using ProgramGuideResponseType = chip::app::Clusters::Channel::Commands::ProgramGuideResponse::Type; + using ChannelInfoType = chip::app::Clusters::Channel::Structs::ChannelInfoStruct::Type; + using AdditionalInfoType = chip::app::Clusters::Channel::Structs::AdditionalInfoStruct::Type; + using LineupInfoType = chip::app::Clusters::Channel::Structs::LineupInfoStruct::Type; + using PageTokenType = chip::app::Clusters::Channel::Structs::PageTokenStruct::Type; + using ProgramType = chip::app::Clusters::Channel::Structs::ProgramStruct::Type; + using ChannelPagingType = chip::app::Clusters::Channel::Structs::ChannelPagingStruct::Type; + using Feature = chip::app::Clusters::Channel::Feature; + +public: + ChannelManager(); + + CHIP_ERROR HandleGetChannelList(chip::app::AttributeValueEncoder & aEncoder) override; + CHIP_ERROR HandleGetLineup(chip::app::AttributeValueEncoder & aEncoder) override; + CHIP_ERROR HandleGetCurrentChannel(chip::app::AttributeValueEncoder & aEncoder) override; + + void HandleChangeChannel(chip::app::CommandResponseHelper & helper, + const chip::CharSpan & match) override; + bool HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) override; + bool HandleSkipChannel(const int16_t & count) override; + void HandleGetProgramGuide(chip::app::CommandResponseHelper & helper, + const chip::Optional & startTime, const chip::Optional & endTime, + const chip::Optional> & channelList, + const chip::Optional & pageToken, + const chip::Optional> & recordingFlag, + const chip::Optional> & externalIdList, + const chip::Optional & data) override; + + bool HandleRecordProgram(const chip::CharSpan & programIdentifier, bool shouldRecordSeries, + const chip::app::DataModel::DecodableList & externalIdList, + const chip::ByteSpan & data) override; + + bool HandleCancelRecordProgram(const chip::CharSpan & programIdentifier, bool shouldRecordSeries, + const chip::app::DataModel::DecodableList & externalIdList, + const chip::ByteSpan & data) override; + + uint32_t GetFeatureMap(chip::EndpointId endpoint) override; + uint16_t GetClusterRevision(chip::EndpointId endpoint) override; + +protected: + uint16_t mCurrentChannelIndex; + ChannelInfoType mCurrentChannel; + std::vector mChannels; + std::vector mPrograms; + +private: + bool isChannelMatched(const ChannelInfoType & channel, const chip::CharSpan & match); + static constexpr uint32_t mDynamicEndpointFeatureMap = + chip::BitMask(Feature::kChannelList, Feature::kLineupInfo).Raw(); + static constexpr uint16_t kClusterRevision = 2; +}; diff --git a/examples/chef/common/clusters/keypad-input/KeypadInputManager.cpp b/examples/chef/common/clusters/keypad-input/KeypadInputManager.cpp new file mode 100644 index 00000000000000..bbae2b399b4c0f --- /dev/null +++ b/examples/chef/common/clusters/keypad-input/KeypadInputManager.cpp @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#ifdef MATTER_DM_PLUGIN_KEYPAD_INPUT_SERVER +#include "KeypadInputManager.h" +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters::KeypadInput; + +using chip::app::CommandResponseHelper; + +void KeypadInputManager::HandleSendKey(CommandResponseHelper & helper, const CecKeyCodeType & keycCode) +{ + Commands::SendKeyResponse::Type response; + + switch (keycCode) + { + case CecKeyCodeType::kUp: + case CecKeyCodeType::kDown: + case CecKeyCodeType::kLeft: + case CecKeyCodeType::kRight: + case CecKeyCodeType::kSelect: + case CecKeyCodeType::kBackward: + case CecKeyCodeType::kExit: + case CecKeyCodeType::kRootMenu: + case CecKeyCodeType::kSetupMenu: + case CecKeyCodeType::kEnter: + case CecKeyCodeType::kNumber0OrNumber10: + case CecKeyCodeType::kNumbers1: + case CecKeyCodeType::kNumbers2: + case CecKeyCodeType::kNumbers3: + case CecKeyCodeType::kNumbers4: + case CecKeyCodeType::kNumbers5: + case CecKeyCodeType::kNumbers6: + case CecKeyCodeType::kNumbers7: + case CecKeyCodeType::kNumbers8: + case CecKeyCodeType::kNumbers9: + response.status = chip::app::Clusters::KeypadInput::StatusEnum::kSuccess; + break; + default: + response.status = chip::app::Clusters::KeypadInput::StatusEnum::kUnsupportedKey; + break; + } + + helper.Success(response); +} + +uint32_t KeypadInputManager::GetFeatureMap(chip::EndpointId endpoint) +{ + if (endpoint >= MATTER_DM_KEYPAD_INPUT_CLUSTER_SERVER_ENDPOINT_COUNT) + { + return mDynamicEndpointFeatureMap; + } + + uint32_t featureMap = 0; + Attributes::FeatureMap::Get(endpoint, &featureMap); + return featureMap; +} +#endif // MATTER_DM_PLUGIN_KEYPAD_INPUT_SERVER diff --git a/examples/chef/common/clusters/keypad-input/KeypadInputManager.h b/examples/chef/common/clusters/keypad-input/KeypadInputManager.h new file mode 100644 index 00000000000000..a3c6634166d683 --- /dev/null +++ b/examples/chef/common/clusters/keypad-input/KeypadInputManager.h @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +class KeypadInputManager : public chip::app::Clusters::KeypadInput::Delegate +{ + using SendKeyResponseType = chip::app::Clusters::KeypadInput::Commands::SendKeyResponse::Type; + using CecKeyCodeType = chip::app::Clusters::KeypadInput::CECKeyCodeEnum; + using Feature = chip::app::Clusters::KeypadInput::Feature; + +public: + void HandleSendKey(chip::app::CommandResponseHelper & helper, const CecKeyCodeType & keyCode) override; + + uint32_t GetFeatureMap(chip::EndpointId endpoint) override; + +private: + static constexpr uint32_t mDynamicEndpointFeatureMap = + chip::BitMask(Feature::kNavigationKeyCodes, Feature::kLocationKeys, Feature::kNumberKeys).Raw(); +}; diff --git a/examples/chef/common/clusters/low-power/LowPowerManager.cpp b/examples/chef/common/clusters/low-power/LowPowerManager.cpp new file mode 100644 index 00000000000000..1926d0c7150ddd --- /dev/null +++ b/examples/chef/common/clusters/low-power/LowPowerManager.cpp @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#ifdef MATTER_DM_PLUGIN_LOW_POWER_SERVER +#include "LowPowerManager.h" + +bool LowPowerManager::HandleSleep() +{ + ChipLogProgress(Zcl, "LowPowerManager::HandleSleep"); + return true; +} +#endif // MATTER_DM_PLUGIN_LOW_POWER_SERVER diff --git a/examples/chef/common/clusters/low-power/LowPowerManager.h b/examples/chef/common/clusters/low-power/LowPowerManager.h new file mode 100644 index 00000000000000..92bb1417be514d --- /dev/null +++ b/examples/chef/common/clusters/low-power/LowPowerManager.h @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +class LowPowerManager : public chip::app::Clusters::LowPower::Delegate +{ +public: + bool HandleSleep() override; +}; diff --git a/examples/chef/common/clusters/media-input/MediaInputManager.cpp b/examples/chef/common/clusters/media-input/MediaInputManager.cpp new file mode 100644 index 00000000000000..f7e853cc46a40b --- /dev/null +++ b/examples/chef/common/clusters/media-input/MediaInputManager.cpp @@ -0,0 +1,102 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#ifdef MATTER_DM_PLUGIN_MEDIA_INPUT_SERVER +#include "MediaInputManager.h" + +using namespace std; +using namespace chip; +using namespace chip::app::Clusters::MediaInput; + +MediaInputManager::MediaInputManager() +{ + struct InputData inputData1(1, chip::app::Clusters::MediaInput::InputTypeEnum::kHdmi, "HDMI 1", + "High-Definition Multimedia Interface"); + mInputs.push_back(inputData1); + struct InputData inputData2(2, chip::app::Clusters::MediaInput::InputTypeEnum::kHdmi, "HDMI 2", + "High-Definition Multimedia Interface"); + mInputs.push_back(inputData2); + struct InputData inputData3(3, chip::app::Clusters::MediaInput::InputTypeEnum::kHdmi, "HDMI 3", + "High-Definition Multimedia Interface"); + mInputs.push_back(inputData3); + + mCurrentInput = 1; +} + +CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncoder & aEncoder) +{ + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + for (auto const & inputData : this->mInputs) + { + ReturnErrorOnFailure(encoder.Encode(inputData.GetEncodable())); + } + return CHIP_NO_ERROR; + }); +} + +uint8_t MediaInputManager::HandleGetCurrentInput() +{ + return mCurrentInput; +} + +bool MediaInputManager::HandleSelectInput(const uint8_t index) +{ + for (auto const & inputData : mInputs) + { + if (inputData.index == index) + { + mCurrentInput = index; + return true; + } + } + + return false; +} + +bool MediaInputManager::HandleShowInputStatus() +{ + ChipLogProgress(Zcl, " MediaInputManager::HandleShowInputStatus()"); + for (auto const & inputData : mInputs) + { + ChipLogProgress(Zcl, " [%d] type=%d selected=%d name=%s desc=%s", inputData.index, + static_cast(inputData.inputType), (mCurrentInput == inputData.index ? 1 : 0), + inputData.name.c_str(), inputData.description.c_str()); + } + return true; +} + +bool MediaInputManager::HandleHideInputStatus() +{ + ChipLogProgress(Zcl, " MediaInputManager::HandleHideInputStatus()"); + return true; +} + +bool MediaInputManager::HandleRenameInput(const uint8_t index, const chip::CharSpan & newName) +{ + for (auto & inputData : mInputs) + { + if (inputData.index == index) + { + inputData.Rename(newName); + return true; + } + } + + return false; +} +#endif // MATTER_DM_PLUGIN_MEDIA_INPUT_SERVER diff --git a/examples/chef/common/clusters/media-input/MediaInputManager.h b/examples/chef/common/clusters/media-input/MediaInputManager.h new file mode 100644 index 00000000000000..104db65e2bbe97 --- /dev/null +++ b/examples/chef/common/clusters/media-input/MediaInputManager.h @@ -0,0 +1,68 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +class MediaInputManager : public chip::app::Clusters::MediaInput::Delegate +{ + using InputInfoType = chip::app::Clusters::MediaInput::Structs::InputInfoStruct::Type; + +public: + MediaInputManager(); + + CHIP_ERROR HandleGetInputList(chip::app::AttributeValueEncoder & aEncoder) override; + uint8_t HandleGetCurrentInput() override; + bool HandleSelectInput(const uint8_t index) override; + bool HandleShowInputStatus() override; + bool HandleHideInputStatus() override; + bool HandleRenameInput(const uint8_t index, const chip::CharSpan & name) override; + + struct InputData + { + uint8_t index; + chip::app::Clusters::MediaInput::InputTypeEnum inputType; + std::string name; + std::string description; + + InputData(uint8_t i, chip::app::Clusters::MediaInput::InputTypeEnum t, const char * n, const char * d) : + index(i), inputType(t), name(n), description(d) + {} + + void Rename(const chip::CharSpan & newName) { name.assign(newName.data(), newName.size()); } + + InputInfoType GetEncodable() const + { + InputInfoType result; + result.index = index; + result.inputType = inputType; + result.name = chip::CharSpan::fromCharString(name.c_str()); + result.description = chip::CharSpan::fromCharString(description.c_str()); + return result; + } + }; + +protected: + uint8_t mCurrentInput; + std::vector mInputs; + +private: +}; diff --git a/examples/chef/common/clusters/media-playback/MediaPlaybackManager.cpp b/examples/chef/common/clusters/media-playback/MediaPlaybackManager.cpp new file mode 100644 index 00000000000000..512da2966d68b6 --- /dev/null +++ b/examples/chef/common/clusters/media-playback/MediaPlaybackManager.cpp @@ -0,0 +1,339 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#ifdef MATTER_DM_PLUGIN_MEDIA_PLAYBACK_SERVER +#include "MediaPlaybackManager.h" +#include +#include + +using namespace std; +using namespace chip::app::DataModel; +using namespace chip::app::Clusters::MediaPlayback; +using namespace chip::Uint8; + +using chip::CharSpan; +using chip::app::AttributeValueEncoder; +using chip::app::CommandResponseHelper; + +PlaybackStateEnum MediaPlaybackManager::HandleGetCurrentState() +{ + return mCurrentState; +} + +uint64_t MediaPlaybackManager::HandleGetStartTime() +{ + return mStartTime; +} + +uint64_t MediaPlaybackManager::HandleGetDuration() +{ + return mDuration; +} + +CHIP_ERROR MediaPlaybackManager::HandleGetSampledPosition(AttributeValueEncoder & aEncoder) +{ + return aEncoder.Encode(mPlaybackPosition); +} + +float MediaPlaybackManager::HandleGetPlaybackSpeed() +{ + return mPlaybackSpeed; +} + +uint64_t MediaPlaybackManager::HandleGetSeekRangeStart() +{ + return mStartTime; +} + +uint64_t MediaPlaybackManager::HandleGetSeekRangeEnd() +{ + return mDuration; +} + +CHIP_ERROR MediaPlaybackManager::HandleGetActiveAudioTrack(AttributeValueEncoder & aEncoder) +{ + return aEncoder.Encode(mActiveAudioTrack); +} + +CHIP_ERROR MediaPlaybackManager::HandleGetAvailableAudioTracks(AttributeValueEncoder & aEncoder) +{ + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + for (auto const & audioTrack : mAvailableAudioTracks) + { + ReturnErrorOnFailure(encoder.Encode(audioTrack)); + } + return CHIP_NO_ERROR; + }); +} + +CHIP_ERROR MediaPlaybackManager::HandleGetActiveTextTrack(AttributeValueEncoder & aEncoder) +{ + return aEncoder.Encode(mActiveTextTrack); +} + +CHIP_ERROR MediaPlaybackManager::HandleGetAvailableTextTracks(AttributeValueEncoder & aEncoder) +{ + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + for (auto const & textTrack : mAvailableTextTracks) + { + ReturnErrorOnFailure(encoder.Encode(textTrack)); + } + return CHIP_NO_ERROR; + }); +} + +void MediaPlaybackManager::HandlePlay(CommandResponseHelper & helper) +{ + mCurrentState = PlaybackStateEnum::kPlaying; + mPlaybackSpeed = 1; + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +void MediaPlaybackManager::HandlePause(CommandResponseHelper & helper) +{ + mCurrentState = PlaybackStateEnum::kPaused; + mPlaybackSpeed = 0; + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +void MediaPlaybackManager::HandleStop(CommandResponseHelper & helper) +{ + mCurrentState = PlaybackStateEnum::kNotPlaying; + mPlaybackSpeed = 0; + mPlaybackPosition = { 0, chip::app::DataModel::Nullable(0) }; + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +void MediaPlaybackManager::HandleFastForward(CommandResponseHelper & helper, + const chip::Optional & audioAdvanceUnmuted) +{ + if (mPlaybackSpeed == kPlaybackMaxForwardSpeed) + { + // if already at max speed, return error + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSpeedOutOfRange; + helper.Success(response); + return; + } + + mCurrentState = PlaybackStateEnum::kPlaying; + mPlaybackSpeed = (mPlaybackSpeed <= 0 ? 1 : mPlaybackSpeed * 2); + if (mPlaybackSpeed > kPlaybackMaxForwardSpeed) + { + // don't exceed max speed + mPlaybackSpeed = kPlaybackMaxForwardSpeed; + } + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +void MediaPlaybackManager::HandlePrevious(CommandResponseHelper & helper) +{ + mCurrentState = PlaybackStateEnum::kPlaying; + mPlaybackSpeed = 1; + mPlaybackPosition = { 0, chip::app::DataModel::Nullable(0) }; + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +void MediaPlaybackManager::HandleRewind(CommandResponseHelper & helper, + const chip::Optional & audioAdvanceUnmuted) +{ + if (mPlaybackSpeed == kPlaybackMaxRewindSpeed) + { + // if already at max speed in reverse, return error + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSpeedOutOfRange; + helper.Success(response); + return; + } + + mCurrentState = PlaybackStateEnum::kPlaying; + mPlaybackSpeed = (mPlaybackSpeed >= 0 ? -1 : mPlaybackSpeed * 2); + if (mPlaybackSpeed < kPlaybackMaxRewindSpeed) + { + // don't exceed max rewind speed + mPlaybackSpeed = kPlaybackMaxRewindSpeed; + } + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +void MediaPlaybackManager::HandleSkipBackward(CommandResponseHelper & helper, + const uint64_t & deltaPositionMilliseconds) +{ + uint64_t newPosition = (mPlaybackPosition.position.Value() > deltaPositionMilliseconds + ? mPlaybackPosition.position.Value() - deltaPositionMilliseconds + : 0); + mPlaybackPosition = { 0, chip::app::DataModel::Nullable(newPosition) }; + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +void MediaPlaybackManager::HandleSkipForward(CommandResponseHelper & helper, + const uint64_t & deltaPositionMilliseconds) +{ + uint64_t newPosition = mPlaybackPosition.position.Value() + deltaPositionMilliseconds; + newPosition = newPosition > mDuration ? mDuration : newPosition; + mPlaybackPosition = { 0, chip::app::DataModel::Nullable(newPosition) }; + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +void MediaPlaybackManager::HandleSeek(CommandResponseHelper & helper, + const uint64_t & positionMilliseconds) +{ + if (positionMilliseconds > mDuration) + { + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSeekOutOfRange; + helper.Success(response); + } + else + { + mPlaybackPosition = { 0, chip::app::DataModel::Nullable(positionMilliseconds) }; + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); + } +} + +void MediaPlaybackManager::HandleNext(CommandResponseHelper & helper) +{ + mCurrentState = PlaybackStateEnum::kPlaying; + mPlaybackSpeed = 1; + mPlaybackPosition = { 0, chip::app::DataModel::Nullable(0) }; + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +void MediaPlaybackManager::HandleStartOver(CommandResponseHelper & helper) +{ + mPlaybackPosition = { 0, chip::app::DataModel::Nullable(0) }; + + Commands::PlaybackResponse::Type response; + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +bool MediaPlaybackManager::HandleActivateAudioTrack(const chip::CharSpan & trackId, const uint8_t & audioOutputIndex) +{ + std::string idString(trackId.data(), trackId.size()); + for (auto const & availableAudioTrack : mAvailableAudioTracks) + { + std::string nextIdString(availableAudioTrack.id.data(), availableAudioTrack.id.size()); + if (nextIdString == idString) + { + mActiveAudioTrack = availableAudioTrack; + return true; + } + } + return false; +} + +bool MediaPlaybackManager::HandleActivateTextTrack(const chip::CharSpan & trackId) +{ + std::string idString(trackId.data(), trackId.size()); + for (auto const & availableTextTrack : mAvailableTextTracks) + { + std::string nextIdString(availableTextTrack.id.data(), availableTextTrack.id.size()); + if (nextIdString == idString) + { + mActiveTextTrack = availableTextTrack; + return true; + } + } + return false; +} + +bool MediaPlaybackManager::HandleDeactivateTextTrack() +{ + // Handle Deactivate Text Track + if (mActiveTextTrack.id.data() != nullptr) + { + mActiveTextTrack = {}; + } + return true; +} + +uint32_t MediaPlaybackManager::GetFeatureMap(chip::EndpointId endpoint) +{ + if (endpoint >= MATTER_DM_MEDIA_PLAYBACK_CLUSTER_SERVER_ENDPOINT_COUNT) + { + return mDynamicEndpointFeatureMap; + } + + uint32_t featureMap = 0; + Attributes::FeatureMap::Get(endpoint, &featureMap); + return featureMap; +} + +uint16_t MediaPlaybackManager::GetClusterRevision(chip::EndpointId endpoint) +{ + if (endpoint >= MATTER_DM_MEDIA_PLAYBACK_CLUSTER_SERVER_ENDPOINT_COUNT) + { + return kClusterRevision; + } + + uint16_t clusterRevision = 0; + bool success = + (Attributes::ClusterRevision::Get(endpoint, &clusterRevision) == chip::Protocols::InteractionModel::Status::Success); + if (!success) + { + ChipLogError(Zcl, "MediaPlaybackManager::GetClusterRevision error reading cluster revision"); + } + return clusterRevision; +} + +#endif /// MATTER_DM_PLUGIN_MEDIA_PLAYBACK_SERVER diff --git a/examples/chef/common/clusters/media-playback/MediaPlaybackManager.h b/examples/chef/common/clusters/media-playback/MediaPlaybackManager.h new file mode 100644 index 00000000000000..79bca10a3c8fb6 --- /dev/null +++ b/examples/chef/common/clusters/media-playback/MediaPlaybackManager.h @@ -0,0 +1,117 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +class MediaPlaybackManager : public chip::app::Clusters::MediaPlayback::Delegate +{ + using PlaybackResponseType = chip::app::Clusters::MediaPlayback::Commands::PlaybackResponse::Type; + using PlaybackPositionType = chip::app::Clusters::MediaPlayback::Structs::PlaybackPositionStruct::Type; + using TrackType = chip::app::Clusters::MediaPlayback::Structs::TrackStruct::Type; + using TrackAttributesType = chip::app::Clusters::MediaPlayback::Structs::TrackAttributesStruct::Type; + using Feature = chip::app::Clusters::MediaPlayback::Feature; + +public: + chip::app::Clusters::MediaPlayback::PlaybackStateEnum HandleGetCurrentState() override; + uint64_t HandleGetStartTime() override; + uint64_t HandleGetDuration() override; + CHIP_ERROR HandleGetSampledPosition(chip::app::AttributeValueEncoder & aEncoder) override; + float HandleGetPlaybackSpeed() override; + uint64_t HandleGetSeekRangeStart() override; + uint64_t HandleGetSeekRangeEnd() override; + CHIP_ERROR HandleGetActiveAudioTrack(chip::app::AttributeValueEncoder & aEncoder) override; + CHIP_ERROR HandleGetAvailableAudioTracks(chip::app::AttributeValueEncoder & aEncoder) override; + CHIP_ERROR HandleGetActiveTextTrack(chip::app::AttributeValueEncoder & aEncoder) override; + CHIP_ERROR HandleGetAvailableTextTracks(chip::app::AttributeValueEncoder & aEncoder) override; + + void HandlePlay(chip::app::CommandResponseHelper & helper) override; + void HandlePause(chip::app::CommandResponseHelper & helper) override; + void HandleStop(chip::app::CommandResponseHelper & helper) override; + void HandleFastForward(chip::app::CommandResponseHelper & helper, + const chip::Optional & audioAdvanceUnmuted) override; + void HandlePrevious(chip::app::CommandResponseHelper & helper) override; + void HandleRewind(chip::app::CommandResponseHelper & helper, + const chip::Optional & audioAdvanceUnmuted) override; + void HandleSkipBackward(chip::app::CommandResponseHelper & helper, + const uint64_t & deltaPositionMilliseconds) override; + void HandleSkipForward(chip::app::CommandResponseHelper & helper, + const uint64_t & deltaPositionMilliseconds) override; + void HandleSeek(chip::app::CommandResponseHelper & helper, + const uint64_t & positionMilliseconds) override; + void HandleNext(chip::app::CommandResponseHelper & helper) override; + void HandleStartOver(chip::app::CommandResponseHelper & helper) override; + bool HandleActivateAudioTrack(const chip::CharSpan & trackId, const uint8_t & audioOutputIndex) override; + bool HandleActivateTextTrack(const chip::CharSpan & trackId) override; + bool HandleDeactivateTextTrack() override; + + uint32_t GetFeatureMap(chip::EndpointId endpoint) override; + uint16_t GetClusterRevision(chip::EndpointId endpoint) override; + +protected: + // NOTE: it does not make sense to have default state of playing with a speed of 0, but + // the CI test cases expect these values, and need to be fixed. + chip::app::Clusters::MediaPlayback::PlaybackStateEnum mCurrentState = + chip::app::Clusters::MediaPlayback::PlaybackStateEnum::kPlaying; + PlaybackPositionType mPlaybackPosition = { 0, chip::app::DataModel::Nullable(0) }; + TrackType mActiveAudioTrack = { chip::CharSpan("activeAudioTrackId_0", 20), + chip::app::DataModel::Nullable( + { chip::CharSpan("languageCode1", 13), + chip::Optional>( + { chip::app::DataModel::MakeNullable(chip::CharSpan("displayName1", 12)) }) }) }; + std::vector mAvailableAudioTracks = { + { chip::CharSpan("activeAudioTrackId_0", 20), + chip::app::DataModel::Nullable( + { chip::CharSpan("languageCode1", 13), + chip::Optional>( + { chip::app::DataModel::MakeNullable(chip::CharSpan("displayName1", 12)) }) }) }, + { chip::CharSpan("activeAudioTrackId_1", 20), + chip::app::DataModel::Nullable( + { chip::CharSpan("languageCode2", 13), + chip::Optional>( + { chip::app::DataModel::MakeNullable(chip::CharSpan("displayName2", 12)) }) }) } + }; + TrackType mActiveTextTrack = {}; + std::vector mAvailableTextTracks = { + { chip::CharSpan("activeTextTrackId_0", 19), + chip::app::DataModel::Nullable( + { chip::CharSpan("languageCode1", 13), + chip::Optional>( + { chip::app::DataModel::MakeNullable(chip::CharSpan("displayName1", 12)) }) }) }, + { chip::CharSpan("activeTextTrackId_1", 19), + chip::app::DataModel::Nullable( + { chip::CharSpan("languageCode2", 13), + chip::Optional>( + { chip::app::DataModel::MakeNullable(chip::CharSpan("displayName2", 12)) }) }) } + }; + float mPlaybackSpeed = 1.0; + uint64_t mStartTime = 0; + // Magic number for testing. + uint64_t mDuration = 80000; + bool mAudioAdvanceMuted = false; + + static const int kPlaybackMaxForwardSpeed = 10; + static const int kPlaybackMaxRewindSpeed = -10; + +private: + static constexpr uint32_t mDynamicEndpointFeatureMap = + chip::BitMask(Feature::kAdvancedSeek, Feature::kVariableSpeed).Raw(); + static constexpr uint16_t kClusterRevision = 2; +}; diff --git a/examples/chef/common/clusters/target-navigator/TargetNavigatorManager.cpp b/examples/chef/common/clusters/target-navigator/TargetNavigatorManager.cpp new file mode 100644 index 00000000000000..17acf11b39bf23 --- /dev/null +++ b/examples/chef/common/clusters/target-navigator/TargetNavigatorManager.cpp @@ -0,0 +1,94 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#ifdef MATTER_DM_PLUGIN_TARGET_NAVIGATOR_SERVER +#include "TargetNavigatorManager.h" +#include + +using namespace std; +using namespace chip::app; +using namespace chip::app::Clusters::TargetNavigator; + +using chip::CharSpan; +using chip::app::AttributeValueEncoder; +using chip::app::CommandResponseHelper; + +TargetNavigatorManager::TargetNavigatorManager(std::list targets, uint8_t currentTarget) +{ + mTargets = targets; + mCurrentTarget = currentTarget; +} + +CHIP_ERROR TargetNavigatorManager::HandleGetTargetList(AttributeValueEncoder & aEncoder) +{ + // NOTE: the ids for each target start at 1 so that we can reserve 0 as "no current target" + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + int i = 0; + for (std::string & entry : mTargets) + { + Structs::TargetInfoStruct::Type outputInfo; + outputInfo.identifier = static_cast(i + 1); + outputInfo.name = CharSpan::fromCharString(entry.c_str()); + ReturnErrorOnFailure(encoder.Encode(outputInfo)); + i++; + } + return CHIP_NO_ERROR; + }); +} + +uint8_t TargetNavigatorManager::HandleGetCurrentTarget() +{ + return mCurrentTarget; +} + +void TargetNavigatorManager::HandleNavigateTarget(CommandResponseHelper & helper, + const uint64_t & target, const CharSpan & data) +{ + NavigateTargetResponseType response; + if (target == kNoCurrentTarget || target > mTargets.size()) + { + response.data = chip::MakeOptional(CharSpan::fromCharString("error")); + response.status = StatusEnum::kTargetNotFound; + helper.Success(response); + return; + } + mCurrentTarget = static_cast(target); + + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; + helper.Success(response); +} + +uint16_t TargetNavigatorManager::GetClusterRevision(chip::EndpointId endpoint) +{ + if (endpoint >= MATTER_DM_TARGET_NAVIGATOR_CLUSTER_SERVER_ENDPOINT_COUNT) + { + return kClusterRevision; + } + + uint16_t clusterRevision = 0; + bool success = + (Attributes::ClusterRevision::Get(endpoint, &clusterRevision) == chip::Protocols::InteractionModel::Status::Success); + if (!success) + { + ChipLogError(Zcl, "TargetNavigatorManager::GetClusterRevision error reading cluster revision"); + } + + return clusterRevision; +} +#endif // MATTER_DM_PLUGIN_TARGET_NAVIGATOR_SERVER diff --git a/examples/chef/common/clusters/target-navigator/TargetNavigatorManager.h b/examples/chef/common/clusters/target-navigator/TargetNavigatorManager.h new file mode 100644 index 00000000000000..21a08b9595cd82 --- /dev/null +++ b/examples/chef/common/clusters/target-navigator/TargetNavigatorManager.h @@ -0,0 +1,45 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +class TargetNavigatorManager : public chip::app::Clusters::TargetNavigator::Delegate +{ + using TargetInfoType = chip::app::Clusters::TargetNavigator::Structs::TargetInfoStruct::Type; + using NavigateTargetResponseType = chip::app::Clusters::TargetNavigator::Commands::NavigateTargetResponse::Type; + +public: + TargetNavigatorManager() : TargetNavigatorManager({ "exampleName", "exampleName" }, kNoCurrentTarget){}; + TargetNavigatorManager(std::list targets, uint8_t currentTarget); + + CHIP_ERROR HandleGetTargetList(chip::app::AttributeValueEncoder & aEncoder) override; + uint8_t HandleGetCurrentTarget() override; + void HandleNavigateTarget(chip::app::CommandResponseHelper & responser, const uint64_t & target, + const chip::CharSpan & data) override; + uint16_t GetClusterRevision(chip::EndpointId endpoint) override; + +protected: + // NOTE: the ids for each target start at 1 so that we can reserve 0 as "no current target" + static const uint8_t kNoCurrentTarget = 0; + std::list mTargets; + uint8_t mCurrentTarget; + +private: + static constexpr uint16_t kClusterRevision = 2; +}; diff --git a/examples/chef/common/clusters/wake-on-lan/WakeOnLanManager.cpp b/examples/chef/common/clusters/wake-on-lan/WakeOnLanManager.cpp new file mode 100644 index 00000000000000..5f4e2e1ec7b6e2 --- /dev/null +++ b/examples/chef/common/clusters/wake-on-lan/WakeOnLanManager.cpp @@ -0,0 +1,68 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#ifdef MATTER_DM_PLUGIN_WAKE_ON_LAN_SERVER +#include "WakeOnLanManager.h" +#include +#include +#include +#include +#include + +constexpr char kNullHexMACAddress[] = "000000000000"; + +using namespace chip; +using namespace chip::app::Clusters::WakeOnLan; + +std::string getMacAddress() +{ + uint8_t macBuffer[chip::DeviceLayer::ConfigurationManager::kPrimaryMACAddressLength]; + MutableByteSpan mac(macBuffer); + if (chip::DeviceLayer::ConfigurationMgr().GetPrimaryMACAddress(mac) != CHIP_NO_ERROR) + { + ChipLogProgress(Zcl, "WakeOnLanManager::getMacAddress no primary MAC configured by DeviceLayer"); + return kNullHexMACAddress; + } + + char macStr[chip::DeviceLayer::ConfigurationManager::kPrimaryMACAddressLength * 2 + 1] = { 0 }; // added null char + if (BytesToHex(&macBuffer[0], sizeof(macBuffer), &macStr[0], sizeof(macBuffer) * 2u, chip::Encoding::HexFlags::kUppercase) != + CHIP_NO_ERROR) + { + ChipLogProgress(Zcl, "WakeOnLanManager::getMacAddress hex conversion failed"); + return kNullHexMACAddress; + } + + return std::string(macStr); +} + +CHIP_ERROR WakeOnLanManager::HandleGetMacAddress(chip::app::AttributeValueEncoder & aEncoder) +{ + ChipLogProgress(Zcl, "WakeOnLanManager::HandleGetMacAddress"); + + // Spec REQUIRES 48-bit mac addresses. This means at least Thread devices will + // fail here. + if (chip::DeviceLayer::ConfigurationManager::kPrimaryMACAddressLength != 6) + { + ChipLogError(Zcl, "WakeOnLanManager: primary MAC address is not 48-bit"); + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + + return aEncoder.Encode(CharSpan::fromCharString(getMacAddress().c_str())); +} +#endif // MATTER_DM_PLUGIN_WAKE_ON_LAN_SERVER diff --git a/examples/chef/common/clusters/wake-on-lan/WakeOnLanManager.h b/examples/chef/common/clusters/wake-on-lan/WakeOnLanManager.h new file mode 100644 index 00000000000000..63217020e9ab11 --- /dev/null +++ b/examples/chef/common/clusters/wake-on-lan/WakeOnLanManager.h @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +class WakeOnLanManager : public chip::app::Clusters::WakeOnLan::Delegate +{ +public: + CHIP_ERROR HandleGetMacAddress(chip::app::AttributeValueEncoder & aEncoder) override; +}; diff --git a/examples/chef/common/stubs.cpp b/examples/chef/common/stubs.cpp index cff7ffdee4679f..48c48620c98fb0 100644 --- a/examples/chef/common/stubs.cpp +++ b/examples/chef/common/stubs.cpp @@ -22,6 +22,8 @@ using chip::app::DataModel::Nullable; using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, const EmberAfAttributeMetadata * attributeMetadata, @@ -341,14 +343,127 @@ bool emberAfPluginDoorLockSetCredential(chip::EndpointId endpointId, uint16_t cr #endif /* MATTER_DM_PLUGIN_DOOR_LOCK_SERVER */ +void emberAfPluginSmokeCoAlarmSelfTestRequestCommand(EndpointId endpointId) {} + +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, + uint8_t * value) +{ + ClusterId clusterId = attributePath.mClusterId; + AttributeId attributeId = attributePath.mAttributeId; + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); + + if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) + { + ChipLogProgress(Zcl, "OnOff attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", ChipLogValueMEI(attributeId), + type, *value, size); + } + else if (clusterId == LevelControl::Id) + { + ChipLogProgress(Zcl, "Level Control attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + + // WIP Apply attribute change to Light + } +} + +/** @brief OnOff Cluster Init + * + * This function is called when a specific cluster is initialized. It gives the + * application an opportunity to take care of cluster initialization procedures. + * It is called exactly once for each endpoint where cluster is present. + * + * TODO Issue #3841 + * emberAfOnOffClusterInitCallback happens before the stack initialize the cluster + * attributes to the default value. + * The logic here expects something similar to the deprecated Plugins callback + * emberAfPluginOnOffClusterServerPostInitCallback. + * + */ +void emberAfOnOffClusterInitCallback(EndpointId endpoint) {} + +#ifdef MATTER_DM_PLUGIN_AUDIO_OUTPUT_SERVER +#include "audio-output/AudioOutputManager.h" +static AudioOutputManager audioOutputManager; + +void emberAfAudioOutputClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Linux App: AudioOutput::SetDefaultDelegate"); + AudioOutput::SetDefaultDelegate(endpoint, &audioOutputManager); +} +#endif + #ifdef MATTER_DM_PLUGIN_CHANNEL_SERVER -#include +#include "channel/ChannelManager.h" +static ChannelManager channelManager; void emberAfChannelClusterInitCallback(EndpointId endpoint) { - app::Clusters::Channel::SetDefaultDelegate(endpoint, - static_cast(&(ChefChannelManager::Instance()))); + ChipLogProgress(Zcl, "TV Linux App: Channel::SetDefaultDelegate"); + Channel::SetDefaultDelegate(endpoint, &channelManager); } -#endif // MATTER_DM_PLUGIN_CHANNEL_SERVER +#endif -void emberAfPluginSmokeCoAlarmSelfTestRequestCommand(EndpointId endpointId) {} +#ifdef MATTER_DM_PLUGIN_KEYPAD_INPUT_SERVER +#include "keypad-input/KeypadInputManager.h" +static KeypadInputManager keypadInputManager; + +void emberAfKeypadInputClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Linux App: KeypadInput::SetDefaultDelegate"); + KeypadInput::SetDefaultDelegate(endpoint, &keypadInputManager); +} +#endif + +#ifdef MATTER_DM_PLUGIN_LOW_POWER_SERVER +#include "low-power/LowPowerManager.h" +static LowPowerManager lowPowerManager; + +void emberAfLowPowerClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Linux App: LowPower::SetDefaultDelegate"); + LowPower::SetDefaultDelegate(endpoint, &lowPowerManager); +} +#endif + +#ifdef MATTER_DM_PLUGIN_MEDIA_INPUT_SERVER +#include "media-input/MediaInputManager.h" +static MediaInputManager mediaInputManager; +void emberAfMediaInputClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Linux App: MediaInput::SetDefaultDelegate"); + MediaInput::SetDefaultDelegate(endpoint, &mediaInputManager); +} +#endif + +#ifdef MATTER_DM_PLUGIN_MEDIA_PLAYBACK_SERVER +#include "media-playback/MediaPlaybackManager.h" +static MediaPlaybackManager mediaPlaybackManager; + +void emberAfMediaPlaybackClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Linux App: MediaPlayback::SetDefaultDelegate"); + MediaPlayback::SetDefaultDelegate(endpoint, &mediaPlaybackManager); +} +#endif + +#ifdef MATTER_DM_PLUGIN_TARGET_NAVIGATOR_SERVER +#include "target-navigator/TargetNavigatorManager.h" +static TargetNavigatorManager targetNavigatorManager; + +void emberAfTargetNavigatorClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Linux App: TargetNavigator::SetDefaultDelegate"); + TargetNavigator::SetDefaultDelegate(endpoint, &targetNavigatorManager); +} +#endif + +#ifdef MATTER_DM_PLUGIN_WAKE_ON_LAN_SERVER +#include "wake-on-lan/WakeOnLanManager.h" +static WakeOnLanManager wakeOnLanManager; + +void emberAfWakeOnLanClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Linux App: WakeOnLanManager::SetDefaultDelegate"); + WakeOnLan::SetDefaultDelegate(endpoint, &wakeOnLanManager); +} +#endif diff --git a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter index 554cdfa7e42e23..bcc9bd054ff722 100644 --- a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter +++ b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter @@ -1250,7 +1250,7 @@ cluster ActivatedCarbonFilterMonitoring = 114 { } /** An interface for controlling a fan in a heating/cooling system. */ -provisional cluster FanControl = 514 { +cluster FanControl = 514 { revision 4; enum AirflowDirectionEnum : enum8 { diff --git a/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter b/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter index 734ed039932a9f..e827ce800b081d 100644 --- a/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter +++ b/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter @@ -1518,7 +1518,7 @@ cluster Thermostat = 513 { } /** An interface for controlling a fan in a heating/cooling system. */ -provisional cluster FanControl = 514 { +cluster FanControl = 514 { revision 4; enum AirflowDirectionEnum : enum8 { diff --git a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter index c5c71d597ebe74..d8fb307e9d8579 100644 --- a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter +++ b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter @@ -1,6 +1,56 @@ // This IDL was generated automatically by ZAP. // It is for view/code review purposes only. +/** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ +cluster Identify = 3 { + revision 4; + + enum EffectIdentifierEnum : enum8 { + kBlink = 0; + kBreathe = 1; + kOkay = 2; + kChannelChange = 11; + kFinishEffect = 254; + kStopEffect = 255; + } + + enum EffectVariantEnum : enum8 { + kDefault = 0; + } + + enum IdentifyTypeEnum : enum8 { + kNone = 0; + kLightOutput = 1; + kVisibleIndicator = 2; + kAudibleBeep = 3; + kDisplay = 4; + kActuator = 5; + } + + attribute int16u identifyTime = 0; + readonly attribute IdentifyTypeEnum identifyType = 1; + 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 IdentifyRequest { + int16u identifyTime = 0; + } + + request struct TriggerEffectRequest { + EffectIdentifierEnum effectIdentifier = 0; + EffectVariantEnum effectVariant = 1; + } + + /** Command description for Identify */ + command access(invoke: manage) Identify(IdentifyRequest): DefaultSuccess = 0; + /** Command description for TriggerEffect */ + command access(invoke: manage) TriggerEffect(TriggerEffectRequest): DefaultSuccess = 64; +} + /** Attributes and commands for switching devices between 'On' and 'Off' states. */ cluster OnOff = 6 { revision 6; @@ -73,6 +123,131 @@ cluster OnOff = 6 { command OnWithTimedOff(OnWithTimedOffRequest): DefaultSuccess = 66; } +/** Attributes and commands for controlling devices that can be set to a level between fully 'On' and fully 'Off.' */ +cluster LevelControl = 8 { + revision 5; + + enum MoveModeEnum : enum8 { + kUp = 0; + kDown = 1; + } + + enum StepModeEnum : enum8 { + kUp = 0; + kDown = 1; + } + + bitmap Feature : bitmap32 { + kOnOff = 0x1; + kLighting = 0x2; + kFrequency = 0x4; + } + + bitmap OptionsBitmap : bitmap8 { + kExecuteIfOff = 0x1; + kCoupleColorTempToLevel = 0x2; + } + + readonly attribute nullable int8u currentLevel = 0; + readonly attribute optional int16u remainingTime = 1; + readonly attribute optional int8u minLevel = 2; + readonly attribute optional int8u maxLevel = 3; + readonly attribute optional int16u currentFrequency = 4; + readonly attribute optional int16u minFrequency = 5; + readonly attribute optional int16u maxFrequency = 6; + attribute OptionsBitmap options = 15; + attribute optional int16u onOffTransitionTime = 16; + attribute nullable int8u onLevel = 17; + attribute optional nullable int16u onTransitionTime = 18; + attribute optional nullable int16u offTransitionTime = 19; + attribute optional nullable int8u defaultMoveRate = 20; + attribute access(write: manage) optional nullable int8u startUpCurrentLevel = 16384; + 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 MoveToLevelRequest { + int8u level = 0; + nullable int16u transitionTime = 1; + OptionsBitmap optionsMask = 2; + OptionsBitmap optionsOverride = 3; + } + + request struct MoveRequest { + MoveModeEnum moveMode = 0; + nullable int8u rate = 1; + OptionsBitmap optionsMask = 2; + OptionsBitmap optionsOverride = 3; + } + + request struct StepRequest { + StepModeEnum stepMode = 0; + int8u stepSize = 1; + nullable int16u transitionTime = 2; + OptionsBitmap optionsMask = 3; + OptionsBitmap optionsOverride = 4; + } + + request struct StopRequest { + OptionsBitmap optionsMask = 0; + OptionsBitmap optionsOverride = 1; + } + + request struct MoveToLevelWithOnOffRequest { + int8u level = 0; + nullable int16u transitionTime = 1; + OptionsBitmap optionsMask = 2; + OptionsBitmap optionsOverride = 3; + } + + request struct MoveWithOnOffRequest { + MoveModeEnum moveMode = 0; + nullable int8u rate = 1; + OptionsBitmap optionsMask = 2; + OptionsBitmap optionsOverride = 3; + } + + request struct StepWithOnOffRequest { + StepModeEnum stepMode = 0; + int8u stepSize = 1; + nullable int16u transitionTime = 2; + OptionsBitmap optionsMask = 3; + OptionsBitmap optionsOverride = 4; + } + + request struct StopWithOnOffRequest { + OptionsBitmap optionsMask = 0; + OptionsBitmap optionsOverride = 1; + } + + request struct MoveToClosestFrequencyRequest { + int16u frequency = 0; + } + + /** Command description for MoveToLevel */ + command MoveToLevel(MoveToLevelRequest): DefaultSuccess = 0; + /** Command description for Move */ + command Move(MoveRequest): DefaultSuccess = 1; + /** Command description for Step */ + command Step(StepRequest): DefaultSuccess = 2; + /** Command description for Stop */ + command Stop(StopRequest): DefaultSuccess = 3; + /** Command description for MoveToLevelWithOnOff */ + command MoveToLevelWithOnOff(MoveToLevelWithOnOffRequest): DefaultSuccess = 4; + /** Command description for MoveWithOnOff */ + command MoveWithOnOff(MoveWithOnOffRequest): DefaultSuccess = 5; + /** Command description for StepWithOnOff */ + command StepWithOnOff(StepWithOnOffRequest): DefaultSuccess = 6; + /** Command description for StopWithOnOff */ + command StopWithOnOff(StopWithOnOffRequest): DefaultSuccess = 7; + /** Change the currrent frequency to the provided one, or a close + approximation if the exact provided one is not possible. */ + command MoveToClosestFrequency(MoveToClosestFrequencyRequest): DefaultSuccess = 8; +} + /** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ cluster Descriptor = 29 { revision 2; @@ -449,50 +624,6 @@ cluster LocalizationConfiguration = 43 { readonly attribute int16u clusterRevision = 65533; } -/** Nodes should be expected to be deployed to any and all regions of the world. These global regions - may have differing preferences for how dates and times are conveyed. As such, Nodes that visually - or audibly convey time information need a mechanism by which they can be configured to use a - user’s preferred format. */ -cluster TimeFormatLocalization = 44 { - revision 1; // NOTE: Default/not specifically set - - enum CalendarTypeEnum : enum8 { - kBuddhist = 0; - kChinese = 1; - kCoptic = 2; - kEthiopian = 3; - kGregorian = 4; - kHebrew = 5; - kIndian = 6; - kIslamic = 7; - kJapanese = 8; - kKorean = 9; - kPersian = 10; - kTaiwanese = 11; - kUseActiveLocale = 255; - } - - enum HourFormatEnum : enum8 { - k12hr = 0; - k24hr = 1; - kUseActiveLocale = 255; - } - - bitmap Feature : bitmap32 { - kCalendarFormat = 0x1; - } - - attribute access(write: manage) HourFormatEnum hourFormat = 0; - attribute access(write: manage) optional CalendarTypeEnum activeCalendarType = 1; - readonly attribute optional CalendarTypeEnum supportedCalendarTypes[] = 2; - 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; -} - /** This cluster is used to manage global aspects of the Commissioning flow. */ cluster GeneralCommissioning = 48 { revision 1; // NOTE: Default/not specifically set @@ -1942,14 +2073,6 @@ endpoint 0 { ram attribute clusterRevision default = 1; } - server cluster TimeFormatLocalization { - persist attribute hourFormat default = 0; - persist attribute activeCalendarType default = 0; - callback attribute supportedCalendarTypes; - ram attribute featureMap default = 0; - ram attribute clusterRevision default = 1; - } - server cluster GeneralCommissioning { ram attribute breadcrumb default = 0x0000000000000000; callback attribute basicCommissioningInfo; @@ -2031,7 +2154,7 @@ endpoint 0 { callback attribute windowStatus; callback attribute adminFabricIndex; callback attribute adminVendorId; - ram attribute featureMap default = 0; + ram attribute featureMap default = 1; ram attribute clusterRevision default = 0x0001; handle command OpenCommissioningWindow; @@ -2096,7 +2219,7 @@ endpoint 1 { callback attribute eventList; callback attribute attributeList; ram attribute featureMap default = 0; - ram attribute clusterRevision default = 4; + ram attribute clusterRevision default = 6; handle command Off; handle command On; @@ -2117,6 +2240,7 @@ endpoint 1 { } server cluster WakeOnLan { + ram attribute MACAddress; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -2143,7 +2267,9 @@ endpoint 1 { } server cluster TargetNavigator { + emits event TargetUpdated; callback attribute targetList; + ram attribute currentTarget default = 0; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -2156,18 +2282,33 @@ endpoint 1 { } server cluster MediaPlayback { + emits event StateChanged; ram attribute currentState default = 0x00; + ram attribute startTime default = 0x00; + ram attribute duration default = 0; + callback attribute sampledPosition; + ram attribute playbackSpeed default = 0; + ram attribute seekRangeEnd; + ram attribute seekRangeStart; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; callback attribute attributeList; - ram attribute featureMap default = 0; + ram attribute featureMap default = 3; ram attribute clusterRevision default = 1; handle command Play; handle command Pause; handle command Stop; + handle command StartOver; + handle command Previous; + handle command Next; + handle command Rewind; + handle command FastForward; + handle command SkipForward; + handle command SkipBackward; handle command PlaybackResponse; + handle command Seek; } server cluster MediaInput { @@ -2177,12 +2318,13 @@ endpoint 1 { callback attribute acceptedCommandList; callback attribute eventList; callback attribute attributeList; - ram attribute featureMap default = 0; + ram attribute featureMap default = 1; ram attribute clusterRevision default = 1; handle command SelectInput; handle command ShowInputStatus; handle command HideInputStatus; + handle command RenameInput; } server cluster LowPower { @@ -2201,7 +2343,7 @@ endpoint 1 { callback attribute acceptedCommandList; callback attribute eventList; callback attribute attributeList; - ram attribute featureMap default = 0; + ram attribute featureMap default = 7; ram attribute clusterRevision default = 1; handle command SendKey; @@ -2215,10 +2357,79 @@ endpoint 1 { callback attribute acceptedCommandList; callback attribute eventList; callback attribute attributeList; - ram attribute featureMap default = 0; + ram attribute featureMap default = 1; ram attribute clusterRevision default = 1; handle command SelectOutput; + handle command RenameOutput; + } +} +endpoint 2 { + device type ma_speaker = 34, version 1; + + + server cluster Identify { + ram attribute identifyTime default = 0x0; + ram attribute identifyType default = 0x00; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command Identify; + handle command TriggerEffect; + } + + server cluster OnOff { + ram attribute onOff default = 0; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 6; + + handle command Off; + handle command On; + handle command Toggle; + } + + server cluster LevelControl { + ram attribute currentLevel default = 0x00; + ram attribute minLevel default = 0x00; + ram attribute maxLevel default = 0xFE; + ram attribute options default = 0x00; + ram attribute onLevel default = 0xFE; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 5; + + handle command MoveToLevel; + handle command Move; + handle command Step; + handle command Stop; + handle command MoveToLevelWithOnOff; + handle command MoveWithOnOff; + handle command StepWithOnOff; + handle command StopWithOnOff; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; } } diff --git a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.zap b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.zap index 245f7ee38016e5..92cb592ebd3407 100644 --- a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.zap +++ b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.zap @@ -1002,96 +1002,6 @@ } ] }, - { - "name": "Time Format Localization", - "code": 44, - "mfgCode": null, - "define": "TIME_FORMAT_LOCALIZATION_CLUSTER", - "side": "server", - "enabled": 1, - "attributes": [ - { - "name": "HourFormat", - "code": 0, - "mfgCode": null, - "side": "server", - "type": "HourFormatEnum", - "included": 1, - "storageOption": "NVM", - "singleton": 0, - "bounded": 0, - "defaultValue": "0", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "ActiveCalendarType", - "code": 1, - "mfgCode": null, - "side": "server", - "type": "CalendarTypeEnum", - "included": 1, - "storageOption": "NVM", - "singleton": 0, - "bounded": 0, - "defaultValue": "0", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "SupportedCalendarTypes", - "code": 2, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "FeatureMap", - "code": 65532, - "mfgCode": null, - "side": "server", - "type": "bitmap32", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "0", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "ClusterRevision", - "code": 65533, - "mfgCode": null, - "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "1", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - } - ] - }, { "name": "General Commissioning", "code": 48, @@ -1989,7 +1899,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "1", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2632,7 +2542,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "4", + "defaultValue": "6", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2818,6 +2728,22 @@ "side": "server", "enabled": 1, "attributes": [ + { + "name": "MACAddress", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "GeneratedCommandList", "code": 65528, @@ -3146,6 +3072,22 @@ "maxInterval": 65534, "reportableChange": 0 }, + { + "name": "CurrentTarget", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "GeneratedCommandList", "code": 65528, @@ -3242,6 +3184,15 @@ "maxInterval": 65534, "reportableChange": 0 } + ], + "events": [ + { + "name": "TargetUpdated", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + } ] }, { @@ -3276,6 +3227,62 @@ "isIncoming": 1, "isEnabled": 1 }, + { + "name": "StartOver", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "Previous", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "Next", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "Rewind", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "FastForward", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SkipForward", + "code": 8, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SkipBackward", + "code": 9, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, { "name": "PlaybackResponse", "code": 10, @@ -3283,6 +3290,14 @@ "source": "server", "isIncoming": 0, "isEnabled": 1 + }, + { + "name": "Seek", + "code": 11, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 } ], "attributes": [ @@ -3303,43 +3318,43 @@ "reportableChange": 0 }, { - "name": "GeneratedCommandList", - "code": 65528, + "name": "StartTime", + "code": 1, "mfgCode": null, "side": "server", - "type": "array", + "type": "epoch_us", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "0x00", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "AcceptedCommandList", - "code": 65529, + "name": "Duration", + "code": 2, "mfgCode": null, "side": "server", - "type": "array", + "type": "int64u", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "SampledPosition", + "code": 3, "mfgCode": null, "side": "server", - "type": "array", + "type": "PlaybackPositionStruct", "included": 1, "storageOption": "External", "singleton": 0, @@ -3351,74 +3366,179 @@ "reportableChange": 0 }, { - "name": "AttributeList", - "code": 65531, + "name": "PlaybackSpeed", + "code": 4, "mfgCode": null, "side": "server", - "type": "array", + "type": "single", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "FeatureMap", - "code": 65532, + "name": "SeekRangeEnd", + "code": 5, "mfgCode": null, "side": "server", - "type": "bitmap32", + "type": "int64u", "included": 1, "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "ClusterRevision", - "code": 65533, + "name": "SeekRangeStart", + "code": 6, "mfgCode": null, "side": "server", - "type": "int16u", + "type": "int64u", "included": 1, "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": "", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 - } - ] - }, - { - "name": "Media Input", - "code": 1287, - "mfgCode": null, - "define": "MEDIA_INPUT_CLUSTER", - "side": "server", - "enabled": 1, - "commands": [ + }, { - "name": "SelectInput", - "code": 0, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "ShowInputStatus", - "code": 1, + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "StateChanged", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Media Input", + "code": 1287, + "mfgCode": null, + "define": "MEDIA_INPUT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "SelectInput", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ShowInputStatus", + "code": 1, "mfgCode": null, "source": "client", "isIncoming": 1, @@ -3431,6 +3551,14 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RenameInput", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 } ], "attributes": [ @@ -3540,7 +3668,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "1", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3780,7 +3908,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "7", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3819,6 +3947,14 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RenameOutput", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 } ], "attributes": [ @@ -3928,7 +4064,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "1", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3953,21 +4089,783 @@ ] } ] - } - ], - "endpoints": [ - { - "endpointTypeName": "MA-rootdevice", - "endpointTypeIndex": 0, - "profileId": 259, - "endpointId": 0, - "networkId": 0 }, { - "endpointTypeName": "Anonymous Endpoint Type", - "endpointTypeIndex": 1, - "profileId": 259, - "endpointId": 1, + "id": 3, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 34, + "profileId": 259, + "label": "MA-speaker", + "name": "MA-speaker" + }, + "deviceTypes": [ + { + "code": 34, + "profileId": 259, + "label": "MA-speaker", + "name": "MA-speaker" + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 34 + ], + "deviceTypeName": "MA-speaker", + "deviceTypeCode": 34, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "On/Off", + "code": 6, + "mfgCode": null, + "define": "ON_OFF_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Off", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "On", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "Toggle", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "OnOff", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "6", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Level Control", + "code": 8, + "mfgCode": null, + "define": "LEVEL_CONTROL_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "MoveToLevel", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "Move", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "Step", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "Stop", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "MoveToLevelWithOnOff", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "MoveWithOnOff", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StepWithOnOff", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StopWithOnOff", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "CurrentLevel", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinLevel", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxLevel", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFE", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Options", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "OptionsBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OnLevel", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFE", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + } + ], + "endpoints": [ + { + "endpointTypeName": "MA-rootdevice", + "endpointTypeIndex": 0, + "profileId": 259, + "endpointId": 0, + "networkId": 0 + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 1, + "profileId": 259, + "endpointId": 1, + "networkId": 0 + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 2, + "profileId": 259, + "endpointId": 2, "networkId": 0 } ] diff --git a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter index 71d511aedcc508..097015b4634695 100644 --- a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter +++ b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter @@ -1286,7 +1286,7 @@ cluster FixedLabel = 64 { } /** An interface for controlling a fan in a heating/cooling system. */ -provisional cluster FanControl = 514 { +cluster FanControl = 514 { revision 4; enum AirflowDirectionEnum : enum8 { diff --git a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter index d1aee2ea4e8135..bcef3bca0f1b1e 100644 --- a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter +++ b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter @@ -1875,7 +1875,7 @@ cluster Thermostat = 513 { } /** An interface for controlling a fan in a heating/cooling system. */ -provisional cluster FanControl = 514 { +cluster FanControl = 514 { revision 4; enum AirflowDirectionEnum : enum8 { diff --git a/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter b/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter index de4a1c961cd506..0aa08d68385f6d 100644 --- a/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter +++ b/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter @@ -1458,7 +1458,7 @@ cluster Thermostat = 513 { } /** An interface for controlling a fan in a heating/cooling system. */ -provisional cluster FanControl = 514 { +cluster FanControl = 514 { revision 4; enum AirflowDirectionEnum : enum8 { diff --git a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter index fdefbfc5c9dbee..ce01f50bd303e7 100644 --- a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter +++ b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter @@ -1678,7 +1678,7 @@ cluster Thermostat = 513 { } /** An interface for controlling a fan in a heating/cooling system. */ -provisional cluster FanControl = 514 { +cluster FanControl = 514 { revision 4; enum AirflowDirectionEnum : enum8 { diff --git a/examples/chef/esp32/main/CMakeLists.txt b/examples/chef/esp32/main/CMakeLists.txt index e6ab518f3494a9..8278cf9a735675 100644 --- a/examples/chef/esp32/main/CMakeLists.txt +++ b/examples/chef/esp32/main/CMakeLists.txt @@ -33,6 +33,7 @@ set(PRIV_INCLUDE_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/third_party/nlio/repo/include" "${CMAKE_SOURCE_DIR}/../" "${CMAKE_SOURCE_DIR}/../common" + "${CMAKE_SOURCE_DIR}/../common/clusters" "${CMAKE_SOURCE_DIR}/main/include/" ) @@ -62,6 +63,14 @@ set(SRC_DIRS_LIST ${SRC_DIRS_LIST} "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_SOURCE_DIR}/../common" + "${CMAKE_SOURCE_DIR}/../common/clusters/media-input/" + "${CMAKE_SOURCE_DIR}/../common/clusters/low-power/" + "${CMAKE_SOURCE_DIR}/../common/clusters/media-playback/" + "${CMAKE_SOURCE_DIR}/../common/clusters/target-navigator/" + "${CMAKE_SOURCE_DIR}/../common/clusters/wake-on-lan/" + "${CMAKE_SOURCE_DIR}/../common/clusters/channel/" + "${CMAKE_SOURCE_DIR}/../common/clusters/keypad-input/" + "${CMAKE_SOURCE_DIR}/../common/clusters/audio-output/" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/zzz_generated/app-common/app-common/zap-generated/attributes" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/util" diff --git a/examples/chef/linux/BUILD.gn b/examples/chef/linux/BUILD.gn index a25c1f5ffa11ce..a119f832e051db 100644 --- a/examples/chef/linux/BUILD.gn +++ b/examples/chef/linux/BUILD.gn @@ -43,12 +43,19 @@ chip_data_model("chef-data-model") { executable("${sample_name}") { sources = [ "${project_dir}/common/chef-air-quality.cpp", - "${project_dir}/common/chef-channel-manager.cpp", "${project_dir}/common/chef-concentration-measurement.cpp", "${project_dir}/common/chef-fan-control-manager.cpp", "${project_dir}/common/chef-resource-monitoring-delegates.cpp", "${project_dir}/common/chef-rvc-mode-delegate.cpp", "${project_dir}/common/chef-rvc-operational-state-delegate.cpp", + "${project_dir}/common/clusters/audio-output/AudioOutputManager.cpp", + "${project_dir}/common/clusters/channel/ChannelManager.cpp", + "${project_dir}/common/clusters/keypad-input/KeypadInputManager.cpp", + "${project_dir}/common/clusters/low-power/LowPowerManager.cpp", + "${project_dir}/common/clusters/media-input/MediaInputManager.cpp", + "${project_dir}/common/clusters/media-playback/MediaPlaybackManager.cpp", + "${project_dir}/common/clusters/target-navigator/TargetNavigatorManager.cpp", + "${project_dir}/common/clusters/wake-on-lan/WakeOnLanManager.cpp", "${project_dir}/common/stubs.cpp", "${project_dir}/linux/main.cpp", ] @@ -63,6 +70,7 @@ executable("${sample_name}") { include_dirs = [ "include", "${project_dir}/common", + "${project_dir}/common/clusters", ] if (chip_enable_pw_rpc) { diff --git a/examples/chef/nrfconnect/CMakeLists.txt b/examples/chef/nrfconnect/CMakeLists.txt index 17556ef398b27a..0a408e829dd04f 100644 --- a/examples/chef/nrfconnect/CMakeLists.txt +++ b/examples/chef/nrfconnect/CMakeLists.txt @@ -60,6 +60,7 @@ target_include_directories(app PRIVATE ${GEN_DIR} ${CHEF} ${CHEF}/common + ${CHEF}/common/clusters/ ${GEN_DIR}/../ ${CHIP_ROOT}/src ${CHIP_ROOT}/examples/shell/shell_common/include @@ -81,12 +82,19 @@ endif() target_sources(app PRIVATE ${CHEF}/common/chef-air-quality.cpp - ${CHEF}/common/chef-channel-manager.cpp ${CHEF}/common/chef-concentration-measurement.cpp ${CHEF}/common/chef-fan-control-manager.cpp ${CHEF}/common/chef-resource-monitoring-delegates.cpp ${CHEF}/common/chef-rvc-mode-delegate.cpp ${CHEF}/common/chef-rvc-operational-state-delegate.cpp + ${CHEF}/common/clusters/media-input/MediaInputManager.cpp + ${CHEF}/common/clusters/low-power/LowPowerManager.cpp + ${CHEF}/common/clusters/media-playback/MediaPlaybackManager.cpp + ${CHEF}/common/clusters/target-navigator/TargetNavigatorManager.cpp + ${CHEF}/common/clusters/wake-on-lan/WakeOnLanManager.cpp + ${CHEF}/common/clusters/channel/ChannelManager.cpp + ${CHEF}/common/clusters/keypad-input/KeypadInputManager.cpp + ${CHEF}/common/clusters/audio-output/AudioOutputManager.cpp ${CHEF}/common/stubs.cpp ${CHEF}/nrfconnect/main.cpp ) diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.matter b/examples/energy-management-app/energy-management-common/energy-management-app.matter index c56280b2b72f08..1cedefb6c1e43c 100644 --- a/examples/energy-management-app/energy-management-common/energy-management-app.matter +++ b/examples/energy-management-app/energy-management-common/energy-management-app.matter @@ -1770,6 +1770,7 @@ endpoint 0 { ram attribute lastNetworkingStatus; ram attribute lastNetworkID; ram attribute lastConnectErrorValue; + callback attribute supportedWiFiBands; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.zap b/examples/energy-management-app/energy-management-common/energy-management-app.zap index d795b4fd482448..88514f105c37f1 100644 --- a/examples/energy-management-app/energy-management-common/energy-management-app.zap +++ b/examples/energy-management-app/energy-management-common/energy-management-app.zap @@ -1452,6 +1452,22 @@ "maxInterval": 65534, "reportableChange": 0 }, + { + "name": "SupportedWiFiBands", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "GeneratedCommandList", "code": 65528, diff --git a/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp b/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp index dc60d748958894..99619fc95b5fb0 100644 --- a/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp +++ b/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp @@ -1474,7 +1474,11 @@ CHIP_ERROR GetEpochTS(uint32_t & chipEpoch) * This should not be certifiable since getting time is a Mandatory * feature of EVSE Cluster */ - VerifyOrDie(err != CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + if (err == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE) + { + ChipLogError(Zcl, "Platform does not support GetClock_RealTimeMS. Check EVSE certification requirements!"); + return err; + } if (err != CHIP_NO_ERROR) { diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImReadCommand.kt b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImReadCommand.kt index e0a95d584130eb..1758fbd868fbfb 100644 --- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImReadCommand.kt +++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImReadCommand.kt @@ -67,13 +67,12 @@ class PairOnNetworkLongImReadCommand( } fun checkUnitTestClusterGeneralStatus(status: Status): Boolean = - (status.getStatus() == CLUSTER_ID_TEST_GENERAL_ERROR_STATUS) && - !status.getClusterStatus().isPresent() + (status.getStatus() == Status.Code.InvalidDataType) && !status.getClusterStatus().isPresent() fun checkUnitTestClusterClusterStatus(status: Status): Boolean = - (status.getStatus() == CLUSTER_ID_TEST_CLUSTER_ERROR_STATUS) && + (status.getStatus() == Status.Code.Failure) && status.getClusterStatus().isPresent() && - status.getClusterStatus().get() == CLUSTER_ID_TEST_CLUSTER_ERROR_CLUSTER_STATUS + (status.getClusterStatus().get() == CLUSTER_ID_TEST_CLUSTER_ERROR_CLUSTER_STATUS) private fun validateResponse(nodeState: NodeState) { val endpointZero = @@ -243,8 +242,6 @@ class PairOnNetworkLongImReadCommand( private const val CLUSTER_ID_BASIC_VERSION = 0L private const val CLUSTER_ID_TEST_GENERAL_ERROR_BOOLEAN = 0x0031L private const val CLUSTER_ID_TEST_CLUSTER_ERROR_BOOLEAN = 0x0032L - private const val CLUSTER_ID_TEST_GENERAL_ERROR_STATUS = 0x8d - private const val CLUSTER_ID_TEST_CLUSTER_ERROR_STATUS = 1 private const val CLUSTER_ID_TEST_CLUSTER_ERROR_CLUSTER_STATUS = 17 } } diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImWriteCommand.kt b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImWriteCommand.kt index 3e90935d22268e..fdb74c5d065b5c 100644 --- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImWriteCommand.kt +++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImWriteCommand.kt @@ -22,6 +22,7 @@ import chip.devicecontroller.GetConnectedDeviceCallbackJni.GetConnectedDeviceCal import chip.devicecontroller.WriteAttributesCallback import chip.devicecontroller.model.AttributeWriteRequest import chip.devicecontroller.model.ChipAttributePath +import chip.devicecontroller.model.Status import com.matter.controller.commands.common.CredentialsIssuer import java.util.logging.Level import java.util.logging.Logger @@ -51,11 +52,8 @@ class PairOnNetworkLongImWriteCommand( setFailure("write failure") } - override fun onResponse(attributePath: ChipAttributePath?) { - logger.log(Level.INFO, "Write receive OnResponse on ") - if (attributePath != null) { - logger.log(Level.INFO, attributePath.toString()) - } + override fun onResponse(attributePath: ChipAttributePath, status: Status) { + logger.log(Level.INFO, "$attributePath : Write response: $status") setSuccess() } } diff --git a/examples/lit-icd-app/nrfconnect/.gitignore b/examples/lit-icd-app/nrfconnect/.gitignore new file mode 100644 index 00000000000000..84c048a73cc2e5 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/examples/lit-icd-app/nrfconnect/CMakeLists.txt b/examples/lit-icd-app/nrfconnect/CMakeLists.txt new file mode 100644 index 00000000000000..a9b921016670e7 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/CMakeLists.txt @@ -0,0 +1,66 @@ +# +# 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. +# +cmake_minimum_required(VERSION 3.13.1) + +get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/connectedhomeip REALPATH) +get_filename_component(NRFCONNECT_COMMON ${CHIP_ROOT}/examples/platform/nrfconnect REALPATH) +get_filename_component(GEN_DIR ${CHIP_ROOT}/zzz_generated/ REALPATH) + +include(${CHIP_ROOT}/config/nrfconnect/app/check-nrfconnect-version.cmake) + +# Set Kconfig root files that will be processed as a first Kconfig for used child images. +set(mcuboot_KCONFIG_ROOT ${CHIP_ROOT}/config/nrfconnect/chip-module/Kconfig.mcuboot.root) +set(multiprotocol_rpmsg_KCONFIG_ROOT ${CHIP_ROOT}/config/nrfconnect/chip-module/Kconfig.multiprotocol_rpmsg.root) + +if(NOT CONF_FILE STREQUAL "prj_no_dfu.conf") + set(PM_STATIC_YML_FILE ${CMAKE_CURRENT_SOURCE_DIR}/configuration/${BOARD}/pm_static_dfu.yml) +endif() + +list(APPEND ZEPHYR_EXTRA_MODULES ${CHIP_ROOT}/config/nrfconnect/chip-module) +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) + +# -Wmaybe-uninitialized has too many false positives, including on std::optional +# and chip::Optional. Make it nonfatal. +# +# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635 +target_compile_options(app PRIVATE -Werror -Wno-error=maybe-uninitialized) + +project(chip-nrfconnect-lit-icd-app-example) + +include(${CHIP_ROOT}/config/nrfconnect/app/enable-gnu-std.cmake) +include(${CHIP_ROOT}/config/nrfconnect/app/flashing.cmake) +include(${CHIP_ROOT}/src/app/chip_data_model.cmake) + +target_include_directories(app PRIVATE + main/include + ${GEN_DIR}/app-common + ${GEN_DIR}/lit-icd-app + ${NRFCONNECT_COMMON}/util/include + ${NRFCONNECT_COMMON}/app/include) + +target_sources(app PRIVATE + main/AppTask.cpp + main/main.cpp + ${NRFCONNECT_COMMON}/util/LEDWidget.cpp) + +chip_configure_data_model(app + INCLUDE_SERVER + ZAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../lit-icd-common/lit-icd-server-app.zap +) + +if(CONFIG_CHIP_OTA_REQUESTOR) + target_sources(app PRIVATE ${NRFCONNECT_COMMON}/util/OTAUtil.cpp) +endif() diff --git a/examples/lit-icd-app/nrfconnect/Kconfig b/examples/lit-icd-app/nrfconnect/Kconfig new file mode 100644 index 00000000000000..4d9501ac5cab90 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/Kconfig @@ -0,0 +1,41 @@ +# +# 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. +# +mainmenu "Matter nRF Connect LIT ICD Example Application" + +config STATE_LEDS + bool "Use LEDs to indicate the device state" + default y + help + Use LEDs to render the current state of the device such as the progress of commissioning of + the device into a network or the factory reset initiation. Note that setting this option to + 'n' does not disable the LED indicating the state of the simulated bolt. + +# Sample configuration used for Thread networking +if NET_L2_OPENTHREAD + +choice OPENTHREAD_NORDIC_LIBRARY_CONFIGURATION + default OPENTHREAD_NORDIC_LIBRARY_MTD +endchoice + +choice OPENTHREAD_DEVICE_TYPE + default OPENTHREAD_MTD +endchoice + +endif # NET_L2_OPENTHREAD + +rsource "../../../config/nrfconnect/chip-module/Kconfig.features" +rsource "../../../config/nrfconnect/chip-module/Kconfig.defaults" +source "Kconfig.zephyr" diff --git a/examples/lit-icd-app/nrfconnect/README.md b/examples/lit-icd-app/nrfconnect/README.md new file mode 100644 index 00000000000000..704950fdcac63e --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/README.md @@ -0,0 +1,401 @@ +# Matter nRF Connect LIT ICD Example Application + +The nRF Connect LIT ICD Example allows to test the device that utilizes Long +Idle Time feature from the Intermittently Connected Device Management cluster. +It uses buttons to change the device states and LEDs to show the state of these +changes. You can use this example as a reference for creating your own +application. + +Nordic Semiconductor logo +nRF52840 DK + +The example is based on +[Matter](https://github.com/project-chip/connectedhomeip) and Nordic +Semiconductor's nRF Connect SDK, and was created to facilitate testing and +certification of a Matter device communicating over a low-power, 802.15.4 Thread +network. + +The example behaves as a Matter accessory, that is a device that can be paired +into an existing Matter network and can be controlled by this network. + +
+ +## Overview + +This example is running on the nRF Connect platform, which is based on Nordic +Semiconductor's +[nRF Connect SDK](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/index.html) +and [Zephyr RTOS](https://zephyrproject.org/). Visit Matter's +[nRF Connect platform overview](../../../docs/guides/nrfconnect_platform_overview.md) +to read more about the platform structure and dependencies. + +By default, the Matter accessory device has IPv6 networking disabled. You must +pair it with the Matter controller over Bluetooth® LE to get the configuration +from the controller to use the device within a Thread network. You have to make +the device discoverable manually (for security reasons). See +[Bluetooth LE advertising](#bluetooth-le-advertising) to learn how to do this. +The controller must get the commissioning information from the Matter accessory +device and provision the device into the network. + +The sample uses buttons for changing the device states, and LEDs to show the +state of these changes. + +### Bluetooth LE advertising + +In this example, to commission the device onto a Matter network, it must be +discoverable over Bluetooth LE. For security reasons, you must start Bluetooth +LE advertising manually after powering up the device by pressing **Button 4**. + +### Bluetooth LE rendezvous + +In this example, the commissioning procedure is done over Bluetooth LE between a +Matter device and the Matter controller, where the controller has the +commissioner role. + +To start the rendezvous, the controller must get the commissioning information +from the Matter device. The data payload is encoded within a QR code, printed to +the UART console, and shared using an NFC tag. The emulation of the NFC tag +emulation starts automatically when Bluetooth LE advertising is started and +stays enabled until Bluetooth LE advertising timeout expires. + +#### Thread provisioning + +The provisioning operation, which is the Last part of the rendezvous procedure, +involves sending the Thread network credentials from the Matter controller to +the Matter device. As a result, the device joins the Thread network and can +communicate with other devices in the network. + +### Device Firmware Upgrade + +The example supports over-the-air (OTA) device firmware upgrade (DFU) using +Matter OTA mechanism, which is enabled by default. + +The +[MCUboot](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/mcuboot/index.html) +bootloader solution is used to replace the old firmware image with the new one. + +#### Matter Over-the-Air Update + +The Matter over-the-air update distinguishes two types of nodes: OTA Provider +and OTA Requestor. + +An OTA Provider is a node that hosts a new firmware image and is able to respond +on an OTA Requestor's queries regarding availability of new firmware images or +requests to start sending the update packages. + +An OTA Requestor is a node that wants to download a new firmware image and sends +requests to an OTA Provider to start the update process. + +#### Bootloader + +MCUboot is a secure bootloader used for swapping firmware images of different +versions and generating proper build output files that can be used in the device +firmware upgrade process. + +The bootloader solution requires an area of flash memory to swap application +images during the firmware upgrade. Nordic Semiconductor devices use an external +memory chip for this purpose. The memory chip communicates with the +microcontroller through the QSPI bus. + +See the +[Building with Device Firmware Upgrade support](#building-with-device-firmware-upgrade-support) +section to learn how to change MCUboot and flash configuration in this example. + +
+ +## Requirements + +The application requires a specific revision of the nRF Connect SDK to work +correctly. See [Setting up the environment](#setting-up-the-environment) for +more information. + +### Supported devices + +The example supports building and running on the following devices: + +| Hardware platform | Build target | Platform image | +| ----------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| [nRF52840 DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) | `nrf52840dk_nrf52840` |
nRF52840 DKnRF52840 DK
| +| [nRF5340 DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF5340-DK) | `nrf5340dk_nrf5340_cpuapp` |
nRF5340 DKnRF5340 DK
| + +
+ +## Device UI + +This section lists the User Interface elements that you can use to control and +monitor the state of the device. These correspond to PCB components on the +platform image. + +**LED 1** shows the overall state of the device and its connectivity. The +following states are possible: + +- _Short Flash On (50 ms on/950 ms off)_ — The device is in the + unprovisioned (unpaired) state and is waiting for a commissioning + application to connect. + +- _Rapid Even Flashing (100 ms on/100 ms off)_ — The device is in the + unprovisioned state and a commissioning application is connected through + Bluetooth LE. + +- _Short Flash Off (950ms on/50ms off)_ — The device is fully + provisioned, but does not yet have full connectivity for Thread network. + +- _Solid On_ — The device is fully provisioned. + +**LED 2** is used for the Identify feature purpose. The LED starts blinking +evenly (500 ms on/500 ms off) when the Identify command of the Identify cluster +is received on the endpoint 1. The command’s argument can be used to specify the +duration of the effect. + +**Button 1** Pressing the button for more than 3 s initiates the factory reset +of the device. Releasing the button within the 3-second window cancels the +factory reset procedure. + +**Button 3** Represents the User Active Mode Trigger feature from the +Intermittently Connected Devices Management cluster. Pressing it puts the ICD +device in the active mode and makes it responsive. + +**Button 4** Starts the NFC tag emulation, enables Bluetooth LE advertising for +the predefined period of time (15 minutes by default), and makes the device +discoverable over Bluetooth LE. This button is used during the commissioning +procedure. + +**SEGGER J-Link USB port** can be used to get logs from the device or +communicate with it using the +[command line interface](../../../docs/guides/nrfconnect_examples_cli.md). + +**NFC port with antenna attached** can be used to start the +[rendezvous](#bluetooth-le-rendezvous) by providing the commissioning +information from the Matter device in a data payload that can be shared using +NFC. + +
+ +## Setting up the environment + +Before building the example, check out the Matter repository and sync submodules +using the following command: + + $ python3 scripts/checkout_submodules.py --shallow --platform nrfconnect + +> **Note**: +> +> For Linux operating system install +> [SEGGER J-Link Software](https://www.segger.com/downloads/jlink/#J-LinkSoftwareAndDocumentationPack). + +### Install Command Line Tools + +With admin permissions enabled, download and install the +[nRF Command Line Tools](https://www.nordicsemi.com/Products/Development-tools/nrf-command-line-tools). + +### Install Toolchain Manager + +Toolchain Manager is available from +[nRF Connect for Desktop](https://www.nordicsemi.com/Products/Development-tools/nrf-connect-for-desktop), +a cross-platform tool that provides different applications that simplify +installing the nRF Connect SDK. Both the tool and the application are available +for Windows, Linux, and macOS. + +To install the Toolchain Manager app, complete the following steps: + +1. [Download nRF Connect for Desktop](https://www.nordicsemi.com/Products/Development-tools/nrf-connect-for-desktop/download#infotabs) + for your operating system. + +2. Install and run the tool on your machine. + +3. In the **APPS** section, click **Install** button on the Toolchain Manager + tab. + +### Install nRF Connect SDK + +Complete the following steps to install the nRF Connect SDK: + +1. Open Toolchain Manager in nRF Connect for Desktop. + +2. Click the **Install** button next to the + [recommended](../../../config/nrfconnect/.nrfconnect-recommended-revision) + version of the nRF Connect SDK. + +3. A pop-up window will inform you about the current installation directory. If + you want to change the directory, click the **Change directory** button. + Otherwise, click the **Continue installation** button. + +4. When the nRF Connect SDK is installed on your machine, the **Install** + button changes to the **Open VS Code** button. + +5. Click the dropdown menu next to the **Open VS Code** button for the + installed nRF Connect SDK version, and select **Open terminal**. + +6. Make sure that the nRF Connect SDK version is compatible with the Matter SDK + version: + + ``` + $ cd {connectedhomeip directory} + $ python3 scripts/setup/nrfconnect/update_ncs.py --update + ``` + +Now you can proceed with the [Building](#building) instruction. + +
+ +## Building + +Complete the following steps to build the sample: + +1. Navigate to the example's directory: + + $ cd examples/lit-icd-app/nrfconnect + +2. Run the following command to build the example, with _build-target_ replaced + with the build target name of the Nordic Semiconductor's kit you own, for + example `nrf52840dk_nrf52840`: + + $ west build -b build-target + + You only need to specify the build target on the first build. See + [Requirements](#requirements) for the build target names of compatible kits. + +The output `zephyr.hex` file will be available in the `build/zephyr/` directory. + +### Removing build artifacts + +If you're planning to build the example for a different kit or make changes to +the configuration, remove all build artifacts before building. To do so, use the +following command: + + $ rm -r build + +### Building with release configuration + +To build the example with release configuration that disables the diagnostic +features like logs and command-line interface, run the following command: + + $ west build -b build-target -- -DCONF_FILE=prj_release.conf + +Remember to replace _build-target_ with the build target name of the Nordic +Semiconductor's kit you own. + +### Building with Device Firmware Upgrade support + +Support for DFU using Matter OTA is enabled by default. + +To completely disable support for DFU, run the following command with +_build-target_ replaced with the build target name of the Nordic Semiconductor +kit you are using (for example `nrf52840dk_nrf52840`): + + $ west build -b build-target -- -DCONF_FILE=prj_no_dfu.conf + +> **Note**: +> +> There are two types of Device Firmware Upgrade modes: single-image DFU and +> multi-image DFU. Single-image mode supports upgrading only one firmware image, +> the application image, and should be used for single-core nRF52840 DK devices. +> Multi-image mode allows to upgrade more firmware images and is suitable for +> upgrading the application core and network core firmware in two-core nRF5340 +> DK devices. + +#### Changing bootloader configuration + +To change the default MCUboot configuration, edit the `prj.conf` file located in +the `child_image/mcuboot` directory. + +Make sure to keep the configuration consistent with changes made to the +application configuration. This is necessary for the configuration to work, as +the bootloader image is a separate application from the user application and it +has its own configuration file. + +#### Changing flash memory settings + +In the default configuration, the MCUboot uses the +[Partition Manager](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/scripts/partition_manager/partition_manager.html#partition-manager) +to configure flash partitions used for the bootloader application image slot +purposes. You can change these settings by defining +[static partitions](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/scripts/partition_manager/partition_manager.html#ug-pm-static). +This example uses this option to define using an external flash. + +To modify the flash settings of your board (that is, your _build-target_, for +example `nrf52840dk_nrf52840`), edit the `pm_static_dfu.yml` file located in the +`configuration/build-target/` directory. + +
+ +## Configuring the example + +The Zephyr ecosystem is based on Kconfig files and the settings can be modified +using the menuconfig utility. + +To open the menuconfig utility, run the following command from the example +directory: + + $ west build -b build-target -t menuconfig + +Remember to replace _build-target_ with the build target name of the Nordic +Semiconductor's kit you own. + +Changes done with menuconfig will be lost if the `build` directory is deleted. +To make them persistent, save the configuration options in the `prj.conf` file. + +### Example build types + +The example uses different configuration files depending on the supported +features. Configuration files are provided for different build types and they +are located in the application root directory. + +The `prj.conf` file represents a debug build type. Other build types are covered +by dedicated files with the build type added as a suffix to the prj part, as per +the following list. For example, the release build type file name is +`prj_release.conf`. If a board has other configuration files, for example +associated with partition layout or child image configuration, these follow the +same pattern. + +Before you start testing the application, you can select one of the build types +supported by the sample. This sample supports the following build types, +depending on the selected board: + +- debug -- Debug version of the application - can be used to enable additional + features for verifying the application behavior, such as logs or + command-line shell. +- release -- Release version of the application - can be used to enable only + the necessary application functionalities to optimize its performance. +- no_dfu -- Debug version of the application without Device Firmware Upgrade + feature support. + +For more information, see the +[Configuring nRF Connect SDK examples](../../../docs/guides/nrfconnect_examples_configuration.md) +page. + +
+ +## Flashing and debugging + +To flash the application to the device, use the west tool and run the following +command from the example directory: + + $ west flash --erase + +If you have multiple development kits connected, west will prompt you to pick +the correct one. + +To debug the application on target, run the following command from the example +directory: + + $ west debug + +
+ +## Testing the example + +Check the [CLI tutorial](../../../docs/guides/nrfconnect_examples_cli.md) to +learn how to use command-line interface of the application. + +### Testing using Linux CHIPTool + +Read the [CHIP Tool user guide](../../../docs/guides/chip_tool_guide.md) to see +how to use [CHIP Tool for Linux or mac OS](../../chip-tool/README.md) to +commission and control the application within a Matter-enabled Thread network. + +### Testing Device Firmware Upgrade + +Read the +[DFU tutorial](../../../docs/guides/nrfconnect_examples_software_update.md) to +see how to upgrade your device firmware. diff --git a/examples/lit-icd-app/nrfconnect/boards/nrf52840dk_nrf52840.overlay b/examples/lit-icd-app/nrfconnect/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 00000000000000..7babe0424821ba --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,54 @@ +/* + * 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. + */ + +/ { + chosen { + nordic,pm-ext-flash = &mx25r64; + }; + + /* + * In some default configurations within the nRF Connect SDK, + * e.g. on nRF52840, the chosen zephyr,entropy node is &cryptocell. + * This devicetree overlay ensures that default is overridden wherever it + * is set, as this application uses the RNG node for entropy exclusively. + */ + chosen { + zephyr,entropy = &rng; + }; +}; + +/* Disable unused peripherals to reduce power consumption */ +&adc { + status = "disabled"; +}; +&uart1 { + status = "disabled"; +}; +&i2c0 { + status = "disabled"; +}; +&pwm0 { + status = "disabled"; +}; +&spi1 { + status = "disabled"; +}; +&spi3 { + status = "disabled"; +}; +&usbd { + status = "disabled"; +}; diff --git a/examples/lit-icd-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay b/examples/lit-icd-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000000..12155ffcd1f509 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#include + +/ { + chosen { + nordic,pm-ext-flash = &mx25r64; + }; +}; + +/* Set IPC thread priority to the highest value to not collide with other threads. */ +&ipc0 { + zephyr,priority = <0 PRIO_COOP>; +}; + +/* Disable unused peripherals to reduce power consumption */ +&adc { + status = "disabled"; +}; +&i2c1 { + status = "disabled"; +}; +&pwm0 { + status = "disabled"; +}; +&spi2 { + status = "disabled"; +}; +&usbd { + status = "disabled"; +}; diff --git a/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf52840dk_nrf52840.overlay b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 00000000000000..9f9128c6beff60 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/ { + chosen { + nordic,pm-ext-flash = &mx25r64; + }; +}; diff --git a/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf52840dk_nrf52840_release.overlay b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf52840dk_nrf52840_release.overlay new file mode 100644 index 00000000000000..9f9128c6beff60 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf52840dk_nrf52840_release.overlay @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/ { + chosen { + nordic,pm-ext-flash = &mx25r64; + }; +}; diff --git a/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf5340dk_nrf5340_cpuapp.overlay b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000000..50069180506973 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,20 @@ +/* + * 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. + */ +/ { + chosen { + nordic,pm-ext-flash = &mx25r64; + }; +}; diff --git a/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf5340dk_nrf5340_cpuapp_release.overlay b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf5340dk_nrf5340_cpuapp_release.overlay new file mode 100644 index 00000000000000..9f9128c6beff60 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/boards/nrf5340dk_nrf5340_cpuapp_release.overlay @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/ { + chosen { + nordic,pm-ext-flash = &mx25r64; + }; +}; diff --git a/examples/lit-icd-app/nrfconnect/child_image/mcuboot/prj.conf b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/prj.conf new file mode 100644 index 00000000000000..3f43b733b4bb96 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/prj.conf @@ -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. +# + +# This target uses Kconfig.mcuboot.defaults to set options common for all +# samples using mcuboot. This file should contain only options specific for this sample +# mcuboot configuration or overrides of default values. + +CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h" + +# Bootloader size optimization +# Disable not used modules that cannot be set in Kconfig.mcuboot.defaults due to overriding +# in board files. +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_USE_SEGGER_RTT=n +CONFIG_GPIO=n diff --git a/examples/lit-icd-app/nrfconnect/child_image/mcuboot/prj_release.conf b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/prj_release.conf new file mode 100644 index 00000000000000..3f43b733b4bb96 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/child_image/mcuboot/prj_release.conf @@ -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. +# + +# This target uses Kconfig.mcuboot.defaults to set options common for all +# samples using mcuboot. This file should contain only options specific for this sample +# mcuboot configuration or overrides of default values. + +CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h" + +# Bootloader size optimization +# Disable not used modules that cannot be set in Kconfig.mcuboot.defaults due to overriding +# in board files. +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_USE_SEGGER_RTT=n +CONFIG_GPIO=n diff --git a/examples/lit-icd-app/nrfconnect/child_image/multiprotocol_rpmsg/prj.conf b/examples/lit-icd-app/nrfconnect/child_image/multiprotocol_rpmsg/prj.conf new file mode 100644 index 00000000000000..48deaa9fa18135 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/child_image/multiprotocol_rpmsg/prj.conf @@ -0,0 +1,25 @@ +# +# 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. +# + +# This target uses Kconfig.multiprotocol_rpmsg.defaults to set options common for all +# samples using multiprotocol_rpmsg. This file should contain only options specific for this sample +# multiprotocol_rpmsg configuration or overrides of default values. + +# Disable not used modules that cannot be set in Kconfig.multiprotocol_rpmsg.defaults due to overriding +# in board files. + +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n diff --git a/examples/lit-icd-app/nrfconnect/child_image/multiprotocol_rpmsg/prj_no_dfu.conf b/examples/lit-icd-app/nrfconnect/child_image/multiprotocol_rpmsg/prj_no_dfu.conf new file mode 100644 index 00000000000000..48deaa9fa18135 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/child_image/multiprotocol_rpmsg/prj_no_dfu.conf @@ -0,0 +1,25 @@ +# +# 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. +# + +# This target uses Kconfig.multiprotocol_rpmsg.defaults to set options common for all +# samples using multiprotocol_rpmsg. This file should contain only options specific for this sample +# multiprotocol_rpmsg configuration or overrides of default values. + +# Disable not used modules that cannot be set in Kconfig.multiprotocol_rpmsg.defaults due to overriding +# in board files. + +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n diff --git a/examples/lit-icd-app/nrfconnect/child_image/multiprotocol_rpmsg/prj_release.conf b/examples/lit-icd-app/nrfconnect/child_image/multiprotocol_rpmsg/prj_release.conf new file mode 100644 index 00000000000000..48deaa9fa18135 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/child_image/multiprotocol_rpmsg/prj_release.conf @@ -0,0 +1,25 @@ +# +# 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. +# + +# This target uses Kconfig.multiprotocol_rpmsg.defaults to set options common for all +# samples using multiprotocol_rpmsg. This file should contain only options specific for this sample +# multiprotocol_rpmsg configuration or overrides of default values. + +# Disable not used modules that cannot be set in Kconfig.multiprotocol_rpmsg.defaults due to overriding +# in board files. + +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n diff --git a/examples/lit-icd-app/nrfconnect/configuration/nrf52840dk_nrf52840/pm_static_dfu.yml b/examples/lit-icd-app/nrfconnect/configuration/nrf52840dk_nrf52840/pm_static_dfu.yml new file mode 100644 index 00000000000000..ce42b39e55ee87 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/configuration/nrf52840dk_nrf52840/pm_static_dfu.yml @@ -0,0 +1,42 @@ +mcuboot: + address: 0x0 + size: 0x7000 + region: flash_primary +mcuboot_pad: + address: 0x7000 + size: 0x200 +app: + address: 0x7200 + size: 0xf3e00 +mcuboot_primary: + orig_span: &id001 + - mcuboot_pad + - app + span: *id001 + address: 0x7000 + size: 0xf4000 + region: flash_primary +mcuboot_primary_app: + orig_span: &id002 + - app + span: *id002 + address: 0x7200 + size: 0xf3e00 +factory_data: + address: 0xfb000 + size: 0x1000 + region: flash_primary +settings_storage: + address: 0xfc000 + size: 0x4000 + region: flash_primary +mcuboot_secondary: + address: 0x0 + size: 0xf4000 + device: MX25R64 + region: external_flash +external_flash: + address: 0xf4000 + size: 0x70c000 + device: MX25R64 + region: external_flash diff --git a/examples/lit-icd-app/nrfconnect/configuration/nrf5340dk_nrf5340_cpuapp/pm_static_dfu.yml b/examples/lit-icd-app/nrfconnect/configuration/nrf5340dk_nrf5340_cpuapp/pm_static_dfu.yml new file mode 100644 index 00000000000000..10e8680c363a53 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/configuration/nrf5340dk_nrf5340_cpuapp/pm_static_dfu.yml @@ -0,0 +1,56 @@ +mcuboot: + address: 0x0 + size: 0x8000 + region: flash_primary +mcuboot_pad: + address: 0x8000 + size: 0x200 +app: + address: 0x8200 + size: 0xf2e00 +mcuboot_primary: + orig_span: &id001 + - mcuboot_pad + - app + span: *id001 + address: 0x8000 + size: 0xf3000 + region: flash_primary +mcuboot_primary_app: + orig_span: &id002 + - app + span: *id002 + address: 0x8200 + size: 0xf2e00 +factory_data: + address: 0xfb000 + size: 0x1000 + region: flash_primary +settings_storage: + address: 0xfc000 + size: 0x4000 + region: flash_primary +mcuboot_primary_1: + address: 0x0 + size: 0x40000 + device: flash_ctrl + region: ram_flash +mcuboot_secondary: + address: 0x0 + size: 0xf3000 + device: MX25R64 + region: external_flash +mcuboot_secondary_1: + address: 0xf3000 + size: 0x40000 + device: MX25R64 + region: external_flash +external_flash: + address: 0x133000 + size: 0x6CD000 + device: MX25R64 + region: external_flash +pcd_sram: + address: 0x20000000 + size: 0x2000 + region: sram_primary diff --git a/examples/lit-icd-app/nrfconnect/main/AppTask.cpp b/examples/lit-icd-app/nrfconnect/main/AppTask.cpp new file mode 100644 index 00000000000000..50622d0c88b96e --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/main/AppTask.cpp @@ -0,0 +1,502 @@ +/* + * 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 "AppTask.h" +#include "AppConfig.h" +#include "AppEvent.h" +#include "FabricTableDelegate.h" +#include "LEDUtil.h" + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#if CONFIG_CHIP_OTA_REQUESTOR +#include "OTAUtil.h" +#endif + +#include +#include +#include + +LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); + +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; + +namespace { +constexpr uint32_t kFactoryResetTriggerTimeout = 3000; +constexpr uint32_t kFactoryResetCancelWindowTimeout = 3000; +constexpr size_t kAppEventQueueSize = 10; +constexpr EndpointId kIdentifyEndpointId = 1; + +// NOTE! This key is for test/certification only and should not be available in production devices! +// If CONFIG_CHIP_FACTORY_DATA is enabled, this value is read from the factory data. +uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + +K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); +k_timer sFunctionTimer; + +chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; + +Identify sIdentify = { kIdentifyEndpointId, AppTask::IdentifyStartHandler, AppTask::IdentifyStopHandler, + Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator }; + +LEDWidget sStatusLED; +LEDWidget sIdentifyLED; +FactoryResetLEDsWrapper<2> sFactoryResetLEDs{ { FACTORY_RESET_SIGNAL_LED, FACTORY_RESET_SIGNAL_LED1 } }; + +bool sIsNetworkProvisioned = false; +bool sIsNetworkEnabled = false; +bool sHaveBLEConnections = false; + +} // namespace + +namespace LedConsts { +constexpr uint32_t kBlinkRate_ms{ 500 }; +constexpr uint32_t kIdentifyBlinkRate_ms{ 500 }; +namespace StatusLed { +namespace Unprovisioned { +constexpr uint32_t kOn_ms{ 100 }; +constexpr uint32_t kOff_ms{ kOn_ms }; +} // namespace Unprovisioned +namespace Provisioned { +constexpr uint32_t kOn_ms{ 50 }; +constexpr uint32_t kOff_ms{ 950 }; +} // namespace Provisioned + +} // namespace StatusLed +} // namespace LedConsts + +CHIP_ERROR AppTask::Init() +{ + // Initialize CHIP stack + LOG_INF("Init CHIP stack"); + + CHIP_ERROR err = chip::Platform::MemoryInit(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("Platform::MemoryInit() failed"); + return err; + } + + err = PlatformMgr().InitChipStack(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("PlatformMgr().InitChipStack() failed"); + return err; + } + +#if defined(CONFIG_NET_L2_OPENTHREAD) + err = ThreadStackMgr().InitThreadStack(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("ThreadStackMgr().InitThreadStack() failed"); + return err; + } + +#ifdef CONFIG_OPENTHREAD_MTD_SED + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SleepyEndDevice); +#else + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_MinimalEndDevice); +#endif + if (err != CHIP_NO_ERROR) + { + LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed"); + return err; + } +#else + return CHIP_ERROR_INTERNAL; +#endif // CONFIG_NET_L2_OPENTHREAD + + // Initialize LEDs + LEDWidget::InitGpio(); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); + + sStatusLED.Init(SYSTEM_STATE_LED); + sIdentifyLED.Init(IDENTIFY_STATE_LED); + sIdentifyLED.Set(false); + + UpdateStatusLED(); + + // Initialize buttons + auto ret = dk_buttons_init(ButtonEventHandler); + if (ret) + { + LOG_ERR("dk_buttons_init() failed"); + return chip::System::MapErrorZephyr(ret); + } + + // Initialize timer user data + k_timer_init(&sFunctionTimer, &AppTask::FunctionTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&sFunctionTimer, this); + +#ifdef CONFIG_CHIP_OTA_REQUESTOR + /* OTA image confirmation must be done before the factory data init. */ + OtaConfirmNewImage(); +#endif + + // Initialize CHIP server +#if CONFIG_CHIP_FACTORY_DATA + ReturnErrorOnFailure(mFactoryDataProvider.Init()); + SetDeviceInstanceInfoProvider(&mFactoryDataProvider); + SetDeviceAttestationCredentialsProvider(&mFactoryDataProvider); + SetCommissionableDataProvider(&mFactoryDataProvider); + // Read EnableKey from the factory data. + MutableByteSpan enableKey(sTestEventTriggerEnableKey); + err = mFactoryDataProvider.GetEnableKey(enableKey); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("mFactoryDataProvider.GetEnableKey() failed. Could not delegate a test event trigger"); + memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey)); + } +#else + SetDeviceInstanceInfoProvider(&DeviceInstanceInfoProviderMgrImpl()); + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); +#endif + + static CommonCaseDeviceServerInitParams initParams; + static SimpleTestEventTriggerDelegate sTestEventTriggerDelegate{}; + static OTATestEventTriggerHandler sOtaTestEventTriggerHandler{}; + VerifyOrDie(sTestEventTriggerDelegate.Init(ByteSpan(sTestEventTriggerEnableKey)) == CHIP_NO_ERROR); + VerifyOrDie(sTestEventTriggerDelegate.AddHandler(&sOtaTestEventTriggerHandler) == CHIP_NO_ERROR); + (void) initParams.InitializeStaticResourcesBeforeServerInit(); + initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate; + ReturnErrorOnFailure(chip::Server::GetInstance().Init(initParams)); + AppFabricTableDelegate::Init(); + + gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage()); + chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); + ConfigurationMgr().LogDeviceConfig(); + PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); + + // Add CHIP event handler and start CHIP thread. + // Note that all the initialization code should happen prior to this point to avoid data races + // between the main and the CHIP threads + PlatformMgr().AddEventHandler(ChipEventHandler, 0); + err = PlatformMgr().StartEventLoopTask(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("PlatformMgr().StartEventLoopTask() failed"); + } + + return err; +} + +CHIP_ERROR AppTask::StartApp() +{ + ReturnErrorOnFailure(Init()); + + AppEvent event{}; + + while (true) + { + k_msgq_get(&sAppEventQueue, &event, K_FOREVER); + DispatchEvent(event); + } + + return CHIP_NO_ERROR; +} + +void AppTask::IdentifyStartHandler(Identify *) +{ + AppEvent event; + event.Type = AppEventType::IdentifyStart; + event.Handler = [](const AppEvent &) { sIdentifyLED.Blink(LedConsts::kIdentifyBlinkRate_ms); }; + PostEvent(event); +} + +void AppTask::IdentifyStopHandler(Identify *) +{ + AppEvent event; + event.Type = AppEventType::IdentifyStop; + event.Handler = [](const AppEvent &) { sIdentifyLED.Set(false); }; + PostEvent(event); +} + +void AppTask::ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged) +{ + AppEvent button_event; + button_event.Type = AppEventType::Button; + + if (BLE_ADVERTISEMENT_START_BUTTON_MASK & buttonState & hasChanged) + { + button_event.ButtonEvent.PinNo = BLE_ADVERTISEMENT_START_BUTTON; + button_event.ButtonEvent.Action = static_cast(AppEventType::ButtonPushed); + button_event.Handler = StartBLEAdvertisementHandler; + PostEvent(button_event); + } + + if (FUNCTION_BUTTON_MASK & hasChanged) + { + button_event.ButtonEvent.PinNo = FUNCTION_BUTTON; + button_event.ButtonEvent.Action = + static_cast((FUNCTION_BUTTON_MASK & buttonState) ? AppEventType::ButtonPushed : AppEventType::ButtonReleased); + button_event.Handler = FunctionHandler; + PostEvent(button_event); + } + + if (ICD_UAT_BUTTON_MASK & hasChanged) + { + button_event.ButtonEvent.PinNo = ICD_UAT_BUTTON; + button_event.ButtonEvent.Action = static_cast(AppEventType::ButtonPushed); + button_event.Handler = IcdUatEventHandler; + PostEvent(button_event); + } +} + +void AppTask::IcdUatEventHandler(const AppEvent &) +{ + Server::GetInstance().GetICDManager().UpdateOperationState(ICDManager::OperationalState::ActiveMode); +} + +void AppTask::FunctionTimerTimeoutCallback(k_timer * timer) +{ + if (!timer) + { + return; + } + + AppEvent event; + event.Type = AppEventType::Timer; + event.TimerEvent.Context = k_timer_user_data_get(timer); + event.Handler = FunctionTimerEventHandler; + PostEvent(event); +} + +void AppTask::FunctionTimerEventHandler(const AppEvent & event) +{ + if (event.Type != AppEventType::Timer || !Instance().mFunctionTimerActive) + { + return; + } + + // If we reached here, the button was held past kFactoryResetTriggerTimeout, initiate factory reset + if (Instance().mFunction == FunctionEvent::SoftwareUpdate) + { + LOG_INF("Factory Reset Triggered. Release button within %ums to cancel.", kFactoryResetTriggerTimeout); + + // Start timer for kFactoryResetCancelWindowTimeout to allow user to cancel, if required. + Instance().StartTimer(kFactoryResetCancelWindowTimeout); + Instance().mFunction = FunctionEvent::FactoryReset; + + // Turn off all LEDs before starting blink to make sure blink is coordinated. + sStatusLED.Set(false); + sFactoryResetLEDs.Set(false); + + sStatusLED.Blink(LedConsts::kBlinkRate_ms); + sFactoryResetLEDs.Blink(LedConsts::kBlinkRate_ms); + } + else if (Instance().mFunction == FunctionEvent::FactoryReset) + { + // Actually trigger Factory Reset + Instance().mFunction = FunctionEvent::NoneSelected; + chip::Server::GetInstance().ScheduleFactoryReset(); + } + else if (Instance().mFunction == FunctionEvent::AdvertisingStart) + { + // The button was held past kAdvertisingTriggerTimeout, start BLE advertisement if we have 2 buttons UI + StartBLEAdvertisementHandler(event); + } +} + +void AppTask::FunctionHandler(const AppEvent & event) +{ + if (event.ButtonEvent.PinNo != FUNCTION_BUTTON) + return; + + // To trigger software update: press the FUNCTION_BUTTON button briefly (< FACTORY_RESET_TRIGGER_TIMEOUT) + // To initiate factory reset: press the FUNCTION_BUTTON for FACTORY_RESET_TRIGGER_TIMEOUT + FACTORY_RESET_CANCEL_WINDOW_TIMEOUT + // All LEDs start blinking after FACTORY_RESET_TRIGGER_TIMEOUT to signal factory reset has been initiated. + // To cancel factory reset: release the FUNCTION_BUTTON once all LEDs start blinking within the + // FACTORY_RESET_CANCEL_WINDOW_TIMEOUT + if (event.ButtonEvent.Action == static_cast(AppEventType::ButtonPushed)) + { + if (!Instance().mFunctionTimerActive && Instance().mFunction == FunctionEvent::NoneSelected) + { + Instance().StartTimer(kFactoryResetTriggerTimeout); + + Instance().mFunction = FunctionEvent::SoftwareUpdate; + } + } + else + { + // If the button was released before factory reset got initiated, trigger a software update. + if (Instance().mFunctionTimerActive && Instance().mFunction == FunctionEvent::SoftwareUpdate) + { + Instance().CancelTimer(); + Instance().mFunction = FunctionEvent::NoneSelected; + } + else if (Instance().mFunctionTimerActive && Instance().mFunction == FunctionEvent::FactoryReset) + { + sFactoryResetLEDs.Set(false); + UpdateStatusLED(); + Instance().CancelTimer(); + Instance().mFunction = FunctionEvent::NoneSelected; + LOG_INF("Factory Reset has been Canceled"); + } + } +} + +void AppTask::StartBLEAdvertisementHandler(const AppEvent &) +{ + if (Server::GetInstance().GetFabricTable().FabricCount() != 0) + { + LOG_INF("Matter service BLE advertising not started - device is already commissioned"); + return; + } + + if (ConnectivityMgr().IsBLEAdvertisingEnabled()) + { + LOG_INF("BLE advertising is already enabled"); + return; + } + + if (Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() != CHIP_NO_ERROR) + { + LOG_ERR("OpenBasicCommissioningWindow() failed"); + } +} + +void AppTask::UpdateLedStateEventHandler(const AppEvent & event) +{ + if (event.Type == AppEventType::UpdateLedState) + { + event.UpdateLedStateEvent.LedWidget->UpdateState(); + } +} + +void AppTask::LEDStateUpdateHandler(LEDWidget & ledWidget) +{ + AppEvent event; + event.Type = AppEventType::UpdateLedState; + event.Handler = UpdateLedStateEventHandler; + event.UpdateLedStateEvent.LedWidget = &ledWidget; + PostEvent(event); +} + +void AppTask::UpdateStatusLED() +{ +#ifdef CONFIG_STATE_LEDS + // Update the status LED. + // + // If IPv6 network and service provisioned, keep the LED On constantly. + // + // If the system has BLE connection(s) until the stage above, THEN blink the LED at an even + // rate of 100ms. + // + // Otherwise, blink the LED for a very short time. + if (sIsNetworkProvisioned && sIsNetworkEnabled) + { + sStatusLED.Set(true); + } + else if (sHaveBLEConnections) + { + sStatusLED.Blink(LedConsts::StatusLed::Unprovisioned::kOn_ms, LedConsts::StatusLed::Unprovisioned::kOff_ms); + } + else + { + sStatusLED.Blink(LedConsts::StatusLed::Provisioned::kOn_ms, LedConsts::StatusLed::Provisioned::kOff_ms); + } +#endif +} + +void AppTask::ChipEventHandler(const ChipDeviceEvent * event, intptr_t /* arg */) +{ + switch (event->Type) + { + case DeviceEventType::kCHIPoBLEAdvertisingChange: +#ifdef CONFIG_CHIP_NFC_COMMISSIONING + if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Started) + { + if (NFCMgr().IsTagEmulationStarted()) + { + LOG_INF("NFC Tag emulation is already started"); + } + else + { + ShareQRCodeOverNFC(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); + } + } + else if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Stopped) + { + NFCMgr().StopTagEmulation(); + } +#endif + sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0; + UpdateStatusLED(); + break; +#if defined(CONFIG_NET_L2_OPENTHREAD) + case DeviceEventType::kDnssdInitialized: +#if CONFIG_CHIP_OTA_REQUESTOR + InitBasicOTARequestor(); +#endif // CONFIG_CHIP_OTA_REQUESTOR + break; + case DeviceEventType::kThreadStateChange: + sIsNetworkProvisioned = ConnectivityMgr().IsThreadProvisioned(); + sIsNetworkEnabled = ConnectivityMgr().IsThreadEnabled(); + UpdateStatusLED(); + break; +#endif // CONFIG_NET_L2_OPENTHREAD + default: + break; + } +} + +void AppTask::CancelTimer() +{ + k_timer_stop(&sFunctionTimer); + Instance().mFunctionTimerActive = false; +} + +void AppTask::StartTimer(uint32_t aTimeoutInMs) +{ + k_timer_start(&sFunctionTimer, K_MSEC(aTimeoutInMs), K_NO_WAIT); + Instance().mFunctionTimerActive = true; +} + +void AppTask::PostEvent(const AppEvent & event) +{ + if (k_msgq_put(&sAppEventQueue, &event, K_NO_WAIT) != 0) + { + LOG_INF("Failed to post event to app task event queue"); + } +} + +void AppTask::DispatchEvent(const AppEvent & event) +{ + if (event.Handler) + { + event.Handler(event); + } + else + { + LOG_INF("Event received with no handler. Dropping event."); + } +} diff --git a/examples/lit-icd-app/nrfconnect/main/include/AppConfig.h b/examples/lit-icd-app/nrfconnect/main/include/AppConfig.h new file mode 100644 index 00000000000000..26f63f5ec1fa06 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/main/include/AppConfig.h @@ -0,0 +1,33 @@ +/* + * 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 "BoardUtil.h" + +// ---- LIT ICD Application example config ---- + +#define FUNCTION_BUTTON DK_BTN1 +#define FUNCTION_BUTTON_MASK DK_BTN1_MSK +#define ICD_UAT_BUTTON DK_BTN3 +#define ICD_UAT_BUTTON_MASK DK_BTN3_MSK +#define BLE_ADVERTISEMENT_START_BUTTON DK_BTN4 +#define BLE_ADVERTISEMENT_START_BUTTON_MASK DK_BTN4_MSK +#define SYSTEM_STATE_LED DK_LED1 +#define IDENTIFY_STATE_LED DK_LED2 +#define FACTORY_RESET_SIGNAL_LED DK_LED3 +#define FACTORY_RESET_SIGNAL_LED1 DK_LED4 diff --git a/examples/lit-icd-app/nrfconnect/main/include/AppEvent.h b/examples/lit-icd-app/nrfconnect/main/include/AppEvent.h new file mode 100644 index 00000000000000..27ae7408f52e08 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/main/include/AppEvent.h @@ -0,0 +1,72 @@ +/* + * 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 "EventTypes.h" + +class LEDWidget; + +enum class AppEventType : uint8_t +{ + None = 0, + Button, + ButtonPushed, + ButtonReleased, + Timer, + UpdateLedState, + IdentifyStart, + IdentifyStop, +}; + +enum class FunctionEvent : uint8_t +{ + NoneSelected = 0, + SoftwareUpdate = 0, + FactoryReset, + AdvertisingStart +}; + +struct AppEvent +{ + union + { + struct + { + uint8_t PinNo; + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + uint8_t Action; + int32_t Actor; + } LockEvent; + struct + { + LEDWidget * LedWidget; + } UpdateLedStateEvent; + }; + + AppEventType Type{ AppEventType::None }; + EventHandler Handler; +}; diff --git a/examples/lit-icd-app/nrfconnect/main/include/AppTask.h b/examples/lit-icd-app/nrfconnect/main/include/AppTask.h new file mode 100644 index 00000000000000..f1513b2d1e75cb --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/main/include/AppTask.h @@ -0,0 +1,74 @@ +/* + * 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 "AppEvent.h" +#include "LEDWidget.h" + +#if CONFIG_CHIP_FACTORY_DATA +#include +#else +#include +#endif + +struct k_timer; +struct Identify; + +class AppTask +{ +public: + static AppTask & Instance(void) + { + static AppTask sAppTask; + return sAppTask; + }; + CHIP_ERROR StartApp(); + + static void IdentifyStartHandler(Identify *); + static void IdentifyStopHandler(Identify *); + + static void PostEvent(const AppEvent & event); + +private: + CHIP_ERROR Init(); + + static void CancelTimer(); + static void StartTimer(uint32_t timeoutInMs); + + static void DispatchEvent(const AppEvent & event); + static void FunctionTimerEventHandler(const AppEvent & event); + static void FunctionHandler(const AppEvent & event); + static void StartBLEAdvertisementHandler(const AppEvent & event); + static void IcdUatEventHandler(const AppEvent & event); + static void UpdateLedStateEventHandler(const AppEvent & event); + + static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + static void ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged); + static void LEDStateUpdateHandler(LEDWidget & ledWidget); + static void FunctionTimerTimeoutCallback(k_timer * timer); + static void UpdateStatusLED(); + + FunctionEvent mFunction = FunctionEvent::NoneSelected; + bool mFunctionTimerActive = false; + +#if CONFIG_CHIP_FACTORY_DATA + chip::DeviceLayer::FactoryDataProvider mFactoryDataProvider; +#endif +}; diff --git a/examples/lit-icd-app/nrfconnect/main/include/CHIPProjectConfig.h b/examples/lit-icd-app/nrfconnect/main/include/CHIPProjectConfig.h new file mode 100644 index 00000000000000..4baa186190f638 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/main/include/CHIPProjectConfig.h @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2020 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. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once diff --git a/examples/lit-icd-app/nrfconnect/main/main.cpp b/examples/lit-icd-app/nrfconnect/main/main.cpp new file mode 100644 index 00000000000000..0f9b0451e4284d --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/main/main.cpp @@ -0,0 +1,33 @@ +/* + * + * 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 "AppTask.h" + +#include + +LOG_MODULE_REGISTER(app, CONFIG_CHIP_APP_LOG_LEVEL); + +using namespace ::chip; + +int main() +{ + CHIP_ERROR err = AppTask::Instance().StartApp(); + + LOG_ERR("Exited with code %" CHIP_ERROR_FORMAT, err.Format()); + return err == CHIP_NO_ERROR ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/examples/lit-icd-app/nrfconnect/prj.conf b/examples/lit-icd-app/nrfconnect/prj.conf new file mode 100644 index 00000000000000..950be7c8c394e4 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/prj.conf @@ -0,0 +1,46 @@ +# +# 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. +# + +# This sample uses Kconfig.defaults to set options common for all +# samples. This file should contain only options specific for this sample +# or overrides of default values. + +# Enable CHIP +CONFIG_CHIP=y +CONFIG_CHIP_PROJECT_CONFIG="main/include/CHIPProjectConfig.h" +CONFIG_STD_CPP17=y + +# Add support for LEDs and buttons on Nordic development kits +CONFIG_DK_LIBRARY=y + +# Bluetooth Low Energy configuration +CONFIG_BT_DEVICE_NAME="MatterLIT" + +# Other settings +CONFIG_THREAD_NAME=y +CONFIG_MPU_STACK_GUARD=y +CONFIG_RESET_ON_FATAL_ERROR=n + +# Reduce application size +CONFIG_USE_SEGGER_RTT=n + +# Enable Factory Data feature +CONFIG_CHIP_FACTORY_DATA=y +CONFIG_CHIP_FACTORY_DATA_BUILD=y + +# Enable LIT ICD configuration +CONFIG_CHIP_ENABLE_ICD_SUPPORT=y +CONFIG_CHIP_ICD_LIT_SUPPORT=y diff --git a/examples/lit-icd-app/nrfconnect/prj_no_dfu.conf b/examples/lit-icd-app/nrfconnect/prj_no_dfu.conf new file mode 100644 index 00000000000000..00607e349a31ab --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/prj_no_dfu.conf @@ -0,0 +1,48 @@ +# +# 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. +# + +# This sample uses Kconfig.defaults to set options common for all +# samples. This file should contain only options specific for this sample +# or overrides of default values. + +# Enable CHIP +CONFIG_CHIP=y +CONFIG_CHIP_PROJECT_CONFIG="main/include/CHIPProjectConfig.h" +CONFIG_STD_CPP17=y + +# Add support for LEDs and buttons on Nordic development kits +CONFIG_DK_LIBRARY=y + +# Bluetooth Low Energy configuration +CONFIG_BT_DEVICE_NAME="MatterLIT" + +# Other settings +CONFIG_THREAD_NAME=y +CONFIG_MPU_STACK_GUARD=y +CONFIG_RESET_ON_FATAL_ERROR=n + +# Reduce application size +CONFIG_USE_SEGGER_RTT=n + +# Disable Matter OTA DFU +CONFIG_CHIP_OTA_REQUESTOR=n + +# Disable QSPI NOR +CONFIG_CHIP_QSPI_NOR=n + +# Enable LIT ICD configuration +CONFIG_CHIP_ENABLE_ICD_SUPPORT=y +CONFIG_CHIP_ICD_LIT_SUPPORT=y diff --git a/examples/lit-icd-app/nrfconnect/prj_release.conf b/examples/lit-icd-app/nrfconnect/prj_release.conf new file mode 100644 index 00000000000000..61b6b3dfc6f8f8 --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/prj_release.conf @@ -0,0 +1,60 @@ +# +# 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. +# + +# This sample uses Kconfig.defaults to set options common for all +# samples. This file should contain only options specific for this sample +# or overrides of default values. + +# Enable CHIP +CONFIG_CHIP=y +CONFIG_CHIP_PROJECT_CONFIG="main/include/CHIPProjectConfig.h" +CONFIG_STD_CPP17=y + +# Add support for LEDs and buttons on Nordic development kits +CONFIG_DK_LIBRARY=y + +# Bluetooth Low Energy configuration +CONFIG_BT_DEVICE_NAME="MatterLIT" + +# Enable system reset on fatal error +CONFIG_RESET_ON_FATAL_ERROR=y + +# Suspend devices when the CPU goes into sleep +CONFIG_PM_DEVICE=y + +# Disable all debug features +CONFIG_USE_SEGGER_RTT=n +CONFIG_SHELL=n +CONFIG_OPENTHREAD_SHELL=n +CONFIG_CONSOLE=n +CONFIG_UART_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_LOG=n +CONFIG_LOG_MODE_MINIMAL=n +CONFIG_ASSERT_VERBOSE=n +CONFIG_ASSERT_NO_FILE_INFO=y +CONFIG_PRINTK=n +CONFIG_PRINTK_SYNC=n +CONFIG_THREAD_NAME=n +CONFIG_BOOT_BANNER=n + +# Enable Factory Data feature +CONFIG_CHIP_FACTORY_DATA=y +CONFIG_CHIP_FACTORY_DATA_BUILD=y + +# Enable LIT ICD configuration +CONFIG_CHIP_ENABLE_ICD_SUPPORT=y +CONFIG_CHIP_ICD_LIT_SUPPORT=y diff --git a/examples/lit-icd-app/nrfconnect/third_party/connectedhomeip b/examples/lit-icd-app/nrfconnect/third_party/connectedhomeip new file mode 120000 index 00000000000000..c866b86874994d --- /dev/null +++ b/examples/lit-icd-app/nrfconnect/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../.. \ No newline at end of file diff --git a/examples/platform/silabs/efr32/rs911x/hal/efx32_ncp_host.c b/examples/platform/silabs/efr32/rs911x/hal/efx32_ncp_host.c index 414153ecd0164c..82976deb6a3b09 100644 --- a/examples/platform/silabs/efr32/rs911x/hal/efx32_ncp_host.c +++ b/examples/platform/silabs/efr32/rs911x/hal/efx32_ncp_host.c @@ -15,7 +15,6 @@ * ******************************************************************************/ -#include "FreeRTOS.h" #include "cmsis_os2.h" #include "dmadrv.h" #include "em_cmu.h" @@ -37,13 +36,16 @@ #include "sl_power_manager.h" #endif +#define USART_INITSYNC_BAUDRATE 12500000 + static bool dma_callback(unsigned int channel, unsigned int sequenceNo, void * userParam); unsigned int rx_ldma_channel; unsigned int tx_ldma_channel; -osMutexId_t spi_transfer_mutex = 0; +osMutexId_t ncp_transfer_mutex = 0; static uint32_t dummy_buffer; +static sl_si91x_host_init_configuration init_config = { 0 }; // LDMA descriptor and transfer configuration structures for USART TX channel LDMA_Descriptor_t ldmaTXDescriptor; @@ -70,33 +72,22 @@ static bool dma_callback(unsigned int channel, unsigned int sequenceNo, void * u static void gpio_interrupt(uint8_t interrupt_number) { UNUSED_PARAMETER(interrupt_number); - sl_si91x_host_set_bus_event(NCP_HOST_BUS_RX_EVENT); - // GPIO_IntClear(0xAAAA); -} - -void sl_si91x_host_set_sleep_indicator(void) -{ - GPIO_PinOutSet(SLEEP_CONFIRM_PIN.port, SLEEP_CONFIRM_PIN.pin); -} -void sl_si91x_host_clear_sleep_indicator(void) -{ - GPIO_PinOutClear(SLEEP_CONFIRM_PIN.port, SLEEP_CONFIRM_PIN.pin); + if (NULL != init_config.rx_irq) + { + init_config.rx_irq(); + } } -uint32_t sl_si91x_host_get_wake_indicator(void) +static void efx32_spi_init(void) { - return GPIO_PinInGet(WAKE_INDICATOR_PIN.port, WAKE_INDICATOR_PIN.pin); -} + // Default asynchronous initializer (master mode, 1 Mbps, 8-bit data) + USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT; -sl_status_t sl_si91x_host_init(void) -{ - // Enable clock (not needed on xG21) - CMU_ClockEnable(cmuClock_GPIO, true); + init.msbf = true; // MSB first transmission for SPI compatibility + init.autoCsEnable = true; // Allow the USART to assert CS + init.baudrate = USART_INITSYNC_BAUDRATE; -#if SL_SPICTRL_MUX - spi_board_init(); -#endif // Configure SPI bus pins GPIO_PinModeSet(SPI_MISO_PIN.port, SPI_MISO_PIN.pin, gpioModeInput, 0); GPIO_PinModeSet(SPI_MOSI_PIN.port, SPI_MOSI_PIN.pin, gpioModePushPull, 0); @@ -105,12 +96,6 @@ sl_status_t sl_si91x_host_init(void) // Enable clock (not needed on xG21) CMU_ClockEnable(SPI_USART_CMU_CLOCK, true); - // Default asynchronous initializer (master mode, 1 Mbps, 8-bit data) - USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT; - - init.msbf = true; // MSB first transmission for SPI compatibility - init.autoCsEnable = true; // Allow the USART to assert CS - init.baudrate = 12500000; /* * Route USART RX, TX, and CLK to the specified pins. Note that CS is * not controlled by USART so there is no write to the corresponding @@ -139,33 +124,64 @@ sl_status_t sl_si91x_host_init(void) SPI_USART->TIMING |= /*USART_TIMING_TXDELAY_ONE | USART_TIMING_CSSETUP_ONE |*/ USART_TIMING_CSHOLD_ONE; // SPI_USART->CTRL_SET |= USART_CTRL_SMSDELAY; + + // configure packet pending interrupt priority + NVIC_SetPriority(GPIO_ODD_IRQn, PACKET_PENDING_INT_PRI); + GPIOINT_CallbackRegister(INTERRUPT_PIN.pin, gpio_interrupt); + GPIO_PinModeSet(INTERRUPT_PIN.port, INTERRUPT_PIN.pin, gpioModeInputPullFilter, 0); + GPIO_ExtIntConfig(INTERRUPT_PIN.port, INTERRUPT_PIN.pin, INTERRUPT_PIN.pin, true, false, true); +} + +void sl_si91x_host_set_sleep_indicator(void) +{ + GPIO_PinOutSet(SLEEP_CONFIRM_PIN.port, SLEEP_CONFIRM_PIN.pin); +} + +void sl_si91x_host_clear_sleep_indicator(void) +{ + GPIO_PinOutClear(SLEEP_CONFIRM_PIN.port, SLEEP_CONFIRM_PIN.pin); +} + +uint32_t sl_si91x_host_get_wake_indicator(void) +{ + return GPIO_PinInGet(WAKE_INDICATOR_PIN.port, WAKE_INDICATOR_PIN.pin); +} + +sl_status_t sl_si91x_host_init(sl_si91x_host_init_configuration * config) +{ + init_config.rx_irq = config->rx_irq; + init_config.rx_done = config->rx_done; + + // Enable clock (not needed on xG21) + CMU_ClockEnable(cmuClock_GPIO, true); + +#if SL_SPICTRL_MUX + spi_board_init(); +#endif + if (transfer_done_semaphore == NULL) { transfer_done_semaphore = osSemaphoreNew(1, 0, NULL); } - if (spi_transfer_mutex == 0) + if (ncp_transfer_mutex == 0) { - spi_transfer_mutex = osMutexNew(NULL); + ncp_transfer_mutex = osMutexNew(NULL); } - DMADRV_Init(); - DMADRV_AllocateChannel(&rx_ldma_channel, NULL); - DMADRV_AllocateChannel(&tx_ldma_channel, NULL); + efx32_spi_init(); // Start reset line low GPIO_PinModeSet(RESET_PIN.port, RESET_PIN.pin, gpioModePushPull, 0); - // configure packet pending interrupt priority - NVIC_SetPriority(GPIO_ODD_IRQn, PACKET_PENDING_INT_PRI); - // Configure interrupt, sleep and wake confirmation pins - GPIOINT_CallbackRegister(INTERRUPT_PIN.pin, gpio_interrupt); - GPIO_PinModeSet(INTERRUPT_PIN.port, INTERRUPT_PIN.pin, gpioModeInputPullFilter, 0); - GPIO_ExtIntConfig(INTERRUPT_PIN.port, INTERRUPT_PIN.pin, INTERRUPT_PIN.pin, true, false, true); GPIO_PinModeSet(SLEEP_CONFIRM_PIN.port, SLEEP_CONFIRM_PIN.pin, gpioModeWiredOrPullDown, 1); GPIO_PinModeSet(WAKE_INDICATOR_PIN.port, WAKE_INDICATOR_PIN.pin, gpioModeWiredOrPullDown, 0); + DMADRV_Init(); + DMADRV_AllocateChannel(&rx_ldma_channel, NULL); + DMADRV_AllocateChannel(&tx_ldma_channel, NULL); + return SL_STATUS_OK; } @@ -174,11 +190,7 @@ sl_status_t sl_si91x_host_deinit(void) return SL_STATUS_OK; } -void sl_si91x_host_enable_high_speed_bus() -{ - // SPI_USART->CTRL_SET |= USART_CTRL_SMSDELAY | USART_CTRL_SSSEARLY; - // USART_BaudrateSyncSet(SPI_USART, 0, 20000000); -} +void sl_si91x_host_enable_high_speed_bus() {} /*==================================================================*/ /** @@ -194,7 +206,7 @@ void sl_si91x_host_enable_high_speed_bus() */ sl_status_t sl_si91x_host_spi_transfer(const void * tx_buffer, void * rx_buffer, uint16_t buffer_length) { - osMutexAcquire(spi_transfer_mutex, 0xFFFFFFFFUL); + osMutexAcquire(ncp_transfer_mutex, 0xFFFFFFFFUL); #if SL_SPICTRL_MUX sl_wfx_host_spi_cs_assert(); @@ -268,7 +280,7 @@ sl_status_t sl_si91x_host_spi_transfer(const void * tx_buffer, void * rx_buffer, } } - osMutexRelease(spi_transfer_mutex); + osMutexRelease(ncp_transfer_mutex); #if SL_SPICTRL_MUX sl_wfx_host_spi_cs_deassert(); #endif // SL_SPICTRL_MUX @@ -288,6 +300,7 @@ void sl_si91x_host_release_from_reset(void) void sl_si91x_host_enable_bus_interrupt(void) { + NVIC_ClearPendingIRQ(GPIO_ODD_IRQn); NVIC_EnableIRQ(GPIO_ODD_IRQn); } diff --git a/examples/platform/silabs/efr32/rs911x/rs9117.gni b/examples/platform/silabs/efr32/rs911x/rs9117.gni index 251de0be213fe6..5a561c9f201eab 100644 --- a/examples/platform/silabs/efr32/rs911x/rs9117.gni +++ b/examples/platform/silabs/efr32/rs911x/rs9117.gni @@ -27,7 +27,8 @@ rs9117_src_sapi = [ "${wifi_sdk_root}/components/device/silabs/si91x/wireless/sl_net/src/sl_net_rsi_utility.c", "${wifi_sdk_root}/components/device/silabs/si91x/wireless/sl_net/src/sl_net_si91x_integration_handler.c", "${wifi_sdk_root}/components/device/silabs/si91x/wireless/sl_net/src/sl_si91x_net_credentials.c", - "${wifi_sdk_root}/components/device/silabs/si91x/wireless/spi_interface/sl_si91x_spi_driver.c", + "${wifi_sdk_root}/components/device/silabs/si91x/wireless/ncp_interface/spi/sl_si91x_spi.c", + "${wifi_sdk_root}/components/device/silabs/si91x/wireless/ncp_interface/sl_si91x_ncp_driver.c", # wifi component "${wifi_sdk_root}/components/protocol/wifi/src/sl_wifi_callback_framework.c", diff --git a/examples/platform/silabs/efr32/wf200/host_if.cpp b/examples/platform/silabs/efr32/wf200/host_if.cpp index 3240c2642a3080..041a1778421ed3 100644 --- a/examples/platform/silabs/efr32/wf200/host_if.cpp +++ b/examples/platform/silabs/efr32/wf200/host_if.cpp @@ -607,7 +607,7 @@ static void wfx_events_task(void * p_arg) { // Enable the power save SILABS_LOG("WF200 going to DTIM based sleep"); - sl_wfx_set_power_mode(WFM_PM_MODE_DTIM, WFM_PM_POLL_FAST_PS, BEACON_1); + sl_wfx_set_power_mode(WFM_PM_MODE_DTIM, WFM_PM_POLL_FAST_PS, BEACON_1, 0 /*timeout*/); sl_wfx_enable_device_power_save(); } #endif /* CHIP_CONFIG_ENABLE_ICD_SERVER */ diff --git a/examples/temperature-measurement-app/esp32/README.md b/examples/temperature-measurement-app/esp32/README.md index 18d07ff639b06a..99347fc6ead9f4 100644 --- a/examples/temperature-measurement-app/esp32/README.md +++ b/examples/temperature-measurement-app/esp32/README.md @@ -51,9 +51,39 @@ chip-tool pairing ble-wifi 1 SSID PASSPHRASE 20202021 3840 chip-tool diagnosticlogs retrieve-logs-request 0 0 1 0 # Read network diagnostic using BDX protocol -chip-tool diagnosticlogs retrieve-logs-request 1 0 1 0 --TransferFileDesignator network-diag.log +chip-tool interactive start +> diagnosticlogs retrieve-logs-request 1 1 1 0 --TransferFileDesignator network-diag.log +# Retrieve crash over BDX +> diagnosticlogs retrieve-logs-request 1 1 1 0 --TransferFileDesignator crash.bin ``` +esp-idf supports storing and retrieving +[core dump in flash](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/core_dump.html#core-dump-to-flash). + +To support that, application needs to add core dump partition's entry in +[partitons.csv](partitions.csv#7) and we need to enable few menuconfig options. + +``` +CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH=y +CONFIG_ESP32_COREDUMP_DATA_FORMAT_ELF=y +``` + +This example's partition table and sdkconfig.default are already modified + +- Retrieve the core dump using diagnostic logs cluster + + ``` + # Read crash logs over BDX + chip-tool interactive start + > diagnosticlogs retrieve-logs-request 1 1 1 0 --TransferFileDesignator crash.bin + ``` + +- Decode the crash logs, using espcoredump.py + ``` + espcoredump.py --chip (CHIP) info_corefile --core /tmp/crash.bin \ + --core-format elf build/chip-temperature-measurement-app.elf + ``` + ## Optimization Optimization related to WiFi, BLuetooth, Asserts etc are the part of this diff --git a/examples/temperature-measurement-app/esp32/main/CMakeLists.txt b/examples/temperature-measurement-app/esp32/main/CMakeLists.txt index 8953d34869b76a..062266652dc303 100644 --- a/examples/temperature-measurement-app/esp32/main/CMakeLists.txt +++ b/examples/temperature-measurement-app/esp32/main/CMakeLists.txt @@ -55,7 +55,7 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers" ) -set(PRIV_REQUIRES_LIST chip QRCode bt nvs_flash) +set(PRIV_REQUIRES_LIST chip QRCode bt nvs_flash bootloader_support espcoredump) if (CONFIG_ENABLE_PW_RPC) # Append additional directories for RPC build @@ -83,7 +83,7 @@ endif (CONFIG_ENABLE_PW_RPC) idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} SRC_DIRS ${SRC_DIRS_LIST} PRIV_REQUIRES ${PRIV_REQUIRES_LIST} - EMBED_FILES diagnostic_logs/end_user_support.log diagnostic_logs/network_diag.log diagnostic_logs/crash.log) + EMBED_FILES diagnostic_logs/end_user_support.log diagnostic_logs/network_diag.log) include("${CHIP_ROOT}/build/chip/esp32/esp32_codegen.cmake") chip_app_component_codegen("${CHIP_ROOT}/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter") diff --git a/examples/temperature-measurement-app/esp32/main/diagnostic-logs-provider-delegate-impl.cpp b/examples/temperature-measurement-app/esp32/main/diagnostic-logs-provider-delegate-impl.cpp index 4bef0fbd86cc19..5034e3f928788f 100644 --- a/examples/temperature-measurement-app/esp32/main/diagnostic-logs-provider-delegate-impl.cpp +++ b/examples/temperature-measurement-app/esp32/main/diagnostic-logs-provider-delegate-impl.cpp @@ -19,10 +19,19 @@ #include #include +#if defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) +#include +#include +// Its a bit hackish but we need this in order to pull in the sizeof(core_dump_header_t) +// we can even use the static 20 but, what if that gets chagned? +#include "../include_core_dump/esp_core_dump_types.h" +#endif // defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) + using namespace chip; using namespace chip::app::Clusters::DiagnosticLogs; LogProvider LogProvider::sInstance; +LogProvider::CrashLogContext LogProvider::sCrashLogContext; namespace { bool IsValidIntent(IntentEnum intent) @@ -30,24 +39,21 @@ bool IsValidIntent(IntentEnum intent) return intent != IntentEnum::kUnknownEnumValue; } -// end_user_support.log, network_diag.log, and crash.log files are embedded in the firmware +// end_user_support.log and network_diag.log files are embedded in the firmware extern const uint8_t endUserSupportLogStart[] asm("_binary_end_user_support_log_start"); extern const uint8_t endUserSupportLogEnd[] asm("_binary_end_user_support_log_end"); extern const uint8_t networkDiagnosticLogStart[] asm("_binary_network_diag_log_start"); extern const uint8_t networkDiagnosticLogEnd[] asm("_binary_network_diag_log_end"); - -extern const uint8_t crashLogStart[] asm("_binary_crash_log_start"); -extern const uint8_t crashLogEnd[] asm("_binary_crash_log_end"); } // namespace LogProvider::~LogProvider() { - for (auto sessionSpan : mSessionSpanMap) + for (auto sessionSpan : mSessionContextMap) { Platform::MemoryFree(sessionSpan.second); } - mSessionSpanMap.clear(); + mSessionContextMap.clear(); } CHIP_ERROR LogProvider::GetLogForIntent(IntentEnum intent, MutableByteSpan & outBuffer, Optional & outTimeStamp, @@ -69,93 +75,233 @@ CHIP_ERROR LogProvider::GetLogForIntent(IntentEnum intent, MutableByteSpan & out return CHIP_NO_ERROR; } -const uint8_t * LogProvider::GetDataStartForIntent(IntentEnum intent) +size_t LogProvider::GetSizeForIntent(IntentEnum intent) { switch (intent) { case IntentEnum::kEndUserSupport: - return &endUserSupportLogStart[0]; + return static_cast(endUserSupportLogEnd - endUserSupportLogStart); case IntentEnum::kNetworkDiag: - return &networkDiagnosticLogStart[0]; + return static_cast(networkDiagnosticLogEnd - networkDiagnosticLogStart); case IntentEnum::kCrashLogs: - return &crashLogStart[0]; + return GetCrashSize(); default: - return nullptr; + return 0; } } -size_t LogProvider::GetSizeForIntent(IntentEnum intent) +size_t LogProvider::GetCrashSize() { + size_t outSize = 0; + +#if defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) + size_t unusedOutAddr; + esp_err_t esp_err = esp_core_dump_image_get(&unusedOutAddr, &outSize); + VerifyOrReturnValue(esp_err == ESP_OK, 0, ChipLogError(DeviceLayer, "Failed to get core dump image, esp_err:%d", esp_err)); +#endif // defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) + + return outSize; +} + +CHIP_ERROR LogProvider::MapCrashPartition(CrashLogContext * context) +{ +#if defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) + size_t outAddr, outSize; + esp_err_t esp_err = esp_core_dump_image_get(&outAddr, &outSize); + VerifyOrReturnError(esp_err == ESP_OK, CHIP_ERROR(ChipError::Range::kPlatform, esp_err), + ChipLogError(DeviceLayer, "Failed to get core dump image, esp_err:%d", esp_err)); + + /* map the full core dump parition, including the checksum. */ + esp_err = spi_flash_mmap(outAddr, outSize, SPI_FLASH_MMAP_DATA, &context->mappedAddress, &context->mappedHandle); + VerifyOrReturnError(esp_err == ESP_OK, CHIP_ERROR(ChipError::Range::kPlatform, esp_err), + ChipLogError(DeviceLayer, "Failed to mmap the crash partition, esp_err:%d", esp_err)); + + context->crashSize = static_cast(outSize); + return CHIP_NO_ERROR; +#else + return CHIP_ERROR_NOT_FOUND; +#endif // defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) +} + +CHIP_ERROR LogProvider::PrepareLogContextForIntent(LogContext * context, IntentEnum intent) +{ + context->intent = intent; + switch (intent) { + case IntentEnum::kEndUserSupport: { + context->EndUserSupport.span = + ByteSpan(&endUserSupportLogStart[0], static_cast(endUserSupportLogEnd - endUserSupportLogStart)); + } + break; + + case IntentEnum::kNetworkDiag: { + context->NetworkDiag.span = + ByteSpan(&networkDiagnosticLogStart[0], static_cast(networkDiagnosticLogEnd - networkDiagnosticLogStart)); + } + break; + + case IntentEnum::kCrashLogs: { +#if defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) + sCrashLogContext.Reset(); + context->Crash.logContext = &sCrashLogContext; + + CHIP_ERROR err = MapCrashPartition(context->Crash.logContext); + VerifyOrReturnError(err == CHIP_NO_ERROR, err, context->Crash.logContext = nullptr); + + context->Crash.logContext->readOffset = sizeof(core_dump_header_t); + context->Crash.logContext->isMapped = true; +#else + return CHIP_ERROR_NOT_FOUND; +#endif // defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) + } + break; + + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + + return CHIP_NO_ERROR; +} + +void LogProvider::CleanupLogContextForIntent(LogContext * context) +{ + switch (context->intent) + { case IntentEnum::kEndUserSupport: - return static_cast(endUserSupportLogEnd - endUserSupportLogStart); + break; + case IntentEnum::kNetworkDiag: - return static_cast(networkDiagnosticLogEnd - networkDiagnosticLogStart); - case IntentEnum::kCrashLogs: - return static_cast(crashLogEnd - crashLogStart); + break; + + case IntentEnum::kCrashLogs: { +#if defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) + CrashLogContext * logContext = context->Crash.logContext; + spi_flash_munmap(logContext->mappedHandle); + logContext->Reset(); +#endif // defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) + } + break; + default: - return 0; + break; } } +CHIP_ERROR LogProvider::GetDataForIntent(LogContext * context, MutableByteSpan & outBuffer, bool & outIsEndOfLog) +{ + switch (context->intent) + { + case IntentEnum::kEndUserSupport: { + auto dataSize = context->EndUserSupport.span.size(); + auto count = std::min(dataSize, outBuffer.size()); + + VerifyOrReturnError(CanCastTo(count), CHIP_ERROR_INVALID_ARGUMENT, outBuffer.reduce_size(0)); + ReturnErrorOnFailure(CopySpanToMutableSpan(ByteSpan(context->EndUserSupport.span.data(), count), outBuffer)); + + outIsEndOfLog = dataSize == count; + if (!outIsEndOfLog) + { + // reduce the span after reading count bytes + context->EndUserSupport.span = context->EndUserSupport.span.SubSpan(count); + } + } + break; + + case IntentEnum::kNetworkDiag: { + auto dataSize = context->NetworkDiag.span.size(); + auto count = std::min(dataSize, outBuffer.size()); + + VerifyOrReturnError(CanCastTo(count), CHIP_ERROR_INVALID_ARGUMENT, outBuffer.reduce_size(0)); + ReturnErrorOnFailure(CopySpanToMutableSpan(ByteSpan(context->NetworkDiag.span.data(), count), outBuffer)); + + outIsEndOfLog = dataSize == count; + if (!outIsEndOfLog) + { + // reduce the span after reading count bytes + context->NetworkDiag.span = context->NetworkDiag.span.SubSpan(count); + } + } + break; + + case IntentEnum::kCrashLogs: { +#if defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) + CrashLogContext * logContext = context->Crash.logContext; + size_t dataSize = logContext->crashSize - logContext->readOffset; + auto count = std::min(dataSize, outBuffer.size()); + + VerifyOrReturnError(CanCastTo(count), CHIP_ERROR_INVALID_ARGUMENT, outBuffer.reduce_size(0)); + + const uint8_t * readAddr = reinterpret_cast(logContext->mappedAddress) + logContext->readOffset; + memcpy(outBuffer.data(), readAddr, count); + outBuffer.reduce_size(count); + + logContext->readOffset += count; + outIsEndOfLog = dataSize == count; +#else + outBuffer.reduce_size(0); + return CHIP_ERROR_NOT_FOUND; +#endif // defined(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) && defined(CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF) + } + break; + + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + + return CHIP_NO_ERROR; +} + CHIP_ERROR LogProvider::StartLogCollection(IntentEnum intent, LogSessionHandle & outHandle, Optional & outTimeStamp, Optional & outTimeSinceBoot) { VerifyOrReturnValue(IsValidIntent(intent), CHIP_ERROR_INVALID_ARGUMENT); - const uint8_t * dataStart = GetDataStartForIntent(intent); - VerifyOrReturnError(dataStart, CHIP_ERROR_NOT_FOUND); - - size_t dataSize = GetSizeForIntent(intent); - VerifyOrReturnError(dataSize, CHIP_ERROR_NOT_FOUND); + // In case of crash logs we can only mmap at max once, so check before doing anything + if (intent == IntentEnum::kCrashLogs) + { + VerifyOrReturnError(sCrashLogContext.isMapped == false, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(DeviceLayer, "Crash partition already mapped")); + } - ByteSpan * span = reinterpret_cast(Platform::MemoryCalloc(1, sizeof(ByteSpan))); - VerifyOrReturnValue(span, CHIP_ERROR_NO_MEMORY); + LogContext * context = reinterpret_cast(Platform::MemoryCalloc(1, sizeof(LogContext))); + VerifyOrReturnValue(context != nullptr, CHIP_ERROR_NO_MEMORY); - *span = ByteSpan(dataStart, dataSize); + CHIP_ERROR err = PrepareLogContextForIntent(context, intent); + VerifyOrReturnError(err == CHIP_NO_ERROR, err, Platform::MemoryFree(context)); mLogSessionHandle++; // If the session handle rolls over to UINT16_MAX which is invalid, reset to 0. VerifyOrDo(mLogSessionHandle != kInvalidLogSessionHandle, mLogSessionHandle = 0); - outHandle = mLogSessionHandle; - mSessionSpanMap[mLogSessionHandle] = span; + outHandle = mLogSessionHandle; + mSessionContextMap[mLogSessionHandle] = context; + return CHIP_NO_ERROR; } CHIP_ERROR LogProvider::EndLogCollection(LogSessionHandle sessionHandle) { VerifyOrReturnValue(sessionHandle != kInvalidLogSessionHandle, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnValue(mSessionSpanMap.count(sessionHandle), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnValue(mSessionContextMap.count(sessionHandle), CHIP_ERROR_INVALID_ARGUMENT); - ByteSpan * span = mSessionSpanMap[sessionHandle]; - mSessionSpanMap.erase(sessionHandle); + LogContext * context = mSessionContextMap[sessionHandle]; + VerifyOrReturnError(context, CHIP_ERROR_INCORRECT_STATE); + + CleanupLogContextForIntent(context); + Platform::MemoryFree(context); + mSessionContextMap.erase(sessionHandle); - Platform::MemoryFree(span); return CHIP_NO_ERROR; } CHIP_ERROR LogProvider::CollectLog(LogSessionHandle sessionHandle, MutableByteSpan & outBuffer, bool & outIsEndOfLog) { VerifyOrReturnValue(sessionHandle != kInvalidLogSessionHandle, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnValue(mSessionSpanMap.count(sessionHandle), CHIP_ERROR_INVALID_ARGUMENT); - - ByteSpan * span = mSessionSpanMap[sessionHandle]; - auto dataSize = span->size(); - auto count = std::min(dataSize, outBuffer.size()); - - VerifyOrReturnError(CanCastTo(count), CHIP_ERROR_INVALID_ARGUMENT, outBuffer.reduce_size(0)); - - ReturnErrorOnFailure(CopySpanToMutableSpan(ByteSpan(span->data(), count), outBuffer)); + VerifyOrReturnValue(mSessionContextMap.count(sessionHandle), CHIP_ERROR_INVALID_ARGUMENT); - outIsEndOfLog = dataSize == count; + LogContext * context = mSessionContextMap[sessionHandle]; + VerifyOrReturnError(context, CHIP_ERROR_INCORRECT_STATE); - if (!outIsEndOfLog) - { - // reduce the span after reading count bytes - *span = span->SubSpan(count); - } - - return CHIP_NO_ERROR; + return GetDataForIntent(context, outBuffer, outIsEndOfLog); } diff --git a/examples/temperature-measurement-app/esp32/main/diagnostic_logs/crash.log b/examples/temperature-measurement-app/esp32/main/diagnostic_logs/crash.log deleted file mode 100644 index 04089de8ce7afd..00000000000000 --- a/examples/temperature-measurement-app/esp32/main/diagnostic_logs/crash.log +++ /dev/null @@ -1,21 +0,0 @@ -W (5047Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled. - -Core 0 register dump: -PC : 0x4009579a PS : 0x00060c33 A0 : 0x800941e1 A1 : 0x3fff3630 -0x4009579a: uxListRemove at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/list.c:195 - -A2 : 0x00000006 A3 : 0x00060c20 A4 : 0x00000000 A5 : 0x00060c23 -A6 : 0xb33fffff A7 : 0xb33fffff A8 : 0x800950f0 A9 : 0x3fff3600 -A10 : 0x00000001 A11 : 0x000000fe A12 : 0x00000000 A13 : 0x00000000 -A14 : 0x00000000 A15 : 0x00000000 SAR : 0x0000000a EXCCAUSE: 0x0000001c -EXCVADDR: 0x00000016 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff -0x4000c2e0: memcpy in ROM -0x4000c2f6: memcpy in ROM - -Backtrace: 0x40095797:0x3fff3630 0x400941de:0x3fff3650 0x40154b39:0x3fff3670 0x40154b53:0x3fff3690 0x4013e20d:0x3fff36b0 0x40094fa6:0x3fff36d0 -0x40095797: uxListRemove at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/list.c:202 -0x400941de: vTaskDelete at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:1434 (discriminator 4) -0x40154b39: esp_nimble_disable at /opt/espressif/esp-idf/components/bt/host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c:55 -0x40154b53: nimble_port_freertos_deinit at /opt/espressif/esp-idf/components/bt/host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c:80 -0x4013e20d: chip::DeviceLayer::Internal::BLEManagerImpl::bleprph_host_task(void*) at /home/smart/projects/smp_matter/build/esp-idf/chip/../../../../../../../opt/espressif/esp-matter/connectedhomeip/connectedhomeip/config/esp32/third_party/connectedhomeip/src/platform/ESP32/nimble/BLEManagerImpl.cpp:864 -0x40094fa6: vPortTaskWrapper at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162 diff --git a/examples/temperature-measurement-app/esp32/main/include/diagnostic-logs-provider-delegate-impl.h b/examples/temperature-measurement-app/esp32/main/include/diagnostic-logs-provider-delegate-impl.h index d47dccafa6079d..c3d1bd389fb39b 100644 --- a/examples/temperature-measurement-app/esp32/main/include/diagnostic-logs-provider-delegate-impl.h +++ b/examples/temperature-measurement-app/esp32/main/include/diagnostic-logs-provider-delegate-impl.h @@ -20,6 +20,7 @@ #include #include +#include namespace chip { namespace app { @@ -54,12 +55,59 @@ class LogProvider : public DiagnosticLogsProviderDelegate LogProvider(const LogProvider &) = delete; LogProvider & operator=(const LogProvider &) = delete; - // This tracks the ByteSpan for each session - std::map mSessionSpanMap; + struct CrashLogContext + { + spi_flash_mmap_handle_t mappedHandle = 0; + const void * mappedAddress = nullptr; + uint32_t crashSize = 0; + uint32_t readOffset = 0; + bool isMapped = 0; + + void Reset() + { + this->mappedHandle = 0; + this->mappedAddress = nullptr; + this->crashSize = 0; + this->readOffset = 0; + this->isMapped = 0; + } + }; + + static CrashLogContext sCrashLogContext; + + struct LogContext + { + IntentEnum intent; + union + { + struct + { + ByteSpan span; + } EndUserSupport; + struct + { + ByteSpan span; + } NetworkDiag; + struct + { + // TODO: This be a ref counted, so that we can serve parallel queries for crash logs + CrashLogContext * logContext; + } Crash; + }; + }; + + // This tracks the ByteSpan for each session, need to change this to void * + std::map mSessionContextMap; LogSessionHandle mLogSessionHandle = kInvalidLogSessionHandle; - const uint8_t * GetDataStartForIntent(IntentEnum intent); + // Helpers for Retrieving Core Dump from flash + size_t GetCrashSize(); + CHIP_ERROR MapCrashPartition(CrashLogContext * crashLogContext); + + CHIP_ERROR PrepareLogContextForIntent(LogContext * context, IntentEnum intent); + void CleanupLogContextForIntent(LogContext * contex); + CHIP_ERROR GetDataForIntent(LogContext * context, MutableByteSpan & outBuffer, bool & outIsEndOfLog); }; } // namespace DiagnosticLogs diff --git a/examples/temperature-measurement-app/esp32/partitions.csv b/examples/temperature-measurement-app/esp32/partitions.csv index 8b0928187b8708..35c776d19e80fa 100644 --- a/examples/temperature-measurement-app/esp32/partitions.csv +++ b/examples/temperature-measurement-app/esp32/partitions.csv @@ -2,5 +2,6 @@ # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0xC000, phy_init, data, phy, , 0x1000, -# Factory partition size about 1.9MB -factory, app, factory, , 1920K, +# Factory partition size about 1.5MB +factory, app, factory, , 1536K, +coredump, data, coredump,, 64K diff --git a/examples/temperature-measurement-app/esp32/sdkconfig.defaults b/examples/temperature-measurement-app/esp32/sdkconfig.defaults index 6d3243cabfeb8c..3dcab272b297db 100644 --- a/examples/temperature-measurement-app/esp32/sdkconfig.defaults +++ b/examples/temperature-measurement-app/esp32/sdkconfig.defaults @@ -99,3 +99,6 @@ CONFIG_LWIP_IPV6_NUM_ADDRESSES=6 # Enable the diagnostic logs transfer over BDX protocol CONFIG_CHIP_ENABLE_BDX_LOG_TRANSFER=y + +CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH=y +CONFIG_ESP32_COREDUMP_DATA_FORMAT_ELF=y diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java index 79b02f01386769..540798aae913b7 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java @@ -41,6 +41,7 @@ import com.matter.tv.server.tvapp.LowPowerManagerStub; import com.matter.tv.server.tvapp.MediaInputManagerStub; import com.matter.tv.server.tvapp.MediaPlaybackManagerStub; +import com.matter.tv.server.tvapp.MessagesManagerStub; import com.matter.tv.server.tvapp.OnOffManagerStub; import com.matter.tv.server.tvapp.TvApp; import com.matter.tv.server.tvapp.WakeOnLanManagerStub; @@ -96,6 +97,8 @@ public void init(@NonNull Context context) { app.setMediaPlaybackManager(endpoint, new MediaPlaybackManagerStub(endpoint)); } else if (clusterId == Clusters.ClusterId_Channel) { app.setChannelManager(endpoint, new ChannelManagerStub(endpoint)); + } else if (clusterId == Clusters.ClusterId_Messaging) { + app.setMessagesManager(endpoint, new MessagesManagerStub(endpoint)); } else if (clusterId == Clusters.ClusterId_OnOff) { mOnOffEndpoint = endpoint; app.setOnOffManager(endpoint, new OnOffManagerStub(endpoint)); diff --git a/examples/tv-app/android/BUILD.gn b/examples/tv-app/android/BUILD.gn index 63de5a515b0754..47157a271edfe8 100644 --- a/examples/tv-app/android/BUILD.gn +++ b/examples/tv-app/android/BUILD.gn @@ -69,6 +69,8 @@ shared_library("jni") { "java/MediaInputManager.h", "java/MediaPlaybackManager.cpp", "java/MediaPlaybackManager.h", + "java/MessagesManager.cpp", + "java/MessagesManager.h", "java/MyUserPrompter-JNI.cpp", "java/MyUserPrompter-JNI.h", "java/MyUserPrompterResolver-JNI.cpp", @@ -143,6 +145,10 @@ android_library("java") { "java/src/com/matter/tv/server/tvapp/MediaPlaybackManagerStub.java", "java/src/com/matter/tv/server/tvapp/MediaPlaybackPosition.java", "java/src/com/matter/tv/server/tvapp/MediaTrack.java", + "java/src/com/matter/tv/server/tvapp/Message.java", + "java/src/com/matter/tv/server/tvapp/MessageResponseOption.java", + "java/src/com/matter/tv/server/tvapp/MessagesManager.java", + "java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java", "java/src/com/matter/tv/server/tvapp/OnOffManager.java", "java/src/com/matter/tv/server/tvapp/OnOffManagerStub.java", "java/src/com/matter/tv/server/tvapp/TvApp.java", diff --git a/examples/tv-app/android/java/ChannelManager.cpp b/examples/tv-app/android/java/ChannelManager.cpp index 3c0efcab9f8cdc..c7067132e46e9d 100644 --- a/examples/tv-app/android/java/ChannelManager.cpp +++ b/examples/tv-app/android/java/ChannelManager.cpp @@ -57,6 +57,7 @@ void ChannelManager::NewManager(jint endpoint, jobject manager) CHIP_ERROR ChannelManager::HandleGetChannelList(AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -66,6 +67,8 @@ CHIP_ERROR ChannelManager::HandleGetChannelList(AttributeValueEncoder & aEncoder VerifyOrExit(mChannelManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetChannelListMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray channelInfoList = (jobjectArray) env->CallObjectMethod(mChannelManagerObject.ObjectRef(), mGetChannelListMethod); @@ -134,6 +137,7 @@ CHIP_ERROR ChannelManager::HandleGetChannelList(AttributeValueEncoder & aEncoder CHIP_ERROR ChannelManager::HandleGetLineup(AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; chip::app::Clusters::Channel::Structs::LineupInfoStruct::Type lineupInfo; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -144,6 +148,8 @@ CHIP_ERROR ChannelManager::HandleGetLineup(AttributeValueEncoder & aEncoder) VerifyOrExit(mChannelManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetLineupMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + { jobject channelLineupObject = env->CallObjectMethod(mChannelManagerObject.ObjectRef(), mGetLineupMethod); if (channelLineupObject != nullptr) @@ -197,6 +203,7 @@ CHIP_ERROR ChannelManager::HandleGetLineup(AttributeValueEncoder & aEncoder) CHIP_ERROR ChannelManager::HandleGetCurrentChannel(AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; chip::app::Clusters::Channel::Structs::ChannelInfoStruct::Type channelInfo; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -207,6 +214,8 @@ CHIP_ERROR ChannelManager::HandleGetCurrentChannel(AttributeValueEncoder & aEnco VerifyOrExit(mChannelManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetCurrentChannelMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + { jobject channelInfoObject = env->CallObjectMethod(mChannelManagerObject.ObjectRef(), mGetCurrentChannelMethod); if (channelInfoObject != nullptr) @@ -273,6 +282,7 @@ CHIP_ERROR ChannelManager::HandleGetCurrentChannel(AttributeValueEncoder & aEnco void ChannelManager::HandleChangeChannel(CommandResponseHelper & helper, const CharSpan & match) { + DeviceLayer::StackUnlock unlock; std::string name(match.data(), match.size()); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -282,9 +292,10 @@ void ChannelManager::HandleChangeChannel(CommandResponseHelperExceptionClear(); + { UtfString jniname(env, name.c_str()); - env->ExceptionClear(); jobject channelObject = env->CallObjectMethod(mChannelManagerObject.ObjectRef(), mChangeChannelMethod, jniname.jniValue()); if (env->ExceptionCheck()) { @@ -319,6 +330,7 @@ void ChannelManager::HandleChangeChannel(CommandResponseHelper> & externalIdList, const chip::Optional & data) { + DeviceLayer::StackUnlock unlock; ProgramGuideResponseType response; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -394,6 +408,8 @@ void ChannelManager::HandleGetProgramGuide( VerifyOrExit(mChannelManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetProgramGuideMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + { // NOTE: this example app does not pass the Data, PageToken, ChannelsArray or ExternalIdList through to the Java layer UtfString jData(env, ""); @@ -591,6 +607,7 @@ bool ChannelManager::HandleRecordProgram(const chip::CharSpan & programIdentifie const DataModel::DecodableList & externalIdList, const chip::ByteSpan & data) { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnValue(env != nullptr, false, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -628,6 +645,7 @@ bool ChannelManager::HandleCancelRecordProgram(const chip::CharSpan & programIde const DataModel::DecodableList & externalIdList, const chip::ByteSpan & data) { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnValue(env != nullptr, false, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); diff --git a/examples/tv-app/android/java/ContentAppAttributeDelegate.cpp b/examples/tv-app/android/java/ContentAppAttributeDelegate.cpp index 84e7d9933ad022..00b4ca7a225b2c 100644 --- a/examples/tv-app/android/java/ContentAppAttributeDelegate.cpp +++ b/examples/tv-app/android/java/ContentAppAttributeDelegate.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace chip { @@ -43,6 +44,7 @@ std::string ContentAppAttributeDelegate::Read(const chip::app::ConcreteReadAttri return ""; } + DeviceLayer::StackUnlock unlock; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); ChipLogProgress(Zcl, "ContentAppAttributeDelegate::Read being called for endpoint %d cluster %d attribute %d", aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId); diff --git a/examples/tv-app/android/java/ContentAppCommandDelegate.cpp b/examples/tv-app/android/java/ContentAppCommandDelegate.cpp index 3963140d1b5e65..2e5dcbe0f3b5e1 100644 --- a/examples/tv-app/android/java/ContentAppCommandDelegate.cpp +++ b/examples/tv-app/android/java/ContentAppCommandDelegate.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace chip { @@ -50,6 +51,7 @@ void ContentAppCommandDelegate::InvokeCommand(CommandHandlerInterface::HandlerCo { if (handlerContext.mRequestPath.mEndpointId >= FIXED_ENDPOINT_COUNT) { + DeviceLayer::StackUnlock unlock; TLV::TLVReader readerForJson; readerForJson.Init(handlerContext.mPayload); diff --git a/examples/tv-app/android/java/ContentLauncherManager.cpp b/examples/tv-app/android/java/ContentLauncherManager.cpp index caa14b04f9e938..f68e1131fa6fb8 100644 --- a/examples/tv-app/android/java/ContentLauncherManager.cpp +++ b/examples/tv-app/android/java/ContentLauncherManager.cpp @@ -51,6 +51,7 @@ void ContentLauncherManager::HandleLaunchContent(CommandResponseHelper playbackPreferences, bool useCurrentContext) { + DeviceLayer::StackUnlock unlock; Commands::LauncherResponse::Type response; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -61,6 +62,7 @@ void ContentLauncherManager::HandleLaunchContent(CommandResponseHelperExceptionClear(); { UtfString jData(env, data); @@ -106,6 +108,7 @@ void ContentLauncherManager::HandleLaunchUrl(CommandResponseHelperExceptionClear(); + { UtfString jContentUrl(env, contentUrl); UtfString jDisplayString(env, displayString); @@ -160,6 +165,7 @@ void ContentLauncherManager::HandleLaunchUrl(CommandResponseHelper acceptedHeadersList; @@ -170,6 +176,8 @@ CHIP_ERROR ContentLauncherManager::HandleGetAcceptHeaderList(AttributeValueEncod VerifyOrExit(mContentLauncherManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetAcceptHeaderMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray acceptedHeadersArray = (jobjectArray) env->CallObjectMethod(mContentLauncherManagerObject.ObjectRef(), mGetAcceptHeaderMethod); @@ -203,6 +211,7 @@ CHIP_ERROR ContentLauncherManager::HandleGetAcceptHeaderList(AttributeValueEncod uint32_t ContentLauncherManager::HandleGetSupportedStreamingProtocols() { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); uint32_t supportedStreamingProtocols = 0; @@ -213,6 +222,8 @@ uint32_t ContentLauncherManager::HandleGetSupportedStreamingProtocols() VerifyOrExit(mContentLauncherManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetSupportedStreamingProtocolsMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + { jlong jSupportedStreamingProtocols = env->CallLongMethod(mContentLauncherManagerObject.ObjectRef(), mGetSupportedStreamingProtocolsMethod); diff --git a/examples/tv-app/android/java/KeypadInputManager.cpp b/examples/tv-app/android/java/KeypadInputManager.cpp index a43a56cb860978..2382397fc351d9 100644 --- a/examples/tv-app/android/java/KeypadInputManager.cpp +++ b/examples/tv-app/android/java/KeypadInputManager.cpp @@ -44,6 +44,7 @@ void KeypadInputManager::NewManager(jint endpoint, jobject manager) void KeypadInputManager::HandleSendKey(CommandResponseHelper & helper, const CECKeyCodeEnum & keyCode) { + DeviceLayer::StackUnlock unlock; Commands::SendKeyResponse::Type response; jint ret = -1; diff --git a/examples/tv-app/android/java/LevelManager.cpp b/examples/tv-app/android/java/LevelManager.cpp index b79f150c7ae20e..f9be7578e830ab 100644 --- a/examples/tv-app/android/java/LevelManager.cpp +++ b/examples/tv-app/android/java/LevelManager.cpp @@ -112,6 +112,7 @@ CHIP_ERROR LevelManager::InitializeWithObjects(jobject managerObject) void LevelManager::HandleLevelChanged(uint8_t value) { + DeviceLayer::StackUnlock unlock; ChipLogProgress(Zcl, "LevelManager::HandleLevelChanged"); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); diff --git a/examples/tv-app/android/java/LowPowerManager.cpp b/examples/tv-app/android/java/LowPowerManager.cpp index 12e234964d4c5e..5c6906fcd1d659 100644 --- a/examples/tv-app/android/java/LowPowerManager.cpp +++ b/examples/tv-app/android/java/LowPowerManager.cpp @@ -64,6 +64,7 @@ void LowPowerManager::InitializeWithObjects(jobject managerObject) bool LowPowerManager::HandleSleep() { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); JniLocalReferenceScope scope(env); diff --git a/examples/tv-app/android/java/MediaInputManager.cpp b/examples/tv-app/android/java/MediaInputManager.cpp index bbc575b6eab378..0f1c922243c2be 100644 --- a/examples/tv-app/android/java/MediaInputManager.cpp +++ b/examples/tv-app/android/java/MediaInputManager.cpp @@ -51,6 +51,7 @@ void MediaInputManager::NewManager(jint endpoint, jobject manager) CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NO_ENV, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -60,6 +61,8 @@ CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncode VerifyOrExit(mMediaInputManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetInputListMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray inputArray = (jobjectArray) env->CallObjectMethod(mMediaInputManagerObject.ObjectRef(), mGetInputListMethod); if (env->ExceptionCheck()) @@ -121,6 +124,7 @@ CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncode uint8_t MediaInputManager::HandleGetCurrentInput() { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; jint index = -1; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -130,7 +134,8 @@ uint8_t MediaInputManager::HandleGetCurrentInput() ChipLogProgress(Zcl, "Received MediaInputManager::HandleGetCurrentInput"); VerifyOrExit(mMediaInputManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetCurrentInputMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); - VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); + + env->ExceptionClear(); { index = env->CallIntMethod(mMediaInputManagerObject.ObjectRef(), mGetCurrentInputMethod); @@ -154,6 +159,7 @@ uint8_t MediaInputManager::HandleGetCurrentInput() bool MediaInputManager::HandleSelectInput(const uint8_t index) { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnValue(env != nullptr, false, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -179,6 +185,7 @@ bool MediaInputManager::HandleSelectInput(const uint8_t index) bool MediaInputManager::HandleShowInputStatus() { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnValue(env != nullptr, false, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -204,6 +211,7 @@ bool MediaInputManager::HandleShowInputStatus() bool MediaInputManager::HandleHideInputStatus() { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnValue(env != nullptr, false, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -229,6 +237,7 @@ bool MediaInputManager::HandleHideInputStatus() bool MediaInputManager::HandleRenameInput(const uint8_t index, const chip::CharSpan & name) { + DeviceLayer::StackUnlock unlock; std::string inputname(name.data(), name.size()); jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -239,9 +248,10 @@ bool MediaInputManager::HandleRenameInput(const uint8_t index, const chip::CharS VerifyOrExit(mMediaInputManagerObject.HasValidObjectRef(), ChipLogError(Zcl, "mMediaInputManagerObject is not valid")); VerifyOrExit(mRenameInputMethod != nullptr, ChipLogError(Zcl, "mHideInputStatusMethod null")); + env->ExceptionClear(); + { UtfString jniInputname(env, inputname.data()); - env->ExceptionClear(); ret = env->CallBooleanMethod(mMediaInputManagerObject.ObjectRef(), mRenameInputMethod, static_cast(index), jniInputname.jniValue()); if (env->ExceptionCheck()) diff --git a/examples/tv-app/android/java/MediaPlaybackManager.cpp b/examples/tv-app/android/java/MediaPlaybackManager.cpp index 62abeb12ec30eb..667ab2ec41b382 100644 --- a/examples/tv-app/android/java/MediaPlaybackManager.cpp +++ b/examples/tv-app/android/java/MediaPlaybackManager.cpp @@ -97,6 +97,7 @@ CHIP_ERROR MediaPlaybackManager::HandleGetActiveAudioTrack(AttributeValueEncoder CHIP_ERROR MediaPlaybackManager::HandleGetActiveTrack(bool audio, AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; Structs::TrackStruct::Type response; Structs::TrackAttributesStruct::Type trackAttributes; response.trackAttributes = Nullable(trackAttributes); @@ -170,6 +171,7 @@ CHIP_ERROR MediaPlaybackManager::HandleGetAvailableAudioTracks(AttributeValueEnc CHIP_ERROR MediaPlaybackManager::HandleGetAvailableTracks(bool audio, AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -179,6 +181,8 @@ CHIP_ERROR MediaPlaybackManager::HandleGetAvailableTracks(bool audio, AttributeV VerifyOrExit(mMediaPlaybackManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetAvailableTracksMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + return aEncoder.EncodeList([this, env, audio](const auto & encoder) -> CHIP_ERROR { jobjectArray trackList = (jobjectArray) env->CallObjectMethod(mMediaPlaybackManagerObject.ObjectRef(), mGetAvailableTracksMethod, static_cast(audio)); @@ -317,6 +321,7 @@ bool MediaPlaybackManager::HandleActivateAudioTrack(const chip::CharSpan & track bool MediaPlaybackManager::HandleActivateTrack(bool audio, const chip::CharSpan & trackId) { + DeviceLayer::StackUnlock unlock; std::string id(trackId.data(), trackId.size()); jint ret = -1; @@ -328,9 +333,11 @@ bool MediaPlaybackManager::HandleActivateTrack(bool audio, const chip::CharSpan ChipLogProgress(Zcl, "MediaPlaybackManager::HandleActivateAudioTrack"); VerifyOrExit(mMediaPlaybackManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mActivateTrackMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + env->ExceptionClear(); + { UtfString jniid(env, id.c_str()); - env->ExceptionClear(); ret = env->CallIntMethod(mMediaPlaybackManagerObject.ObjectRef(), mActivateTrackMethod, static_cast(audio), jniid.jniValue()); if (env->ExceptionCheck()) @@ -351,6 +358,7 @@ bool MediaPlaybackManager::HandleActivateTextTrack(const chip::CharSpan & trackI bool MediaPlaybackManager::HandleDeactivateTextTrack() { + DeviceLayer::StackUnlock unlock; jint ret = -1; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -439,6 +447,7 @@ void MediaPlaybackManager::InitializeWithObjects(jobject managerObject) uint64_t MediaPlaybackManager::HandleMediaRequestGetAttribute(MediaPlaybackRequestAttribute attribute) { + DeviceLayer::StackUnlock unlock; uint64_t ret = std::numeric_limits::max(); jlong jAttributeValue = -1; CHIP_ERROR err = CHIP_NO_ERROR; @@ -450,6 +459,8 @@ uint64_t MediaPlaybackManager::HandleMediaRequestGetAttribute(MediaPlaybackReque VerifyOrExit(mMediaPlaybackManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetAttributeMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + jAttributeValue = env->CallLongMethod(mMediaPlaybackManagerObject.ObjectRef(), mGetAttributeMethod, static_cast(attribute)); if (env->ExceptionCheck()) @@ -480,6 +491,7 @@ uint64_t MediaPlaybackManager::HandleMediaRequestGetAttribute(MediaPlaybackReque long MediaPlaybackManager::HandleMediaRequestGetLongAttribute(MediaPlaybackRequestAttribute attribute) { + DeviceLayer::StackUnlock unlock; long ret = 0; jlong jAttributeValue = -1; CHIP_ERROR err = CHIP_NO_ERROR; @@ -491,6 +503,8 @@ long MediaPlaybackManager::HandleMediaRequestGetLongAttribute(MediaPlaybackReque VerifyOrExit(mMediaPlaybackManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetAttributeMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + jAttributeValue = env->CallLongMethod(mMediaPlaybackManagerObject.ObjectRef(), mGetAttributeMethod, static_cast(attribute)); if (env->ExceptionCheck()) @@ -516,6 +530,7 @@ Commands::PlaybackResponse::Type MediaPlaybackManager::HandleMediaRequest(MediaP uint64_t deltaPositionMilliseconds) { + DeviceLayer::StackUnlock unlock; Commands::PlaybackResponse::Type response; jint ret = -1; @@ -553,6 +568,7 @@ Commands::PlaybackResponse::Type MediaPlaybackManager::HandleMediaRequest(MediaP CHIP_ERROR MediaPlaybackManager::HandleGetSampledPosition(AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; Structs::PlaybackPositionStruct::Type response; response.updatedAt = 0; response.position = Nullable(0); diff --git a/examples/tv-app/android/java/MessagesManager.cpp b/examples/tv-app/android/java/MessagesManager.cpp new file mode 100644 index 00000000000000..9203d7b54510f5 --- /dev/null +++ b/examples/tv-app/android/java/MessagesManager.cpp @@ -0,0 +1,454 @@ +/** + * + * 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. + */ + +#include "MessagesManager.h" +#include "TvApp-JNI.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters::Messages; +using namespace chip::Uint8; +using MessageResponseOption = chip::app::Clusters::Messages::Structs::MessageResponseOptionStruct::Type; + +/** @brief Messages Cluster Init + * + * This function is called when a specific cluster is initialized. It gives the + * application an opportunity to take care of cluster initialization procedures. + * It is called exactly once for each endpoint where cluster is present. + * + */ +void emberAfMessagesClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "------------TV Android App: Messages::PostClusterInit"); + TvAppJNIMgr().PostClusterInit(chip::app::Clusters::Messages::Id, endpoint); +} + +void MessagesManager::NewManager(jint endpoint, jobject manager) +{ + ChipLogProgress(Zcl, "-----TV Android App: Messages::SetDefaultDelegate"); + MessagesManager * mgr = new MessagesManager(); + VerifyOrReturn(mgr != nullptr, ChipLogError(Zcl, "Failed to create MessagesManager")); + mgr->InitializeWithObjects(manager); + chip::app::Clusters::Messages::SetDefaultDelegate(static_cast(endpoint), mgr); +} + +void MessagesManager::InitializeWithObjects(jobject managerObject) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for MessagesManager")); + + VerifyOrReturn(mMessagesManagerObject.Init(managerObject) == CHIP_NO_ERROR, + ChipLogError(Zcl, "Failed to init mMessagesManagerObject")); + + jclass managerClass = env->GetObjectClass(managerObject); + VerifyOrReturn(managerClass != nullptr, ChipLogError(Zcl, "Failed to get MessagesManager Java class")); + + mGetMessagesMethod = env->GetMethodID(managerClass, "getMessages", "()[Lcom/matter/tv/server/tvapp/Message;"); + if (mGetMessagesMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MessagesManager 'getMessages' method"); + env->ExceptionClear(); + } + + mPresentMessagesMethod = + env->GetMethodID(managerClass, "presentMessages", "(Ljava/lang/String;IIJILjava/lang/String;Ljava/util/HashMap;)Z"); + if (mPresentMessagesMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MessagesManager 'presentMessages' method"); + env->ExceptionClear(); + } + + mCancelMessagesMethod = env->GetMethodID(managerClass, "cancelMessage", "(Ljava/lang/String;)Z"); + if (mCancelMessagesMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MessagesManager 'cancelMessage' method"); + env->ExceptionClear(); + } +} + +uint32_t MessagesManager::GetFeatureMap(chip::EndpointId endpoint) +{ + if (endpoint >= MATTER_DM_CONTENT_LAUNCHER_CLUSTER_SERVER_ENDPOINT_COUNT) + { + return kEndpointFeatureMap; + } + + BitMask FeatureMap; + FeatureMap.Set(Feature::kReceivedConfirmation); + FeatureMap.Set(Feature::kConfirmationResponse); + FeatureMap.Set(Feature::kConfirmationReply); + FeatureMap.Set(Feature::kProtectedMessages); + + uint32_t featureMap = FeatureMap.Raw(); + // forcing to all features since this implementation supports all + // Attributes::FeatureMap::Get(endpoint, &featureMap); + return featureMap; +} + +CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) +{ + DeviceLayer::StackUnlock unlock; + CHIP_ERROR err = CHIP_NO_ERROR; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); + JniLocalReferenceScope scope(env); + + env->ExceptionClear(); + + ChipLogProgress(Zcl, "Received MessagesManager::HandleGetMessages"); + VerifyOrExit(mMessagesManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mGetMessagesMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { + jobjectArray messagesList = + static_cast(env->CallObjectMethod(mMessagesManagerObject.ObjectRef(), mGetMessagesMethod)); + if (env->ExceptionCheck()) + { + ChipLogError(Zcl, "Java exception in MessagesManager::HandleGetMessages"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; + } + + jint length = env->GetArrayLength(messagesList); + + for (jint i = 0; i < length; i++) + { + std::vector options; + std::vector optionLabels; + uint8_t buf[kMessageIdLength]; + + chip::app::Clusters::Messages::Structs::MessageStruct::Type message; + jobject messageObject = env->GetObjectArrayElement(messagesList, i); + jclass messageClass = env->GetObjectClass(messageObject); + + jfieldID getMessageIdField = env->GetFieldID(messageClass, "messageId", "Ljava/lang/String;"); + jstring jmessageId = static_cast(env->GetObjectField(messageObject, getMessageIdField)); + JniUtfString messageId(env, jmessageId); + if (jmessageId != nullptr) + { + VerifyOrReturnValue(chip::Encoding::HexToBytes(messageId.charSpan().data(), messageId.charSpan().size(), buf, + sizeof(buf)) == sizeof(buf), + CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(Zcl, "HexToBytes failed")); + message.messageID = ByteSpan(buf, sizeof(buf)); + } + + jfieldID getMessageTextField = env->GetFieldID(messageClass, "messageText", "Ljava/lang/String;"); + jstring jmessageText = static_cast(env->GetObjectField(messageObject, getMessageTextField)); + JniUtfString messageText(env, jmessageText); + if (jmessageText != nullptr) + { + message.messageText = messageText.charSpan(); + } + + jfieldID messageControlField = env->GetFieldID(messageClass, "messageControl", "I"); + jint jmessageControl = env->GetIntField(messageObject, messageControlField); + message.messageControl = static_cast>(static_cast(jmessageControl)); + + jfieldID priorityField = env->GetFieldID(messageClass, "priority", "I"); + jint jpriority = env->GetIntField(messageObject, priorityField); + if (jpriority >= 0) + { + message.priority = MessagePriorityEnum(static_cast(jpriority)); + } + + jfieldID startTimeField = env->GetFieldID(messageClass, "startTime", "J"); + jlong jstartTime = env->GetLongField(messageObject, startTimeField); + if (jstartTime >= 0) + { + message.startTime = DataModel::Nullable(static_cast(jstartTime)); + } + + jfieldID durationField = env->GetFieldID(messageClass, "duration", "I"); + jint jduration = env->GetIntField(messageObject, durationField); + if (jduration >= 0) + { + message.duration = DataModel::Nullable(static_cast(jduration)); + } + + jfieldID getResponseOptionsField = + env->GetFieldID(messageClass, "responseOptions", "[Lcom/matter/tv/server/tvapp/MessageResponseOption;"); + + jobjectArray responsesArray = static_cast(env->GetObjectField(messageObject, getResponseOptionsField)); + jint size = env->GetArrayLength(responsesArray); + if (size > 0) + { + for (jint j = 0; j < size; j++) + { + MessageResponseOption option; + + jobject responseOptionObject = env->GetObjectArrayElement(responsesArray, j); + jclass responseOptionClass = env->GetObjectClass(responseOptionObject); + + jfieldID idField = env->GetFieldID(responseOptionClass, "id", "J"); + jlong jid = env->GetLongField(responseOptionObject, idField); + option.messageResponseID = Optional(static_cast(jid)); + + jfieldID getLabelField = env->GetFieldID(responseOptionClass, "label", "Ljava/lang/String;"); + jstring jlabelText = static_cast(env->GetObjectField(responseOptionObject, getLabelField)); + VerifyOrReturnValue(jlabelText != nullptr, CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(Zcl, "jlabelText null")); + JniUtfString * label = new JniUtfString(env, jlabelText); + VerifyOrReturnValue(label != nullptr, CHIP_ERROR_NO_MEMORY, ChipLogError(Zcl, "label null")); + + optionLabels.push_back(label); + + option.label = Optional(label->charSpan()); + + options.push_back(option); + } + + message.responses = Optional>( + DataModel::List(options.data(), options.size())); + } + ReturnErrorOnFailure(encoder.Encode(message)); + for (JniUtfString * optionLabel : optionLabels) + { + delete optionLabel; + } + } + + return CHIP_NO_ERROR; + }); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "MessagesManager::HandleGetMessages status error: %s", err.AsString()); + } + return err; +} + +CHIP_ERROR MessagesManager::HandleGetActiveMessageIds(AttributeValueEncoder & aEncoder) +{ + DeviceLayer::StackUnlock unlock; + CHIP_ERROR err = CHIP_NO_ERROR; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); + JniLocalReferenceScope scope(env); + + ChipLogProgress(Zcl, "Received MessagesManager::HandleGetActiveMessageIds"); + VerifyOrExit(mMessagesManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mGetMessagesMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + env->ExceptionClear(); + + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { + jobjectArray messagesList = + static_cast(env->CallObjectMethod(mMessagesManagerObject.ObjectRef(), mGetMessagesMethod)); + if (env->ExceptionCheck()) + { + ChipLogError(Zcl, "Java exception in MessagesManager::HandleGetActiveMessageIds"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; + } + + jint length = env->GetArrayLength(messagesList); + + for (jint i = 0; i < length; i++) + { + jobject messageObject = env->GetObjectArrayElement(messagesList, i); + jclass messageClass = env->GetObjectClass(messageObject); + + jfieldID getMessageIdField = env->GetFieldID(messageClass, "messageId", "Ljava/lang/String;"); + jstring jmessageId = static_cast(env->GetObjectField(messageObject, getMessageIdField)); + JniUtfString messageId(env, jmessageId); + if (jmessageId != nullptr) + { + uint8_t buf[kMessageIdLength]; + VerifyOrReturnValue(chip::Encoding::HexToBytes(messageId.charSpan().data(), messageId.charSpan().size(), buf, + sizeof(buf)) == sizeof(buf), + CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(Zcl, "HexToBytes failed")); + + ReturnErrorOnFailure(encoder.Encode(ByteSpan(buf, sizeof(buf)))); + } + } + + return CHIP_NO_ERROR; + }); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "MessagesManager::HandleGetMessages status error: %s", err.AsString()); + } + + return err; +} + +CHIP_ERROR MessagesManager::HandlePresentMessagesRequest( + const ByteSpan & messageId, const MessagePriorityEnum & priority, const BitMask & messageControl, + const DataModel::Nullable & startTime, const DataModel::Nullable & duration, const CharSpan & messageText, + const Optional> & responses) +{ + DeviceLayer::StackUnlock unlock; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); + JniLocalReferenceScope scope(env); + + ChipLogProgress(Zcl, "Received MessagesManager::HandlePresentMessagesRequest"); + VerifyOrReturnError(mMessagesManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Invalid mMessagesManagerObject")); + VerifyOrReturnError(mPresentMessagesMethod != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "mPresentMessagesMethod null")); + + env->ExceptionClear(); + { + char hex_buf[(kMessageIdLength * 2) + 1]; + VerifyOrReturnError( + CHIP_NO_ERROR == + chip::Encoding::BytesToUppercaseHexString(messageId.data(), messageId.size(), hex_buf, sizeof(hex_buf)), + CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "BytesToUppercaseHexString failed")); + + jstring jid = env->NewStringUTF(hex_buf); + if (jid == nullptr) + { + return CHIP_ERROR_INTERNAL; + } + + std::string smessageText(messageText.data(), messageText.size()); + jstring jmessageText = env->NewStringUTF(smessageText.c_str()); + if (jmessageText == nullptr) + { + return CHIP_ERROR_INTERNAL; + } + + jint jcontrol = static_cast(messageControl.Raw()); + jint jduration = -1; + if (!duration.IsNull()) + { + jduration = static_cast(duration.Value()); + } + jlong jstartTime = -1; + if (!startTime.IsNull()) + { + jstartTime = static_cast(startTime.Value()); + } + + jint jpriority = static_cast(priority); + + jclass hashMapClass = env->FindClass("java/util/HashMap"); + VerifyOrReturnError(hashMapClass != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find class HashMap")); + jmethodID hashMapCtor = env->GetMethodID(hashMapClass, "", "()V"); + VerifyOrReturnError(hashMapCtor != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Could not find HashMap constructor")); + jobject joptions = env->NewObject(hashMapClass, hashMapCtor); + VerifyOrReturnError(joptions != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not create HashMap")); + + if (responses.HasValue()) + { + jmethodID hashMapPut = + env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + VerifyOrReturnError(hashMapPut != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find HashMap put")); + + jclass longClass = env->FindClass("java/lang/Long"); + VerifyOrReturnError(longClass != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find class Long")); + jmethodID longCtor = env->GetMethodID(longClass, "", "(J)V"); + VerifyOrReturnError(longCtor != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Could not find Long constructor")); + + auto iter = responses.Value().begin(); + while (iter.Next()) + { + auto & response = iter.GetValue(); + + std::string label(response.label.Value().data(), response.label.Value().size()); + jstring jlabel = env->NewStringUTF(label.c_str()); + if (jlabel == nullptr) + { + return CHIP_ERROR_INTERNAL; + } + + jobject jlong = env->NewObject(longClass, longCtor, response.messageResponseID.Value()); + VerifyOrReturnError(jlong != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not create Long")); + + // add to HashMap + env->CallObjectMethod(joptions, hashMapPut, jlong, jlabel); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in MessagesManager::HandlePresentMessagesRequest"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INTERNAL; + } + } + } + + env->CallBooleanMethod(mMessagesManagerObject.ObjectRef(), mPresentMessagesMethod, jid, jpriority, jcontrol, jstartTime, + jduration, jmessageText, joptions); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in MessagesManager::HandlePresentMessagesRequest"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INTERNAL; + } + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR MessagesManager::HandleCancelMessagesRequest(const DataModel::DecodableList & messageIds) +{ + DeviceLayer::StackUnlock unlock; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); + JniLocalReferenceScope scope(env); + + ChipLogProgress(Zcl, "Received MessagesManager::HandleCancelMessagesRequest"); + VerifyOrReturnError(mMessagesManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Invalid mMessagesManagerObject")); + VerifyOrReturnError(mCancelMessagesMethod != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "mCancelMessagesMethod null")); + + env->ExceptionClear(); + + auto iter = messageIds.begin(); + while (iter.Next()) + { + auto & id = iter.GetValue(); + + char hex_buf[(kMessageIdLength * 2) + 1]; + VerifyOrReturnError(CHIP_NO_ERROR == + chip::Encoding::BytesToUppercaseHexString(id.data(), id.size(), hex_buf, sizeof(hex_buf)), + CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "BytesToUppercaseHexString failed")); + + jstring jid = env->NewStringUTF(hex_buf); + if (jid == nullptr) + { + return CHIP_ERROR_INTERNAL; + } + + env->CallBooleanMethod(mMessagesManagerObject.ObjectRef(), mCancelMessagesMethod, jid); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in MessagesManager::HandleCancelMessagesRequest"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INTERNAL; + } + } + return CHIP_NO_ERROR; +} diff --git a/examples/tv-app/android/java/MessagesManager.h b/examples/tv-app/android/java/MessagesManager.h new file mode 100644 index 00000000000000..563192a542bdf6 --- /dev/null +++ b/examples/tv-app/android/java/MessagesManager.h @@ -0,0 +1,63 @@ +/** + * + * 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. + */ + +#pragma once + +#include + +#include +#include + +#include +#include + +class MessagesManager : public chip::app::Clusters::Messages::Delegate +{ +public: + static void NewManager(jint endpoint, jobject manager); + void InitializeWithObjects(jobject managerObject); + + // Commands + CHIP_ERROR HandlePresentMessagesRequest( + const chip::ByteSpan & messageId, const chip::app::Clusters::Messages::MessagePriorityEnum & priority, + const chip::BitMask & messageControl, + const chip::app::DataModel::Nullable & startTime, const chip::app::DataModel::Nullable & duration, + const chip::CharSpan & messageText, + const chip::Optional< + chip::app::DataModel::DecodableList> & + responses) override; + CHIP_ERROR HandleCancelMessagesRequest(const chip::app::DataModel::DecodableList & messageIds) override; + + // Attributes + CHIP_ERROR HandleGetMessages(chip::app::AttributeValueEncoder & aEncoder) override; + CHIP_ERROR HandleGetActiveMessageIds(chip::app::AttributeValueEncoder & aEncoder) override; + + // Global Attributes + uint32_t GetFeatureMap(chip::EndpointId endpoint) override; + // uint16_t GetClusterRevision(chip::EndpointId endpoint) override; + +private: + chip::JniGlobalReference mMessagesManagerObject; + jmethodID mGetMessagesMethod = nullptr; + + jmethodID mPresentMessagesMethod = nullptr; + jmethodID mCancelMessagesMethod = nullptr; + + // TODO: set this based upon meta data from app + static constexpr uint32_t kEndpointFeatureMap = 15; + // static constexpr uint16_t kClusterRevision = 1; +}; diff --git a/examples/tv-app/android/java/MyUserPrompter-JNI.cpp b/examples/tv-app/android/java/MyUserPrompter-JNI.cpp index d2c83b28a1ce8f..82b06e210d7853 100644 --- a/examples/tv-app/android/java/MyUserPrompter-JNI.cpp +++ b/examples/tv-app/android/java/MyUserPrompter-JNI.cpp @@ -78,6 +78,7 @@ JNIMyUserPrompter::JNIMyUserPrompter(jobject provider) */ void JNIMyUserPrompter::PromptForCommissionOKPermission(uint16_t vendorId, uint16_t productId, const char * commissioneeName) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); std::string stringCommissioneeName(commissioneeName); @@ -119,6 +120,7 @@ void JNIMyUserPrompter::PromptForCommissionOKPermission(uint16_t vendorId, uint1 void JNIMyUserPrompter::PromptForCommissionPasscode(uint16_t vendorId, uint16_t productId, const char * commissioneeName, uint16_t pairingHint, const char * pairingInstruction) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); std::string stringCommissioneeName(commissioneeName); @@ -198,6 +200,7 @@ void JNIMyUserPrompter::PromptCommissioningStarted(uint16_t vendorId, uint16_t p */ void JNIMyUserPrompter::PromptCommissioningSucceeded(uint16_t vendorId, uint16_t productId, const char * commissioneeName) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); std::string stringCommissioneeName(commissioneeName); @@ -234,6 +237,7 @@ void JNIMyUserPrompter::PromptCommissioningSucceeded(uint16_t vendorId, uint16_t */ void JNIMyUserPrompter::PromptCommissioningFailed(const char * commissioneeName, CHIP_ERROR error) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); std::string stringCommissioneeName(commissioneeName); diff --git a/examples/tv-app/android/java/OnOffManager.cpp b/examples/tv-app/android/java/OnOffManager.cpp index 9a330754aa4a16..db694748e8a11b 100644 --- a/examples/tv-app/android/java/OnOffManager.cpp +++ b/examples/tv-app/android/java/OnOffManager.cpp @@ -113,6 +113,7 @@ CHIP_ERROR OnOffManager::InitializeWithObjects(jobject managerObject) void OnOffManager::HandleOnOffChanged(bool value) { + DeviceLayer::StackUnlock unlock; ChipLogProgress(Zcl, "OnOffManager::HandleOnOffChanged"); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); diff --git a/examples/tv-app/android/java/TVApp-JNI.cpp b/examples/tv-app/android/java/TVApp-JNI.cpp index 6bbc35ed297415..72279c49dca9d7 100644 --- a/examples/tv-app/android/java/TVApp-JNI.cpp +++ b/examples/tv-app/android/java/TVApp-JNI.cpp @@ -27,6 +27,7 @@ #include "LowPowerManager.h" #include "MediaInputManager.h" #include "MediaPlaybackManager.h" +#include "MessagesManager.h" #include "MyUserPrompter-JNI.h" #include "OnOffManager.h" #include "WakeOnLanManager.h" @@ -137,6 +138,11 @@ JNI_METHOD(void, setMediaPlaybackManager)(JNIEnv *, jobject, jint endpoint, jobj MediaPlaybackManager::NewManager(endpoint, manager); } +JNI_METHOD(void, setMessagesManager)(JNIEnv *, jobject, jint endpoint, jobject manager) +{ + MessagesManager::NewManager(endpoint, manager); +} + JNI_METHOD(void, setChannelManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { ChannelManager::NewManager(endpoint, manager); diff --git a/examples/tv-app/android/java/WakeOnLanManager.cpp b/examples/tv-app/android/java/WakeOnLanManager.cpp index 5a3093aca53332..a50ddca72bbb3e 100644 --- a/examples/tv-app/android/java/WakeOnLanManager.cpp +++ b/examples/tv-app/android/java/WakeOnLanManager.cpp @@ -51,6 +51,7 @@ void WakeOnLanManager::NewManager(jint endpoint, jobject manager) CHIP_ERROR WakeOnLanManager::HandleGetMacAddress(chip::app::AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; jobject javaMac; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Clusters.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Clusters.java index d699ca68ea6365..5928c1b10181c7 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Clusters.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Clusters.java @@ -129,7 +129,7 @@ public class Clusters { public static final long ClusterId_ApplicationBasic = 0x0000050D; public static final long ClusterId_AccountLogin = 0x0000050E; public static final long ClusterId_TestCluster = 0xFFF1FC05; - public static final long ClusterId_Messaging = 0x00000703; + public static final long ClusterId_Messaging = 0x00000097; public static final long ClusterId_ApplianceIdentification = 0x00000B00; public static final long ClusterId_MeterIdentification = 0x00000B01; public static final long ClusterId_ApplianceEventsAndAlert = 0x00000B02; diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java new file mode 100644 index 00000000000000..c194ffb44f9ee1 --- /dev/null +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java @@ -0,0 +1,46 @@ +/* + * 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. + * + */ +package com.matter.tv.server.tvapp; + +public class Message { + + public String messageId; + public int priority; + public int messageControl; + public long startTime; + public int duration; + public String messageText; + public MessageResponseOption responseOptions[]; + + public Message( + String messageId, + int priority, + int messageControl, + long startTime, + int duration, + String messageText, + MessageResponseOption responseOptions[]) { + this.messageId = messageId; + this.priority = priority; + this.messageControl = messageControl; + this.startTime = startTime; + this.duration = duration; + this.messageText = messageText; + this.responseOptions = responseOptions; + } +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java new file mode 100644 index 00000000000000..5d8e77d1e91389 --- /dev/null +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java @@ -0,0 +1,28 @@ +/* + * 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. + * + */ +package com.matter.tv.server.tvapp; + +public class MessageResponseOption { + public long id = -1; + public String label = "na"; + + public MessageResponseOption(long id, String label) { + this.id = id; + this.label = label; + } +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java new file mode 100644 index 00000000000000..0a5680866714c6 --- /dev/null +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java @@ -0,0 +1,36 @@ +/* + * 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. + * + */ +package com.matter.tv.server.tvapp; + +import java.util.HashMap; + +public interface MessagesManager { + + Message[] getMessages(); + + boolean presentMessages( + String messageId, + int priority, + int messageControl, + long startTime, + int duration, + String messageText, + HashMap responseOptions); + + boolean cancelMessage(String messageId); +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java new file mode 100644 index 00000000000000..63fef69d35c936 --- /dev/null +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java @@ -0,0 +1,82 @@ +/* + * 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. + * + */ +package com.matter.tv.server.tvapp; + +import android.util.Log; +import java.util.HashMap; +import java.util.Map; + +public class MessagesManagerStub implements MessagesManager { + private static final String TAG = MessagesManagerStub.class.getSimpleName(); + + private int endpoint = -1; + + private Map messages = new HashMap(); + + public MessagesManagerStub(int endpoint) { + this.endpoint = endpoint; + Log.d(TAG, "MessagesManagerStub: at " + this.endpoint); + + HashMap responseOptions = new HashMap(); + responseOptions.put(new Long(1), "Yes"); + responseOptions.put(new Long(2), "No"); + presentMessages( + "31323334353637383930313233343536", 1, 1, 30, 60, "TestMessage", responseOptions); + Log.d(TAG, "MessagesManagerStub: added dummy message"); + } + + @Override + public Message[] getMessages() { + Log.d(TAG, "getMessages: at " + this.endpoint); + return messages.values().toArray(new Message[0]); + } + + @Override + public boolean presentMessages( + String messageId, + int priority, + int messageControl, + long startTime, + int duration, + String messageText, + HashMap responseOptions) { + Log.d( + TAG, "presentMessages: at " + this.endpoint + " id:" + messageId + " text:" + messageText); + MessageResponseOption[] options = new MessageResponseOption[responseOptions.size()]; + int i = 0; + + for (Map.Entry set : responseOptions.entrySet()) { + Log.d(TAG, "presentMessages option: key:" + set.getKey() + " value:" + set.getValue()); + options[i] = new MessageResponseOption(set.getKey().longValue(), set.getValue()); + i++; + } + + messages.put( + messageId, + new Message( + messageId, priority, messageControl, startTime, duration, messageText, options)); + return true; + } + + @Override + public boolean cancelMessage(String messageId) { + Log.d(TAG, "cancelMessage: at " + this.endpoint + " messageId:" + messageId); + messages.remove(messageId); + return true; // per spec, succeed unless error + } +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java index d8bb564370afa4..eaf207e45f3618 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java @@ -57,6 +57,8 @@ private void postClusterInit(long clusterId, int endpoint) { public native void setMediaPlaybackManager(int endpoint, MediaPlaybackManager manager); + public native void setMessagesManager(int endpoint, MessagesManager manager); + public native void setChannelManager(int endpoint, ChannelManager manager); public native void setOnOffManager(int endpoint, OnOffManager manager); diff --git a/examples/tv-app/tv-common/clusters/messages/MessagesManager.cpp b/examples/tv-app/tv-common/clusters/messages/MessagesManager.cpp index 11068dc1d720c8..6ffbb9a3476258 100644 --- a/examples/tv-app/tv-common/clusters/messages/MessagesManager.cpp +++ b/examples/tv-app/tv-common/clusters/messages/MessagesManager.cpp @@ -18,64 +18,94 @@ #include "MessagesManager.h" #include +#include using namespace std; +using namespace chip; using namespace chip::app; using namespace chip::app::Clusters::Messages; -using Message = chip::app::Clusters::Messages::Structs::MessageStruct::Type; +using Message = chip::app::Clusters::Messages::Structs::MessageStruct::Type; +using MessageResponseOption = chip::app::Clusters::Messages::Structs::MessageResponseOptionStruct::Type; // Commands -void MessagesManager::HandlePresentMessagesRequest( - const chip::ByteSpan & messageId, const MessagePriorityEnum & priority, - const chip::BitMask & messageControl, const chip::app::DataModel::Nullable & startTime, - const chip::app::DataModel::Nullable & duration, const chip::CharSpan & messageText, - const chip::Optional> & responses) +CHIP_ERROR MessagesManager::HandlePresentMessagesRequest( + const ByteSpan & messageId, const MessagePriorityEnum & priority, const BitMask & messageControl, + const DataModel::Nullable & startTime, const DataModel::Nullable & duration, const CharSpan & messageText, + const Optional> & responses) { - Message message{ - // TODO: Enable id - chip::ByteSpan(), priority, messageControl, startTime, duration, - // TODO: Enable text - chip::CharSpan() - // TODO: Convert responses to Optional> message.responses = responses; - }; + ChipLogProgress(Zcl, "HandlePresentMessagesRequest message:%s", std::string(messageText.data(), messageText.size()).c_str()); + + auto cachedMessage = CachedMessage(messageId, priority, messageControl, startTime, duration, + std::string(messageText.data(), messageText.size())); + if (responses.HasValue()) + { + auto iter = responses.Value().begin(); + while (iter.Next()) + { + auto & response = iter.GetValue(); + + CachedMessageOption option(response.messageResponseID.Value(), + std::string(response.label.Value().data(), response.label.Value().size())); + + cachedMessage.AddOption(option); + } + } + + mCachedMessages.push_back(cachedMessage); - mMessages.push_back(message); // Add your code to present Message + ChipLogProgress(Zcl, "HandlePresentMessagesRequest complete"); + return CHIP_NO_ERROR; } -void MessagesManager::HandleCancelMessagesRequest(const chip::app::DataModel::DecodableList & messageIds) +CHIP_ERROR MessagesManager::HandleCancelMessagesRequest(const DataModel::DecodableList & messageIds) { - // TODO: Cancel Message + auto iter = messageIds.begin(); + while (iter.Next()) + { + auto & id = iter.GetValue(); + + mCachedMessages.remove_if([id](CachedMessage & entry) { return entry.MessageIdMatches(id); }); + // per spec, the command succeeds even when the message id does not match an existing message + } + return CHIP_NO_ERROR; } // Attributes -CHIP_ERROR MessagesManager::HandleGetMessages(chip::app::AttributeValueEncoder & aEncoder) +CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) { return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { - for (Message & entry : mMessages) + for (CachedMessage & entry : mCachedMessages) { - ReturnErrorOnFailure(encoder.Encode(entry)); + ReturnErrorOnFailure(encoder.Encode(entry.GetMessage())); } return CHIP_NO_ERROR; }); } -CHIP_ERROR MessagesManager::HandleGetActiveMessageIds(chip::app::AttributeValueEncoder & aEncoder) +CHIP_ERROR MessagesManager::HandleGetActiveMessageIds(AttributeValueEncoder & aEncoder) { return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { - for (Message & entry : mMessages) + for (CachedMessage & entry : mCachedMessages) { - ReturnErrorOnFailure(encoder.Encode(entry.messageID)); + ReturnErrorOnFailure(encoder.Encode(entry.GetMessage().messageID)); } return CHIP_NO_ERROR; }); } // Global Attributes -uint32_t MessagesManager::GetFeatureMap(chip::EndpointId endpoint) +uint32_t MessagesManager::GetFeatureMap(EndpointId endpoint) { - uint32_t featureMap = 0; - Attributes::FeatureMap::Get(endpoint, &featureMap); + BitMask FeatureMap; + FeatureMap.Set(Feature::kReceivedConfirmation); + FeatureMap.Set(Feature::kConfirmationResponse); + FeatureMap.Set(Feature::kConfirmationReply); + FeatureMap.Set(Feature::kProtectedMessages); + + uint32_t featureMap = FeatureMap.Raw(); + ChipLogProgress(Zcl, "GetFeatureMap featureMap=%d", featureMap); + // forcing to all features since this implementation supports all + // Attributes::FeatureMap::Get(endpoint, &featureMap); return featureMap; } diff --git a/examples/tv-app/tv-common/clusters/messages/MessagesManager.h b/examples/tv-app/tv-common/clusters/messages/MessagesManager.h index 97ff5096b8ef7d..325cd56fc788af 100644 --- a/examples/tv-app/tv-common/clusters/messages/MessagesManager.h +++ b/examples/tv-app/tv-common/clusters/messages/MessagesManager.h @@ -21,12 +21,109 @@ #include #include +#include + +struct CachedMessageOption +{ + CachedMessageOption(uint32_t id, std::string label) : + mLabel(label), mOption{ chip::MakeOptional(id), chip::MakeOptional(chip::CharSpan::fromCharString(mLabel.c_str())) } + {} + + CachedMessageOption(const CachedMessageOption & option) : + mLabel(option.mLabel), + mOption{ option.mOption.messageResponseID, chip::MakeOptional(chip::CharSpan::fromCharString(mLabel.c_str())) } + {} + + CachedMessageOption & operator=(const CachedMessageOption & option) = delete; + + chip::app::Clusters::Messages::Structs::MessageResponseOptionStruct::Type GetMessageOption() { return mOption; } + + ~CachedMessageOption() {} + +protected: + std::string mLabel; + chip::app::Clusters::Messages::Structs::MessageResponseOptionStruct::Type mOption; +}; + +struct CachedMessage +{ + CachedMessage(const CachedMessage & message) : + mPriority(message.mPriority), mMessageControl(message.mMessageControl), mStartTime(message.mStartTime), + mDuration(message.mDuration), mMessageText(message.mMessageText), mOptions(message.mOptions) + { + memcpy(mMessageIdBuffer, message.mMessageIdBuffer, sizeof(mMessageIdBuffer)); + + for (CachedMessageOption & entry : mOptions) + { + mResponseOptions.push_back(entry.GetMessageOption()); + } + } + + CachedMessage & operator=(const CachedMessage & message) = delete; + + CachedMessage(const chip::ByteSpan & messageId, const chip::app::Clusters::Messages::MessagePriorityEnum & priority, + const chip::BitMask & messageControl, + const chip::app::DataModel::Nullable & startTime, + const chip::app::DataModel::Nullable & duration, std::string messageText) : + mPriority(priority), + mMessageControl(messageControl), mStartTime(startTime), mDuration(duration), mMessageText(messageText) + { + memcpy(mMessageIdBuffer, messageId.data(), sizeof(mMessageIdBuffer)); + } + + bool MessageIdMatches(const chip::ByteSpan & id) { return chip::ByteSpan(mMessageIdBuffer).data_equal(id); } + + void AddOption(CachedMessageOption option) + { + mOptions.push_back(option); + mResponseOptions.push_back(option.GetMessageOption()); + } + + chip::app::Clusters::Messages::Structs::MessageStruct::Type GetMessage() + { + if (mResponseOptions.size() > 0) + { + chip::app::DataModel::List options( + mResponseOptions.data(), mResponseOptions.size()); + chip::app::Clusters::Messages::Structs::MessageStruct::Type message{ chip::ByteSpan(mMessageIdBuffer), + mPriority, + mMessageControl, + mStartTime, + mDuration, + chip::CharSpan::fromCharString( + mMessageText.c_str()), + chip::MakeOptional(options) }; + return message; + } + chip::app::Clusters::Messages::Structs::MessageStruct::Type message{ chip::ByteSpan(mMessageIdBuffer), + mPriority, + mMessageControl, + mStartTime, + mDuration, + chip::CharSpan::fromCharString(mMessageText.c_str()) }; + return message; + } + + ~CachedMessage() {} + +protected: + const chip::app::Clusters::Messages::MessagePriorityEnum mPriority; + const chip::BitMask mMessageControl; + const chip::app::DataModel::Nullable mStartTime; + const chip::app::DataModel::Nullable mDuration; + + std::string mMessageText; + uint8_t mMessageIdBuffer[chip::app::Clusters::Messages::kMessageIdLength]; + + std::vector mResponseOptions; + std::list mOptions; +}; class MessagesManager : public chip::app::Clusters::Messages::Delegate { public: // Commands - void HandlePresentMessagesRequest( + CHIP_ERROR HandlePresentMessagesRequest( const chip::ByteSpan & messageId, const chip::app::Clusters::Messages::MessagePriorityEnum & priority, const chip::BitMask & messageControl, const chip::app::DataModel::Nullable & startTime, const chip::app::DataModel::Nullable & duration, @@ -34,7 +131,7 @@ class MessagesManager : public chip::app::Clusters::Messages::Delegate const chip::Optional< chip::app::DataModel::DecodableList> & responses) override; - void HandleCancelMessagesRequest(const chip::app::DataModel::DecodableList & messageIds) override; + CHIP_ERROR HandleCancelMessagesRequest(const chip::app::DataModel::DecodableList & messageIds) override; // Attributes CHIP_ERROR HandleGetMessages(chip::app::AttributeValueEncoder & aEncoder) override; @@ -44,5 +141,5 @@ class MessagesManager : public chip::app::Clusters::Messages::Delegate uint32_t GetFeatureMap(chip::EndpointId endpoint) override; protected: - std::list mMessages; + std::list mCachedMessages; }; diff --git a/integrations/cloudbuild/build-all.yaml b/integrations/cloudbuild/build-all.yaml index 6590630957d902..cdefbcf1ddbe15 100644 --- a/integrations/cloudbuild/build-all.yaml +++ b/integrations/cloudbuild/build-all.yaml @@ -6,7 +6,7 @@ steps: - "--init" - "--recursive" id: Submodules - - name: "ghcr.io/project-chip/chip-build-vscode:35" + - name: "ghcr.io/project-chip/chip-build-vscode:36" env: - PW_ENVIRONMENT_ROOT=/pwenv args: @@ -21,7 +21,7 @@ steps: path: /pwenv timeout: 900s - - name: "ghcr.io/project-chip/chip-build-vscode:35" + - name: "ghcr.io/project-chip/chip-build-vscode:36" env: - PW_ENVIRONMENT_ROOT=/pwenv args: @@ -85,7 +85,7 @@ steps: --target k32w-shell build --create-archives /workspace/artifacts/ - - name: "ghcr.io/project-chip/chip-build-vscode:35" + - name: "ghcr.io/project-chip/chip-build-vscode:36" env: - PW_ENVIRONMENT_ROOT=/pwenv args: diff --git a/integrations/cloudbuild/chef.yaml b/integrations/cloudbuild/chef.yaml index 432308a8bd695f..8dcf827d7e56aa 100644 --- a/integrations/cloudbuild/chef.yaml +++ b/integrations/cloudbuild/chef.yaml @@ -18,7 +18,7 @@ steps: args: - >- perl -i -pe 's/^gdbgui==/# gdbgui==/' /opt/espressif/esp-idf/requirements.txt && - ./examples/chef/chef.py --build_all --build_exclude noip\|basicvideo\|roboticvacuumcleaner + ./examples/chef/chef.py --build_all --build_exclude noip\|roboticvacuumcleaner id: CompileAll waitFor: - Bootstrap diff --git a/integrations/cloudbuild/smoke-test.yaml b/integrations/cloudbuild/smoke-test.yaml index f05bbd0e369d2d..87e22dbbea99d0 100644 --- a/integrations/cloudbuild/smoke-test.yaml +++ b/integrations/cloudbuild/smoke-test.yaml @@ -1,5 +1,5 @@ steps: - - name: "ghcr.io/project-chip/chip-build-vscode:35" + - name: "ghcr.io/project-chip/chip-build-vscode:36" entrypoint: "bash" args: - "-c" @@ -7,7 +7,7 @@ steps: git config --global --add safe.directory "*" git submodule update --init --recursive id: Submodules - - name: "ghcr.io/project-chip/chip-build-vscode:35" + - name: "ghcr.io/project-chip/chip-build-vscode:36" env: - PW_ENVIRONMENT_ROOT=/pwenv args: @@ -22,7 +22,7 @@ steps: path: /pwenv timeout: 900s - - name: "ghcr.io/project-chip/chip-build-vscode:35" + - name: "ghcr.io/project-chip/chip-build-vscode:36" id: ESP32 env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -43,7 +43,7 @@ steps: volumes: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:35" + - name: "ghcr.io/project-chip/chip-build-vscode:36" id: NRFConnect env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -64,7 +64,7 @@ steps: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:35" + - name: "ghcr.io/project-chip/chip-build-vscode:36" id: EFR32 env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -86,7 +86,7 @@ steps: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:35" + - name: "ghcr.io/project-chip/chip-build-vscode:36" id: Linux env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -139,7 +139,7 @@ steps: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:35" + - name: "ghcr.io/project-chip/chip-build-vscode:36" id: Android env: - PW_ENVIRONMENT_ROOT=/pwenv diff --git a/integrations/docker/images/base/chip-build/version b/integrations/docker/images/base/chip-build/version index 4a62ddb7795a85..3f8f2543a19424 100644 --- a/integrations/docker/images/base/chip-build/version +++ b/integrations/docker/images/base/chip-build/version @@ -1 +1 @@ -35 : [Telink] Update Docker image (Zephyr update) +36 : [Silabs] Update GeckoSDK and WIFI SDK diff --git a/integrations/docker/images/chip-cert-bins/Dockerfile b/integrations/docker/images/chip-cert-bins/Dockerfile index 553b3d65718e16..dff19ccd0137ef 100644 --- a/integrations/docker/images/chip-cert-bins/Dockerfile +++ b/integrations/docker/images/chip-cert-bins/Dockerfile @@ -180,6 +180,7 @@ RUN case ${TARGETPLATFORM} in \ --target linux-x64-shell-ipv6only-platform-mdns \ --target linux-x64-chip-cert-ipv6only-platform-mdns \ --target linux-x64-all-clusters-ipv6only \ + --target linux-x64-all-clusters-ipv6only-nlfaultinject \ --target linux-x64-all-clusters-minimal-ipv6only \ --target linux-x64-bridge-ipv6only \ --target linux-x64-tv-app-ipv6only \ @@ -193,11 +194,13 @@ RUN case ${TARGETPLATFORM} in \ --target linux-x64-lit-icd-ipv6only \ --target linux-x64-energy-management-ipv6only \ --target linux-x64-microwave-oven-ipv6only \ + --target linux-x64-rvc-ipv6only \ build \ && mv out/linux-x64-chip-tool-ipv6only-platform-mdns/chip-tool out/chip-tool \ && mv out/linux-x64-shell-ipv6only-platform-mdns/chip-shell out/chip-shell \ && mv out/linux-x64-chip-cert-ipv6only-platform-mdns/chip-cert out/chip-cert \ && mv out/linux-x64-all-clusters-ipv6only/chip-all-clusters-app out/chip-all-clusters-app \ + && mv out/linux-x64-all-clusters-ipv6only-nlfaultinject/chip-all-clusters-app out/chip-all-clusters-app-nlfaultinject \ && mv out/linux-x64-all-clusters-minimal-ipv6only/chip-all-clusters-minimal-app out/chip-all-clusters-minimal-app \ && mv out/linux-x64-bridge-ipv6only/chip-bridge-app out/chip-bridge-app \ && mv out/linux-x64-tv-app-ipv6only/chip-tv-app out/chip-tv-app \ @@ -211,6 +214,7 @@ RUN case ${TARGETPLATFORM} in \ && mv out/linux-x64-lit-icd-ipv6only/lit-icd-app out/lit-icd-app \ && mv out/linux-x64-energy-management-ipv6only/chip-energy-management-app out/chip-energy-management-app \ && mv out/linux-x64-microwave-oven-ipv6only/chip-microwave-oven-app out/chip-microwave-oven-app \ + && mv out/linux-x64-rvc-ipv6only/chip-rvc-app out/chip-rvc-app \ ;; \ "linux/arm64")\ set -x \ @@ -220,6 +224,7 @@ RUN case ${TARGETPLATFORM} in \ --target linux-arm64-shell-ipv6only-platform-mdns \ --target linux-arm64-chip-cert-ipv6only-platform-mdns \ --target linux-arm64-all-clusters-ipv6only \ + --target linux-arm64-all-clusters-ipv6only-nlfaultinject \ --target linux-arm64-all-clusters-minimal-ipv6only \ --target linux-arm64-bridge-ipv6only \ --target linux-arm64-tv-app-ipv6only \ @@ -238,6 +243,7 @@ RUN case ${TARGETPLATFORM} in \ && mv out/linux-arm64-shell-ipv6only-platform-mdns/chip-shell out/chip-shell \ && mv out/linux-arm64-chip-cert-ipv6only-platform-mdns/chip-cert out/chip-cert \ && mv out/linux-arm64-all-clusters-ipv6only/chip-all-clusters-app out/chip-all-clusters-app \ + && mv out/linux-arm64-all-clusters-ipv6only-nlfaultinject/chip-all-clusters-app out/chip-all-clusters-app-nlfaultinject \ && mv out/linux-arm64-all-clusters-minimal-ipv6only/chip-all-clusters-minimal-app out/chip-all-clusters-minimal-app \ && mv out/linux-arm64-bridge-ipv6only/chip-bridge-app out/chip-bridge-app \ && mv out/linux-arm64-tv-app-ipv6only/chip-tv-app out/chip-tv-app \ @@ -251,6 +257,7 @@ RUN case ${TARGETPLATFORM} in \ && mv out/linux-arm64-lit-icd-ipv6only/lit-icd-app out/lit-icd-app \ && mv out/linux-arm64-energy-management-ipv6only/chip-energy-management-app out/chip-energy-management-app \ && mv out/linux-arm64-microwave-oven-ipv6only/chip-microwave-oven-app out/chip-microwave-oven-app \ + && mv out/linux-arm64-rvc-ipv6only/chip-rvc-app out/chip-rvc-app \ ;; \ *) ;; \ esac @@ -269,6 +276,7 @@ COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-tool chip-tool COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-shell chip-shell COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-cert chip-cert COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-all-clusters-app chip-all-clusters-app +COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-all-clusters-app-nlfaultinject chip-all-clusters-app-nlfaultinject COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-all-clusters-minimal-app chip-all-clusters-minimal-app COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-lighting-app chip-lighting-app COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-tv-casting-app chip-tv-casting-app @@ -282,6 +290,7 @@ COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-app1 chip-app1 COPY --from=chip-build-cert-bins /root/connectedhomeip/out/lit-icd-app lit-icd-app COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-energy-management-app chip-energy-management-app COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-microwave-oven-app chip-microwave-oven-app +COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-rvc-app chip-rvc-app # Stage 3.1: Setup the Matter Python environment COPY --from=chip-build-cert-bins /root/connectedhomeip/out/python_lib python_lib diff --git a/integrations/docker/images/stage-2/chip-build-efr32/Dockerfile b/integrations/docker/images/stage-2/chip-build-efr32/Dockerfile index 9f3a218dbdb2bb..8dd4ca6b1444fd 100644 --- a/integrations/docker/images/stage-2/chip-build-efr32/Dockerfile +++ b/integrations/docker/images/stage-2/chip-build-efr32/Dockerfile @@ -13,8 +13,8 @@ RUN set -x \ && : # last line -# Clone Gecko SDK 4.4.0 (124fa19) -RUN wget https://github.com/SiliconLabs/gecko_sdk/releases/download/v4.4.0/gecko-sdk.zip -O /tmp/gecko_sdk.zip \ +# Clone Gecko SDK 4.4.1 (911f6cd) +RUN wget https://github.com/SiliconLabs/gecko_sdk/releases/download/v4.4.1/gecko-sdk.zip -O /tmp/gecko_sdk.zip \ && unzip /tmp/gecko_sdk.zip -d /tmp/gecko_sdk \ && rm -rf /tmp/gecko_sdk.zip \ # Deleting files that are not needed to save space @@ -30,8 +30,8 @@ RUN git clone --depth=1 --single-branch --branch=2.8.2 https://github.com/Silico rm -rf .git \ && : # last line -# Clone WiSeConnect SDK 3.1.1 (b2c1cd0) -RUN git clone --depth=1 --single-branch --branch=v3.1.1 https://github.com/SiliconLabs/wiseconnect.git /tmp/wifi_sdk && \ +# Clone WiSeConnect SDK 3.1.3 (00dd57a) +RUN git clone --depth=1 --single-branch --branch=v3.1.3 https://github.com/SiliconLabs/wiseconnect.git /tmp/wifi_sdk && \ cd /tmp/wifi_sdk && \ rm -rf .git \ && : # last line diff --git a/kotlin-detect-config.yaml b/kotlin-detect-config.yaml index 4dee3c56abb918..2ad54a05d6c483 100644 --- a/kotlin-detect-config.yaml +++ b/kotlin-detect-config.yaml @@ -36,8 +36,8 @@ style: - "**/src/controller/java/src/matter/tlv/types.kt" - "**/src/controller/java/src/matter/tlv/utils.kt" - "**/src/controller/java/src/matter/tlv/values.kt" - - "**/src/controller/java/src/chip/WildcardImport - examples/android/CHIPTest/app/src/androidTest/java/com/tcl/chip/chiptest/ExampleInstrumentedTest.kt" + - "**/src/controller/java/src/matter/tlv/values.kt" + - "**/src/controller/java/src/matter/controller/model/Status.kt" - "**/src/controller/java/tests/chip/devicecontroller/cluster/ChipClusterEventStructTest.kt" - "**/src/controller/java/tests/chip/devicecontroller/cluster/ChipClusterStructTest.kt" - "**/src/controller/java/tests/matter/jsontlv/JsonToTlvToJsonTest.kt" @@ -155,6 +155,7 @@ style: - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterInteractionFragment.kt" - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/EnterNetworkFragment.kt" - "**/examples/java-matter-controller/java/src/com/matter/controller/commands/common/MatterCommand.kt" + - "**/src/controller/java/src/matter/controller/ReportCallbackJni.kt" - "**/src/controller/java/src/matter/onboardingpayload/Base38.kt" - "**/src/controller/java/generated/java/**/*" ForbiddenComment: @@ -184,6 +185,9 @@ style: excludes: - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt" - "**/src/controller/java/generated/java/**/*" + - "**/src/controller/java/src/matter/controller/Messages.kt" + - "**/src/controller/java/src/matter/controller/model/Paths.kt" + - "**/src/controller/java/src/matter/controller/ReportCallbackJni.kt" - "**/src/controller/java/src/matter/onboardingpayload/OnboardingPayload.kt" UseCheckOrError: excludes: @@ -205,6 +209,7 @@ style: FunctionOnlyReturningConstant: excludes: - "**/src/controller/java/generated/java/**/*" + - "**/src/controller/java/src/matter/controller/Messages.kt" - "**/src/controller/java/src/matter/onboardingpayload/QRCodeOnboardingPayloadGenerator.kt" exceptions: @@ -301,6 +306,8 @@ complexity: - "**/src/controller/java/src/matter/controller/MatterControllerImpl.kt" - "**/src/controller/java/src/matter/controller/CompletionListenerAdapter.kt" - "**/src/controller/java/src/matter/controller/MatterController.kt" + - "**/src/controller/java/src/matter/controller/ReportCallbackJni.kt" + - "**/src/controller/java/src/matter/controller/model/States.kt" - "**/src/controller/java/tests/matter/jsontlv/JsonToTlvToJsonTest.kt" - "**/src/controller/java/tests/matter/onboardingpayload/ManualCodeTest.kt" - "**/src/controller/java/tests/matter/onboardingpayload/QRCodeTest.kt" @@ -314,12 +321,17 @@ complexity: - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterDetailFragment.kt" - "**/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Command.kt" - "**/src/controller/java/generated/java/**/*" + - "**/src/controller/java/src/matter/controller/MatterControllerImpl.kt" + - "**/src/controller/java/src/matter/controller/InvokeCallbackJni.kt" + - "**/src/controller/java/src/matter/controller/ReportCallbackJni.kt" + - "**/src/controller/java/src/matter/controller/model/States.kt" - "**/src/controller/java/src/matter/onboardingpayload/OnboardingPayload.kt" LongMethod: excludes: - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/AddressCommissioningFragment.kt" - "**/examples/java-matter-controller/java/src/com/matter/controller/commands/common/CommandManager.kt" - "**/src/controller/java/generated/java/**/*" + - "**/src/controller/java/src/matter/controller/MatterControllerImpl.kt" - "**/src/controller/java/src/matter/onboardingpayload/Base38.kt" - "**/src/controller/java/src/matter/onboardingpayload/ManualOnboardingPayloadGenerator.kt" - "**/src/controller/java/src/matter/onboardingpayload/ManualOnboardingPayloadParser.kt" diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index 771c92b99cabef..af1bd454b86ddb 100755 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -152,6 +152,7 @@ def BuildHostTarget(): target.AppendModifier('nodeps', enable_ble=False, enable_wifi=False, enable_thread=False, crypto_library=HostCryptoLibrary.MBEDTLS, use_clang=True).ExceptIfRe('-(clang|noble|boringssl|mbedtls)') + target.AppendModifier('nlfaultinject', use_nl_fault_injection=True) target.AppendModifier('platform-mdns', use_platform_mdns=True) target.AppendModifier('minmdns-verbose', minmdns_high_verbosity=True) target.AppendModifier('libnl', minmdns_address_policy="libnl") diff --git a/scripts/build/builders/host.py b/scripts/build/builders/host.py index 7b7a02d421f097..fcb609c70e941f 100644 --- a/scripts/build/builders/host.py +++ b/scripts/build/builders/host.py @@ -234,8 +234,8 @@ def OutputNames(self): yield 'refrigerator-app' yield 'refrigerator-app.map' elif self == HostApp.RVC: - yield 'rvc-app' - yield 'rvc-app.map' + yield 'chip-rvc-app' + yield 'chip-rvc-app.map' elif self == HostApp.AIR_PURIFIER: yield 'air-purifier-app' yield 'air-purifier-app.map' @@ -295,7 +295,7 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, enable_ipv4=True, enable_ble=True, enable_wifi=True, enable_thread=True, use_tsan=False, use_asan=False, use_ubsan=False, separate_event_loop=True, fuzzing_type: HostFuzzingType = HostFuzzingType.NONE, use_clang=False, - interactive_mode=True, extra_tests=False, use_platform_mdns=False, enable_rpcs=False, + interactive_mode=True, extra_tests=False, use_nl_fault_injection=False, use_platform_mdns=False, enable_rpcs=False, use_coverage=False, use_dmalloc=False, minmdns_address_policy=None, minmdns_high_verbosity=False, imgui_ui=False, crypto_library: HostCryptoLibrary = None, enable_test_event_triggers=None): @@ -368,6 +368,9 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, # so setting clang is not correct raise Exception('Fake host board is always gcc (not clang)') + if use_nl_fault_injection: + self.extra_gn_options.append('chip_with_nlfaultinjection=true') + if minmdns_address_policy: if use_platform_mdns: raise Exception('Address policy applies to minmdns only') diff --git a/scripts/build/gn_gen_cirque.sh b/scripts/build/gn_gen_cirque.sh index a0713f571189ab..d6f6bd86905a0e 100755 --- a/scripts/build/gn_gen_cirque.sh +++ b/scripts/build/gn_gen_cirque.sh @@ -36,7 +36,7 @@ echo "Setup build environment" source "./scripts/activate.sh" echo "Build: GN configure" -gn --root="$CHIP_ROOT" gen --check --fail-on-unused-args out/debug --args='target_os="all"'"chip_build_tests=false chip_enable_wifi=false chip_im_force_fabric_quota_check=true enable_default_builds=false enable_host_gcc_build=true enable_standalone_chip_tool_build=true enable_linux_all_clusters_app_build=true enable_linux_lighting_app_build=true enable_microwave_oven_app_build=true enable_linux_lit_icd_app_build=true" +gn --root="$CHIP_ROOT" gen --check --fail-on-unused-args out/debug --args='target_os="all"'"chip_build_tests=false chip_enable_wifi=false chip_im_force_fabric_quota_check=true enable_default_builds=false enable_host_gcc_build=true enable_standalone_chip_tool_build=true enable_linux_all_clusters_app_build=true enable_linux_lighting_app_build=true enable_linux_lit_icd_app_build=true" echo "Build: Ninja build" time ninja -C out/debug all check diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt index 6a0b73362b8f5c..3c6a2d3b643d6b 100644 --- a/scripts/build/testdata/all_targets_linux_x64.txt +++ b/scripts/build/testdata/all_targets_linux_x64.txt @@ -10,7 +10,7 @@ efr32-{brd4161a,brd4187c,brd4186c,brd4163a,brd4164a,brd4166a,brd4170a,brd4186a,b esp32-{m5stack,c3devkit,devkitc,qemu}-{all-clusters,all-clusters-minimal,energy-management,ota-provider,ota-requestor,shell,light,lock,bridge,temperature-measurement,ota-requestor,tests}[-rpc][-ipv6only][-tracing] genio-lighting-app linux-fake-tests[-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-coverage][-dmalloc][-clang] -linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,kotlin-matter-controller,minmdns,light,lock,shell,ota-provider,ota-requestor,simulated-app1,simulated-app2,python-bindings,tv-app,tv-casting-app,bridge,tests,chip-cert,address-resolve-tool,contact-sensor,dishwasher,microwave-oven,refrigerator,rvc,air-purifier,lit-icd,air-quality-sensor,network-manager,energy-management}[-nodeps][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui][-evse-test-event] +linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,kotlin-matter-controller,minmdns,light,lock,shell,ota-provider,ota-requestor,simulated-app1,simulated-app2,python-bindings,tv-app,tv-casting-app,bridge,tests,chip-cert,address-resolve-tool,contact-sensor,dishwasher,microwave-oven,refrigerator,rvc,air-purifier,lit-icd,air-quality-sensor,network-manager,energy-management}[-nodeps][-nlfaultinject][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui][-evse-test-event] linux-x64-efr32-test-runner[-clang] imx-{chip-tool,lighting-app,thermostat,all-clusters-app,all-clusters-minimal-app,ota-provider-app}[-release] infineon-psoc6-{lock,light,all-clusters,all-clusters-minimal}[-ota][-updateimage] diff --git a/scripts/helpers/iwyu-check.py b/scripts/helpers/iwyu-check.py index f4419ccd99ff10..822b85c184766d 100755 --- a/scripts/helpers/iwyu-check.py +++ b/scripts/helpers/iwyu-check.py @@ -172,8 +172,8 @@ def main(compile_commands_glob, scanning_destination, mapping_file_dir, logging.info("============== IWYU output start ================") logger = logging.info - while status.poll() is None: - line = status.stdout.readline().rstrip() + for line in status.stdout: + line = line.rstrip() if re.match(r"^warning:.*$", line): logger = logging.warning diff --git a/scripts/helpers/platforms/iwyu.imp b/scripts/helpers/platforms/iwyu.imp index c3d2210b2886dd..06637de3ad3ddb 100644 --- a/scripts/helpers/platforms/iwyu.imp +++ b/scripts/helpers/platforms/iwyu.imp @@ -32,7 +32,12 @@ ## lib/* { include: [ '"lib/core/CHIPError.h"', private, '', public ] }, { include: [ '"lib/dnssd/ServiceNaming.h"', private, '', public ] }, + + ## lib/support/logging/* + { include: [ '"lib/support/logging/BinaryLogging.h"', private, '', public ] }, { include: [ '"lib/support/logging/CHIPLogging.h"', private, '', public ] }, + { include: [ '"lib/support/logging/Constants.h"', private, '', public ] }, + { include: [ '"lib/support/logging/TextOnlyLogging.h"', private, '', public ] }, ## platform/* { include: [ '"platform/NetworkCommissioning.h"', private, '', public ] }, diff --git a/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja b/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja index ba0abf5976f49c..6c8ad742068684 100644 --- a/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja +++ b/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja @@ -102,6 +102,7 @@ import chip.devicecontroller.model.ClusterState; import chip.devicecontroller.model.EndpointState; import chip.devicecontroller.model.InvokeElement; import chip.devicecontroller.model.NodeState; +import chip.devicecontroller.model.Status; import javax.annotation.Nullable; import java.util.ArrayList; @@ -318,8 +319,15 @@ public class ChipClusters { } @Override - public void onResponse(ChipAttributePath attributePath) { - callback.onSuccess(); + public void onResponse(ChipAttributePath attributePath, Status status) { + if (status.getStatus() == Status.Code.Success) + { + callback.onSuccess(); + } + else + { + callback.onError(new StatusException(status.getStatus())); + } } @Override diff --git a/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java b/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java index 9b6287a9a954ae..37c5c031b5c5ae 100644 --- a/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java +++ b/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java @@ -25,6 +25,7 @@ import chip.devicecontroller.model.EndpointState; import chip.devicecontroller.model.InvokeElement; import chip.devicecontroller.model.NodeState; +import chip.devicecontroller.model.Status; import javax.annotation.Nullable; import java.util.ArrayList; @@ -241,8 +242,15 @@ static class WriteAttributesCallbackImpl implements WriteAttributesCallback { } @Override - public void onResponse(ChipAttributePath attributePath) { - callback.onSuccess(); + public void onResponse(ChipAttributePath attributePath, Status status) { + if (status.getStatus() == Status.Code.Success) + { + callback.onSuccess(); + } + else + { + callback.onError(new StatusException(status.getStatus())); + } } @Override diff --git a/scripts/py_matter_yamltests/BUILD.gn b/scripts/py_matter_yamltests/BUILD.gn index b886fb04132c37..f8fa027672b868 100644 --- a/scripts/py_matter_yamltests/BUILD.gn +++ b/scripts/py_matter_yamltests/BUILD.gn @@ -55,6 +55,7 @@ pw_python_package("matter_yamltests") { "test_pics_checker.py", "test_parser_builder.py", "test_pseudo_clusters.py", + "test_yaml_parser.py", "test_yaml_loader.py", ] diff --git a/scripts/py_matter_yamltests/matter_yamltests/errors.py b/scripts/py_matter_yamltests/matter_yamltests/errors.py index daa886573569c1..1f26ea4f8354bc 100644 --- a/scripts/py_matter_yamltests/matter_yamltests/errors.py +++ b/scripts/py_matter_yamltests/matter_yamltests/errors.py @@ -222,3 +222,45 @@ def __init__(self, content): self.tag_key_with_error(content, 'attribute') response = content.get('response') self.tag_key_with_error(response, 'saveAs') + + +class TestStepEnumError(TestStepError): + """ + Raise when an enum value or an enum name is not found in the definitions. + + Parameters: + - enum_name_or_value (str|int): The name (str) or value (int) of the enumeration in the step. + If a string is provided, it is considered the name of the enumeration; if an integer is provided, it is considered the value of the enumeration. + - enum_candidates (dict): A dictionary mapping enumeration names (as strings) to their corresponding values + (as integers). This dictionary represents all known values of the enumeration. + """ + + def __init__(self, enum_name_or_value, enum_candidates: dict): + if type(enum_name_or_value) is str: + message = f'Unknown enum name: "{enum_name_or_value}". The possible values are: "{enum_candidates}"' + + for enum_name in enum_candidates: + if enum_name.lower() == enum_name_or_value.lower(): + message = f'Unknown enum name: "{enum_name_or_value}". Did you mean "{enum_name}" ?' + break + + else: + message = f'Unknown enum value: "{enum_name_or_value}". The possible values are: "{enum_candidates}"' + + super().__init__(message) + + +class TestStepEnumSpecifierNotUnknownError(TestStepError): + """Raise when an enum value declared as unknown is in fact a known enum value from the definitions.""" + + def __init__(self, specified_value, enum_name): + message = f'The value "{specified_value}" is not unknown. It is the value of "{enum_name}"' + super().__init__(message) + + +class TestStepEnumSpecifierWrongError(TestStepError): + """Raise when an enum value is specified for a given enum name but it does not match the enum value from the definitions.""" + + def __init__(self, specified_value, enum_name, enum_value): + message = f'The value "{specified_value}" is not the value of "{enum_name}({enum_value})"' + super().__init__(message) diff --git a/scripts/py_matter_yamltests/matter_yamltests/parser.py b/scripts/py_matter_yamltests/matter_yamltests/parser.py index 16f98bcf96d800..cb0a89c6418756 100644 --- a/scripts/py_matter_yamltests/matter_yamltests/parser.py +++ b/scripts/py_matter_yamltests/matter_yamltests/parser.py @@ -15,6 +15,7 @@ import copy import logging +import re from dataclasses import dataclass, field from enum import Enum, auto from typing import Optional @@ -22,7 +23,8 @@ from . import fixes from .constraints import get_constraints, is_typed_constraint from .definitions import SpecDefinitions -from .errors import TestStepError, TestStepKeyError, TestStepValueNameError +from .errors import (TestStepEnumError, TestStepEnumSpecifierNotUnknownError, TestStepEnumSpecifierWrongError, TestStepError, + TestStepKeyError, TestStepValueNameError) from .pics_checker import PICSChecker from .yaml_loader import YamlLoader @@ -38,6 +40,9 @@ 'SubscribeAll', ] +# If True, enum values should use a valid name instead of a raw value +STRICT_ENUM_VALUE_CHECK = False + class UnknownPathQualifierError(TestStepError): """Raise when an attribute/command/event name is not found in the definitions.""" @@ -169,6 +174,99 @@ def _value_or_config(data, key, config): return data[key] if key in data else config.get(key) +class EnumType: + def __init__(self, enum: Enum): + self.type = enum.name + self.base_type = enum.base_type + + self._codes = {} + self.entries_by_name = {} + self.entries_by_code = {} + self._compute_entries(enum) + + def translate(self, key: str, value) -> int: + if self._codes.get(key) is not None and self._codes.get(key) == value: + return self._codes.get(key) + + if type(value) is str: + code = self._get_code_by_name(value) + else: + code = self._get_code_by_value(value) + + if code is None: + raise TestStepEnumError(value, self.entries_by_name) + + self._codes[key] = code + return code + + def _get_code_by_name(self, value): + # For readability the name could sometimes be written as "enum_name(enum_code)" instead of "enum_name" + # In this case the enum_code should be checked to ensure that it is correct, unless enum_name is UnknownEnumValue + # in which case only invalid enum_code are allowed. + specified_name, specified_code = self._extract_name_and_code(value) + if specified_name not in self.entries_by_name: + return None + + enum_code = self.entries_by_name.get(specified_name) + if specified_code is None or specified_code == enum_code: + return enum_code + + if specified_name != f'{self.type}.UnknownEnumValue': + raise TestStepEnumSpecifierWrongError( + specified_code, specified_name, enum_code) + + enum_name = self.entries_by_code.get(specified_code) + if enum_name: + raise TestStepEnumSpecifierNotUnknownError(value, enum_name) + + return specified_code + + def _get_code_by_value(self, value): + enum_name = self.entries_by_code.get(value) + if not enum_name: + return None + + if STRICT_ENUM_VALUE_CHECK: + raise TestStepEnumError(value, self.entries_by_name) + + return value + + def _compute_entries(self, enum: Enum): + enum_codes = [] + for enum_entry in enum.entries: + name = f'{self.type}.{enum_entry.name}' + code = enum_entry.code + + self.entries_by_name[name] = code + self.entries_by_code[code] = name + enum_codes.append(code) + + # search for the first invalid entry if any + max_code = 0xFF + 1 + if self.base_type == 'enum16': + max_code = 0xFFFF + 1 + + for code in range(0, max_code): + if code not in enum_codes: + name = f'{self.type}.UnknownEnumValue' + self.entries_by_name[name] = code + self.entries_by_code[code] = name + break + + def _extract_name_and_code(self, enum_name: str): + match = re.match(r"([\w.]+)(?:\((\w+)\))?", enum_name) + if match: + name = match.group(1) + code = int(match.group(2)) if match.group(2) else None + return name, code + + return None, None + + @staticmethod + def is_valid_type(target_type: str): + return target_type == 'enum8' or target_type == 'enum16' + + class _TestStepWithPlaceholders: '''A single YAML test parsed, as is, from YAML. @@ -441,7 +539,11 @@ def _as_mapping(self, definitions, cluster_name, target_name): element = definitions.get_type_by_name(cluster_name, target_name) if hasattr(element, 'base_type'): - target_name = element.base_type.lower() + if EnumType.is_valid_type(element.base_type): + target_name = EnumType(element) + else: + target_name = element.base_type + elif hasattr(element, 'fields'): target_name = {f.name: self._as_mapping( definitions, cluster_name, f.data_type.name) for f in element.fields} @@ -480,7 +582,11 @@ def _update_with_definition(self, container: dict, mapping_type): if key == 'value': value[key] = self._update_value_with_definition( - item_value, mapping) + value, + key, + item_value, + mapping + ) elif key == 'saveAs' and type(item_value) is str and item_value not in self._parsing_config_variable_storage: self._parsing_config_variable_storage[item_value] = None elif key == 'saveDataVersionAs' and type(item_value) is str and item_value not in self._parsing_config_variable_storage: @@ -491,37 +597,80 @@ def _update_with_definition(self, container: dict, mapping_type): # the the value type for the target field. if is_typed_constraint(constraint): value[key][constraint] = self._update_value_with_definition( - constraint_value, mapping) + item_value, + constraint, + constraint_value, + mapping + ) else: # This key, value pair does not rely on cluster specifications. pass - def _update_value_with_definition(self, value, mapping_type): + def _update_value_with_definition(self, container: dict, key: str, value, mapping_type): + """ + Processes a given value based on a specified mapping type and returns the updated value. + This method does not modify the container in place; rather, it returns a new value that should be + used to update or process further as necessary. + + The 'container' and 'key' parameters are primarily used for error tagging. If an error occurs + during the value processing, these parameters allow for the error to be precisely located and + reported, facilitating easier debugging and error tracking. + + Parameters: + - container (dict): A dictionary that serves as a context for the operation. It is used for error + tagging if processing fails, by associating errors with specific locations within the data structure. + - key (str): The key related to the value being processed. It is used alongside 'container' to tag + errors, enabling precise identification of the error source. + - value: The value to be processed according to the mapping type. + - mapping_type: Dictates the processing or mapping logic to be applied to 'value'. + + Returns: + The processed value, which is the result of applying the specified mapping type to the original 'value'. + This method does not update the 'container'; any necessary updates based on the processed value must + be handled outside this method. + + Raises: + - TestStepError: If an error occurs during the processing of the value. The error includes details + from the 'container' and 'key' to facilitate error tracing and debugging. + """ + if not mapping_type: return value if type(value) is dict: rv = {} - for key in value: + for item_key in value: # FabricIndex is a special case where the framework requires it to be passed even # if it is not part of the requested arguments per spec and not part of the XML # definition. - if key == 'FabricIndex' or key == 'fabricIndex': - rv[key] = value[key] # int64u + if item_key == 'FabricIndex' or item_key == 'fabricIndex': + rv[item_key] = value[item_key] # int64u else: - if not mapping_type.get(key): - raise TestStepKeyError(value, key) - mapping = mapping_type[key] - rv[key] = self._update_value_with_definition( - value[key], mapping) + if not mapping_type.get(item_key): + raise TestStepKeyError(value, item_key) + mapping = mapping_type[item_key] + rv[item_key] = self._update_value_with_definition( + value, + item_key, + value[item_key], + mapping + ) return rv + if type(value) is list: - return [self._update_value_with_definition(entry, mapping_type) for entry in value] + return [self._update_value_with_definition(container, key, entry, mapping_type) for entry in value] + # TODO currently unsure if the check of `value not in config` is sufficant. For # example let's say value = 'foo + 1' and map type is 'int64u', we would arguably do # the wrong thing below. if value is not None and value not in self._parsing_config_variable_storage: - if mapping_type == 'int64u' or mapping_type == 'int64s' or mapping_type == 'bitmap64' or mapping_type == 'epoch_us': + if type(mapping_type) is EnumType: + try: + value = mapping_type.translate(key, value) + except (TestStepEnumError, TestStepEnumSpecifierNotUnknownError, TestStepEnumSpecifierWrongError) as e: + e.tag_key_with_error(container, key) + raise e + elif mapping_type == 'int64u' or mapping_type == 'int64s' or mapping_type == 'bitmap64' or mapping_type == 'epoch_us': value = fixes.try_apply_float_to_integer_fix(value) value = fixes.try_apply_yaml_cpp_longlong_limitation_fix(value) value = fixes.try_apply_yaml_unrepresentable_integer_for_javascript_fixes( diff --git a/scripts/py_matter_yamltests/test_yaml_parser.py b/scripts/py_matter_yamltests/test_yaml_parser.py index 055f949773f9d3..27472572a96d6b 100644 --- a/scripts/py_matter_yamltests/test_yaml_parser.py +++ b/scripts/py_matter_yamltests/test_yaml_parser.py @@ -20,14 +20,22 @@ # is arguably better then no checks at all. import io -import tempfile import unittest +from unittest.mock import mock_open, patch from matter_yamltests.definitions import ParseSource, SpecDefinitions +from matter_yamltests.errors import TestStepEnumError, TestStepEnumSpecifierNotUnknownError, TestStepEnumSpecifierWrongError from matter_yamltests.parser import TestParser, TestParserConfig simple_test_description = ''' + + + + + + + @@ -36,8 +44,11 @@ Test 0x1234 - + test_enum + + + ''' @@ -52,43 +63,145 @@ tests: - label: "Send Test Command" command: "test" +''' + +enum_values_yaml = ''' +name: Test Enum Values + +config: + nodeId: 0x12344321 + cluster: "Test" + endpoint: 1 + +tests: + - label: "Read attribute test_enum Value" + command: "readAttribute" + attribute: "test_enum" + response: + value: 0 + + - label: "Read attribute test_enum Value" + command: "readAttribute" + attribute: "test_enum" + response: + value: TestEnum.A + + - label: "Read attribute test_enum Value" + command: "readAttribute" + attribute: "test_enum" + response: + value: TestEnum.A(0) + + - label: "Read attribute test_enum Value" + command: "readAttribute" + attribute: "test_enum" + response: + value: TestEnum.UnknownEnumValue + + - label: "Read attribute test_enum Value" + command: "readAttribute" + attribute: "test_enum" + response: + value: TestEnum.UnknownEnumValue(255) + + - label: "Write attribute test_enum Value" + command: "writeAttribute" + attribute: "test_enum" + arguments: + value: 0 + + - label: "Write attribute test_enum Value" + command: "writeAttribute" + attribute: "test_enum" + arguments: + value: TestEnum.A + + - label: "Write attribute test_enum Value" + command: "writeAttribute" + attribute: "test_enum" + arguments: + value: TestEnum.A(0) + + - label: "Write attribute test_enum Value" + command: "writeAttribute" + attribute: "test_enum" + arguments: + value: TestEnum.UnknownEnumValue + + - label: "Write attribute test_enum Value" + command: "writeAttribute" + attribute: "test_enum" + arguments: + value: TestEnum.UnknownEnumValue(255) +''' + +enum_value_read_response_wrong_code_yaml = ''' +tests: + - label: "Read attribute test_enum Value" + cluster: "Test" + command: "readAttribute" + attribute: "test_enum" + response: + value: 123 +''' + +enum_value_read_response_wrong_name_yaml = ''' +tests: + - label: "Read attribute test_enum Value" + cluster: "Test" + command: "readAttribute" + attribute: "test_enum" + response: + value: ThisIsWrong +''' - - label: "Send Test Not Handled Command" - command: "testNotHandled" +enum_value_read_response_wrong_code_specified_yaml = ''' +tests: + - label: "Read attribute test_enum Value" + cluster: "Test" + command: "readAttribute" + attribute: "test_enum" response: - error: INVALID_COMMAND + value: TestEnum.A(123) +''' - - label: "Send Test Specific Command" - command: "testSpecific" +enum_value_read_response_not_unknown_code_specified_yaml = ''' +tests: + - label: "Read attribute test_enum Value" + cluster: "Test" + command: "readAttribute" + attribute: "test_enum" response: - values: - - name: "returnValue" - value: 7 + value: TestEnum.UnknownEnumValue(0) ''' +def mock_open_with_parameter_content(content): + file_object = mock_open(read_data=content).return_value + file_object.__iter__.return_value = content.splitlines(True) + return file_object + + +@patch('builtins.open', new=mock_open_with_parameter_content) class TestYamlParser(unittest.TestCase): def setUp(self): self._definitions = SpecDefinitions( [ParseSource(source=io.StringIO(simple_test_description), name='simple_test_description')]) - self._temp_file = tempfile.NamedTemporaryFile(suffix='.yaml') - with open(self._temp_file.name, 'w') as f: - f.writelines(simple_test_yaml) def test_able_to_iterate_over_all_parsed_tests(self): # self._yaml_parser.tests implements `__next__`, which does value substitution. We are # simply ensure there is no exceptions raise. parser_config = TestParserConfig(None, self._definitions) - yaml_parser = TestParser(self._temp_file.name, parser_config) + yaml_parser = TestParser(simple_test_yaml, parser_config) count = 0 for idx, test_step in enumerate(yaml_parser.tests): count += 1 pass - self.assertEqual(count, 3) + self.assertEqual(count, 1) def test_config(self): parser_config = TestParserConfig(None, self._definitions) - yaml_parser = TestParser(self._temp_file.name, parser_config) + yaml_parser = TestParser(simple_test_yaml, parser_config) for idx, test_step in enumerate(yaml_parser.tests): self.assertEqual(test_step.node_id, 0x12344321) self.assertEqual(test_step.cluster, 'Test') @@ -99,7 +212,7 @@ def test_config_override(self): 'cluster': 'TestOverride', 'endpoint': 4} parser_config = TestParserConfig( None, self._definitions, config_override) - yaml_parser = TestParser(self._temp_file.name, parser_config) + yaml_parser = TestParser(simple_test_yaml, parser_config) for idx, test_step in enumerate(yaml_parser.tests): self.assertEqual(test_step.node_id, 12345) self.assertEqual(test_step.cluster, 'TestOverride') @@ -109,8 +222,37 @@ def test_config_override_unknown_field(self): config_override = {'unknown_field': 1} parser_config = TestParserConfig( None, self._definitions, config_override) - self.assertRaises(KeyError, TestParser, - self._temp_file.name, parser_config) + + yaml_parser = TestParser(simple_test_yaml, parser_config) + self.assertIsInstance(yaml_parser, TestParser) + + def test_config_valid_enum_values(self): + parser_config = TestParserConfig(None, self._definitions) + yaml_parser = TestParser(enum_values_yaml, parser_config) + self.assertIsInstance(yaml_parser, TestParser) + + for idx, test_step in enumerate(yaml_parser.tests): + pass + + def test_config_read_response_wrong_code(self): + parser_config = TestParserConfig(None, self._definitions) + self.assertRaises(TestStepEnumError, TestParser, + enum_value_read_response_wrong_code_yaml, parser_config) + + def test_config_read_response_wrong_name(self): + parser_config = TestParserConfig(None, self._definitions) + self.assertRaises(TestStepEnumError, TestParser, + enum_value_read_response_wrong_name_yaml, parser_config) + + def test_config_read_response_wrong_code_specified(self): + parser_config = TestParserConfig(None, self._definitions) + self.assertRaises(TestStepEnumSpecifierWrongError, TestParser, + enum_value_read_response_wrong_code_specified_yaml, parser_config) + + def test_config_read_response_not_unknown_code_specified(self): + parser_config = TestParserConfig(None, self._definitions) + self.assertRaises(TestStepEnumSpecifierNotUnknownError, TestParser, + enum_value_read_response_not_unknown_code_specified_yaml, parser_config) def main(): diff --git a/scripts/spec_xml/generate_spec_xml.py b/scripts/spec_xml/generate_spec_xml.py index f4f30d060096a0..016f92d4b5759a 100755 --- a/scripts/spec_xml/generate_spec_xml.py +++ b/scripts/spec_xml/generate_spec_xml.py @@ -79,7 +79,7 @@ def scrape_clusters(scraper, spec_root, output_dir, dry_run): def scrape_cluster(filename: str) -> None: xml_path = get_xml_path(filename, clusters_output_dir) - cmd = [scraper, 'cluster', '-i', filename, '-o', xml_path, '-nd'] + cmd = [scraper, 'cluster', '-i', filename, '-o', xml_path, '-nd', '--define', 'in-progress'] if dry_run: print(cmd) else: diff --git a/scripts/tests/chiptest/__init__.py b/scripts/tests/chiptest/__init__.py index fd4ad6f52867b5..ecfd98be618480 100644 --- a/scripts/tests/chiptest/__init__.py +++ b/scripts/tests/chiptest/__init__.py @@ -236,6 +236,7 @@ def _GetChipReplUnsupportedTests() -> Set[str]: "Test_TC_IDM_1_2.yaml", # chip-repl does not support AnyCommands (19/07/2023) "TestGroupKeyManagementCluster.yaml", # chip-repl does not support EqualityCommands (2023-08-04) "TestIcdManagementCluster.yaml", # TODO(#30430): add ICD registration support in chip-repl + "Test_TC_ICDM_3_4.yaml", # chip-repl does not support ICD registration "Test_TC_S_2_2.yaml", # chip-repl does not support EqualityCommands pseudo-cluster "Test_TC_MOD_3_1.yaml", # chip-repl does not support EqualityCommands pseudo-cluster "Test_TC_MOD_3_2.yaml", # chip-repl does not support EqualityCommands pseudo-cluster @@ -264,6 +265,10 @@ def _GetChipReplUnsupportedTests() -> Set[str]: "Test_TC_RVCCLEANM_3_3.yaml", # chip-repl does not support EqualityCommands pseudo-cluster "Test_TC_BINFO_2_1.yaml", # chip-repl does not support EqualityCommands pseudo-cluster "TestDiagnosticLogs.yaml", # chip-repl does not implement a BDXTransferServerDelegate + "Test_TC_EEVSEM_2_1.yaml", # chip-repl does not support EqualityCommands pseudo-cluster + "Test_TC_EEVSEM_3_1.yaml", # chip-repl does not support EqualityCommands pseudo-cluster + "Test_TC_EEVSEM_3_2.yaml", # chip-repl does not support EqualityCommands pseudo-cluster + "Test_TC_EEVSEM_3_3.yaml", # chip-repl does not support EqualityCommands pseudo-cluster "TestDiagnosticLogsDownloadCommand.yaml", # chip-repl does not implement the bdx download command } @@ -308,6 +313,8 @@ def target_for_name(name: str): return TestTarget.LIT_ICD if name.startswith("Test_TC_MWOCTRL_") or name.startswith("Test_TC_MWOM_"): return TestTarget.MWO + if name.startswith("Test_TC_RVCRUNM_") or name.startswith("Test_TC_RVCCLEANM_") or name.startswith("Test_TC_RVCOPSTATE_"): + return TestTarget.RVC return TestTarget.ALL_CLUSTERS diff --git a/scripts/tests/chiptest/linux.py b/scripts/tests/chiptest/linux.py index 1d679ee236a3fd..3dbd851be26b47 100644 --- a/scripts/tests/chiptest/linux.py +++ b/scripts/tests/chiptest/linux.py @@ -183,6 +183,7 @@ def PathsWithNetworkNamespaces(paths: ApplicationPaths) -> ApplicationPaths: tv_app='ip netns exec app'.split() + paths.tv_app, lit_icd_app='ip netns exec app'.split() + paths.lit_icd_app, microwave_oven_app='ip netns exec app'.split() + paths.microwave_oven_app, + rvc_app='ip netns exec app'.split() + paths.rvc_app, bridge_app='ip netns exec app'.split() + paths.bridge_app, chip_repl_yaml_tester_cmd='ip netns exec tool'.split() + paths.chip_repl_yaml_tester_cmd, chip_tool_with_python_cmd='ip netns exec tool'.split() + paths.chip_tool_with_python_cmd, diff --git a/scripts/tests/chiptest/test_definition.py b/scripts/tests/chiptest/test_definition.py index 95f7a631928ba4..12c59cfad0cc41 100644 --- a/scripts/tests/chiptest/test_definition.py +++ b/scripts/tests/chiptest/test_definition.py @@ -176,6 +176,7 @@ class TestTarget(Enum): BRIDGE = auto() LIT_ICD = auto() MWO = auto() + RVC = auto() @dataclass @@ -191,10 +192,11 @@ class ApplicationPaths: microwave_oven_app: typing.List[str] chip_repl_yaml_tester_cmd: typing.List[str] chip_tool_with_python_cmd: typing.List[str] + rvc_app: typing.List[str] def items(self): return [self.chip_tool, self.all_clusters_app, self.lock_app, self.ota_provider_app, self.ota_requestor_app, - self.tv_app, self.bridge_app, self.lit_icd_app, self.microwave_oven_app, self.chip_repl_yaml_tester_cmd, self.chip_tool_with_python_cmd] + self.tv_app, self.bridge_app, self.lit_icd_app, self.microwave_oven_app, self.chip_repl_yaml_tester_cmd, self.chip_tool_with_python_cmd, self.rvc_app] @dataclass @@ -305,6 +307,8 @@ def Run(self, runner, apps_register, paths: ApplicationPaths, pics_file: str, target_app = paths.lit_icd_app elif self.target == TestTarget.MWO: target_app = paths.microwave_oven_app + elif self.target == TestTarget.RVC: + target_app = paths.rvc_app else: raise Exception("Unknown test target - " "don't know which application to run") diff --git a/scripts/tests/run_test_suite.py b/scripts/tests/run_test_suite.py index 9dbe01d9dbcfa0..2df88cd6740653 100755 --- a/scripts/tests/run_test_suite.py +++ b/scripts/tests/run_test_suite.py @@ -257,6 +257,9 @@ def cmd_list(context): @click.option( '--microwave-oven-app', help='what microwave oven app to use') +@click.option( + '--rvc-app', + help='what rvc app to use') @click.option( '--chip-repl-yaml-tester', help='what python script to use for running yaml tests using chip-repl as controller') @@ -288,7 +291,7 @@ def cmd_list(context): help='Number of tests that are expected to fail in each iteration. Overall test will pass if the number of failures matches this. Nonzero values require --keep-going') @click.pass_context def cmd_run(context, iterations, all_clusters_app, lock_app, ota_provider_app, ota_requestor_app, - tv_app, bridge_app, lit_icd_app, microwave_oven_app, chip_repl_yaml_tester, chip_tool_with_python, pics_file, keep_going, test_timeout_seconds, expected_failures): + tv_app, bridge_app, lit_icd_app, microwave_oven_app, rvc_app, chip_repl_yaml_tester, chip_tool_with_python, pics_file, keep_going, test_timeout_seconds, expected_failures): if expected_failures != 0 and not keep_going: logging.exception(f"'--expected-failures {expected_failures}' used without '--keep-going'") sys.exit(2) @@ -321,6 +324,9 @@ def cmd_run(context, iterations, all_clusters_app, lock_app, ota_provider_app, o if microwave_oven_app is None: microwave_oven_app = paths_finder.get('chip-microwave-oven-app') + if rvc_app is None: + rvc_app = paths_finder.get('chip-rvc-app') + if chip_repl_yaml_tester is None: chip_repl_yaml_tester = paths_finder.get('yamltest_with_chip_repl_tester.py') @@ -341,6 +347,7 @@ def cmd_run(context, iterations, all_clusters_app, lock_app, ota_provider_app, o bridge_app=[bridge_app], lit_icd_app=[lit_icd_app], microwave_oven_app=[microwave_oven_app], + rvc_app=[rvc_app], chip_repl_yaml_tester_cmd=['python3'] + [chip_repl_yaml_tester], chip_tool_with_python_cmd=['python3'] + [chip_tool_with_python], ) diff --git a/scripts/tools/check_includes_config.py b/scripts/tools/check_includes_config.py index 42920c4014c133..6943c26ecb3081 100644 --- a/scripts/tools/check_includes_config.py +++ b/scripts/tools/check_includes_config.py @@ -160,6 +160,9 @@ 'src/tracing/json/json_tracing.cpp': {'string', 'sstream'}, 'src/tracing/json/json_tracing.h': {'fstream', 'unordered_map'}, + # Not intended for embedded clients + 'src/app/PendingResponseTrackerImpl.h': {'unordered_set'}, + # Not intended for embedded clients 'src/lib/support/jsontlv/JsonToTlv.cpp': {'sstream'}, 'src/lib/support/jsontlv/JsonToTlv.h': {'string'}, diff --git a/src/app/AttributePathExpandIterator.cpp b/src/app/AttributePathExpandIterator.cpp index 5c1bb50c179f47..784499a41c4d74 100644 --- a/src/app/AttributePathExpandIterator.cpp +++ b/src/app/AttributePathExpandIterator.cpp @@ -52,7 +52,7 @@ extern bool emberAfEndpointIndexIsEnabled(uint16_t index); namespace chip { namespace app { -AttributePathExpandIterator::AttributePathExpandIterator(ObjectList * aAttributePath) +AttributePathExpandIterator::AttributePathExpandIterator(SingleLinkedListNode * aAttributePath) { mpAttributePath = aAttributePath; diff --git a/src/app/AttributePathExpandIterator.h b/src/app/AttributePathExpandIterator.h index dbf8382014ce9c..f11e6793822f84 100644 --- a/src/app/AttributePathExpandIterator.h +++ b/src/app/AttributePathExpandIterator.h @@ -69,7 +69,7 @@ namespace app { class AttributePathExpandIterator { public: - AttributePathExpandIterator(ObjectList * aAttributePath); + AttributePathExpandIterator(SingleLinkedListNode * aAttributePath); /** * Proceed the iterator to the next attribute path in the given cluster info. @@ -105,7 +105,7 @@ class AttributePathExpandIterator inline bool Valid() const { return mpAttributePath != nullptr; } private: - ObjectList * mpAttributePath; + SingleLinkedListNode * mpAttributePath; ConcreteAttributePath mOutputPath; diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 84540e97892e6a..3dfbbbffe56daf 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -42,6 +42,13 @@ declare_args() { chip_im_force_fabric_quota_check = false enable_eventlist_attribute = false + + # Systems that can spare a bit of RAM for InteractionModelEngine/delegate + # pointers should do so (allows InteractionModelEngine decoupling and less usage + # of global pointers) + chip_im_static_global_interaction_model_engine = + current_os != "linux" && current_os != "mac" && current_os != "ios" && + current_os != "android" } buildconfig_header("app_buildconfig") { @@ -57,6 +64,7 @@ buildconfig_header("app_buildconfig") { "CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION=${chip_subscription_timeout_resumption}", "CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE=${enable_eventlist_attribute}", "CHIP_CONFIG_ENABLE_READ_CLIENT=${chip_enable_read_client}", + "CHIP_CONFIG_STATIC_GLOBAL_INTERACTION_MODEL_ENGINE=${chip_im_static_global_interaction_model_engine}", ] visibility = [ ":app_config" ] @@ -79,7 +87,11 @@ source_set("revision_info") { source_set("paths") { sources = [ "AttributePathParams.h", + "CommandPathParams.h", + "CommandPathRegistry.h", + "ConcreteAttributePath.h", "ConcreteClusterPath.h", + "ConcreteCommandPath.h", "ConcreteEventPath.h", "DataVersionFilter.h", "EventPathParams.h", @@ -88,6 +100,7 @@ source_set("paths") { # This source sets also depends on basic-types.h that is not in any dependency we can use public_deps = [ ":app_config", + "${chip_root}/src/app/util:types", "${chip_root}/src/lib/core", "${chip_root}/src/lib/core:types", ] @@ -129,6 +142,8 @@ static_library("interaction-model") { "CASESessionManager.h", "DeviceProxy.cpp", "DeviceProxy.h", + "InteractionModelDelegatePointers.cpp", + "InteractionModelDelegatePointers.h", "InteractionModelEngine.cpp", "InteractionModelEngine.h", "InteractionModelTimeout.h", @@ -161,6 +176,7 @@ static_library("interaction-model") { "${chip_root}/src/app/icd/server:observer", "${chip_root}/src/lib/address_resolve", "${chip_root}/src/lib/support", + "${chip_root}/src/lib/support:static-support", "${chip_root}/src/protocols/interaction_model", "${chip_root}/src/protocols/secure_channel", "${chip_root}/src/system", @@ -211,15 +227,20 @@ static_library("app") { "CommandHandler.cpp", "CommandResponseHelper.h", "CommandResponseSender.cpp", + "CommandResponseSender.h", "CommandSender.cpp", "DefaultAttributePersistenceProvider.cpp", "DefaultAttributePersistenceProvider.h", "DeferredAttributePersistenceProvider.cpp", "DeferredAttributePersistenceProvider.h", "EventManagement.cpp", + "EventManagement.h", "FailSafeContext.cpp", "FailSafeContext.h", "OTAUserConsentCommon.h", + "PendingResponseTracker.h", + "PendingResponseTrackerImpl.cpp", + "PendingResponseTrackerImpl.h", "ReadHandler.cpp", "SafeAttributePersistenceProvider.h", "TimedRequest.cpp", @@ -228,6 +249,21 @@ static_library("app") { "TimerDelegates.h", "WriteClient.cpp", "WriteHandler.cpp", + + # TODO: the following items cannot be included due to interaction-model circularity + # (app depending on im and im including these headers): + # Name with _ so that linter does not recognize it + # "CommandHandler._h" + # "CommandSender._h", + # "ReadClient._h", + # "ReadHandler._h", + # "WriteClient._h", + # "WriteHandler._h" + + # TODO: the following items cannot be included due to platform includes not being + # able to depend on src/app + # Name with _ so that linter does not recognize it + # "_AttributeAccessInterface._h", ] public_deps = [ @@ -247,9 +283,13 @@ static_library("app") { if (chip_enable_read_client) { sources += [ "BufferedReadCallback.cpp", + "BufferedReadCallback.h", "ClusterStateCache.cpp", "ClusterStateCache.h", "ReadClient.cpp", + + # TODO: cannot include "ReadClient._h" because interaction-model backreference + # Name with _ so that linter does not recognize it ] } diff --git a/src/app/CommandHandler.cpp b/src/app/CommandHandler.cpp index 6831a8440606b2..d0e5db94197e0d 100644 --- a/src/app/CommandHandler.cpp +++ b/src/app/CommandHandler.cpp @@ -214,6 +214,7 @@ Status CommandHandler::ProcessInvokeRequest(System::PacketBufferHandle && payloa SetGroupRequest(true); } + // When updating this code, please remember to make corresponding changes to TestOnlyInvokeCommandRequestWithFaultsInjected. VerifyOrReturnError(invokeRequestMessage.GetSuppressResponse(&mSuppressResponse) == CHIP_NO_ERROR, Status::InvalidAction); VerifyOrReturnError(invokeRequestMessage.GetTimedRequest(&mTimedRequest) == CHIP_NO_ERROR, Status::InvalidAction); VerifyOrReturnError(invokeRequestMessage.GetInvokeRequests(&invokeRequests) == CHIP_NO_ERROR, Status::InvalidAction); @@ -911,6 +912,135 @@ void CommandHandler::MoveToState(const State aTargetState) ChipLogDetail(DataManagement, "Command handler moving to [%10.10s]", GetStateStr()); } +#if CHIP_WITH_NLFAULTINJECTION + +namespace { + +CHIP_ERROR TestOnlyExtractCommandPathFromNextInvokeRequest(TLV::TLVReader & invokeRequestsReader, + ConcreteCommandPath & concretePath) +{ + ReturnErrorOnFailure(invokeRequestsReader.Next(TLV::AnonymousTag())); + CommandDataIB::Parser commandData; + ReturnErrorOnFailure(commandData.Init(invokeRequestsReader)); + CommandPathIB::Parser commandPath; + ReturnErrorOnFailure(commandData.GetPath(&commandPath)); + return commandPath.GetConcreteCommandPath(concretePath); +} + +[[maybe_unused]] const char * GetFaultInjectionTypeStr(CommandHandler::NlFaultInjectionType faultType) +{ + switch (faultType) + { + case CommandHandler::NlFaultInjectionType::SeparateResponseMessages: + return "Each response will be sent in a separate InvokeResponseMessage. The order of responses will be the same as the " + "original request."; + case CommandHandler::NlFaultInjectionType::SeparateResponseMessagesAndInvertedResponseOrder: + return "Each response will be sent in a separate InvokeResponseMessage. The order of responses will be reversed from the " + "original request."; + case CommandHandler::NlFaultInjectionType::SkipSecondResponse: + return "Single InvokeResponseMessages. Dropping response to second request"; + } + VerifyOrDieWithMsg(false, DataManagement, "TH Failure: Unexpected fault type"); +} + +} // anonymous namespace + +// This method intentionally duplicates code from other sections. While code consolidation +// is generally preferred, here we prioritize generating a clear crash message to aid in +// troubleshooting test failures. +void CommandHandler::TestOnlyInvokeCommandRequestWithFaultsInjected(Messaging::ExchangeContext * ec, + System::PacketBufferHandle && payload, bool isTimedInvoke, + NlFaultInjectionType faultType) +{ + VerifyOrDieWithMsg(ec != nullptr, DataManagement, "TH Failure: Incoming exchange context should not be null"); + VerifyOrDieWithMsg(mState == State::Idle, DataManagement, "TH Failure: state should be Idle, issue with TH"); + + ChipLogProgress(DataManagement, "Response to InvokeRequestMessage overridden by fault injection"); + ChipLogProgress(DataManagement, " Injecting the following response:%s", GetFaultInjectionTypeStr(faultType)); + + mResponseSender.SetExchangeContext(ec); + Handle workHandle(this); + mResponseSender.WillSendMessage(); + VerifyOrDieWithMsg(!mResponseSender.IsForGroup(), DataManagement, "DUT Failure: Unexpected Group Command"); + + System::PacketBufferTLVReader reader; + InvokeRequestMessage::Parser invokeRequestMessage; + InvokeRequests::Parser invokeRequests; + reader.Init(std::move(payload)); + VerifyOrDieWithMsg(invokeRequestMessage.Init(reader) == CHIP_NO_ERROR, DataManagement, + "TH Failure: Failed 'invokeRequestMessage.Init(reader)'"); +#if CHIP_CONFIG_IM_PRETTY_PRINT + invokeRequestMessage.PrettyPrint(); +#endif + + VerifyOrDieWithMsg(invokeRequestMessage.GetSuppressResponse(&mSuppressResponse) == CHIP_NO_ERROR, DataManagement, + "DUT Failure: Mandatory SuppressResponse field missing"); + VerifyOrDieWithMsg(invokeRequestMessage.GetTimedRequest(&mTimedRequest) == CHIP_NO_ERROR, DataManagement, + "DUT Failure: Mandatory TimedRequest field missing"); + VerifyOrDieWithMsg(invokeRequestMessage.GetInvokeRequests(&invokeRequests) == CHIP_NO_ERROR, DataManagement, + "DUT Failure: Mandatory InvokeRequests field missing"); + VerifyOrDieWithMsg(mTimedRequest == isTimedInvoke, DataManagement, + "DUT Failure: TimedRequest value in message mismatches action"); + + { + InvokeRequestMessage::Parser validationInvokeRequestMessage = invokeRequestMessage; + VerifyOrDieWithMsg(ValidateInvokeRequestMessageAndBuildRegistry(validationInvokeRequestMessage) == CHIP_NO_ERROR, + DataManagement, "DUT Failure: InvokeRequestMessage contents were invalid"); + } + + TLV::TLVReader invokeRequestsReader; + invokeRequests.GetReader(&invokeRequestsReader); + + size_t commandCount = 0; + VerifyOrDieWithMsg(TLV::Utilities::Count(invokeRequestsReader, commandCount, false /* recurse */) == CHIP_NO_ERROR, + DataManagement, + "TH Failure: Failed to get the length of InvokeRequests after InvokeRequestMessage validation"); + + // The command count check (specifically for a count of 2) is tied to IDM_1_3. This may need adjustment for + // compatibility with future test plans. + VerifyOrDieWithMsg(commandCount == 2, DataManagement, "DUT failure: We were strictly expecting exactly 2 InvokeRequests"); + mReserveSpaceForMoreChunkMessages = true; + + { + // Response path is the same as request path since we are replying with a failure message. + ConcreteCommandPath concreteResponsePath1; + ConcreteCommandPath concreteResponsePath2; + VerifyOrDieWithMsg( + TestOnlyExtractCommandPathFromNextInvokeRequest(invokeRequestsReader, concreteResponsePath1) == CHIP_NO_ERROR, + DataManagement, "DUT Failure: Issues encountered while extracting the ConcreteCommandPath from the first request"); + VerifyOrDieWithMsg( + TestOnlyExtractCommandPathFromNextInvokeRequest(invokeRequestsReader, concreteResponsePath2) == CHIP_NO_ERROR, + DataManagement, "DUT Failure: Issues encountered while extracting the ConcreteCommandPath from the second request"); + + if (faultType == NlFaultInjectionType::SeparateResponseMessagesAndInvertedResponseOrder) + { + ConcreteCommandPath temp(concreteResponsePath1); + concreteResponsePath1 = concreteResponsePath2; + concreteResponsePath2 = temp; + } + + VerifyOrDieWithMsg(FallibleAddStatus(concreteResponsePath1, Status::Failure) == CHIP_NO_ERROR, DataManagement, + "TH Failure: Error adding the first InvokeResponse"); + if (faultType == NlFaultInjectionType::SeparateResponseMessages || + faultType == NlFaultInjectionType::SeparateResponseMessagesAndInvertedResponseOrder) + { + VerifyOrDieWithMsg(FinalizeInvokeResponseMessageAndPrepareNext() == CHIP_NO_ERROR, DataManagement, + "TH Failure: Failed to create second InvokeResponseMessage"); + } + if (faultType != NlFaultInjectionType::SkipSecondResponse) + { + VerifyOrDieWithMsg(FallibleAddStatus(concreteResponsePath2, Status::Failure) == CHIP_NO_ERROR, DataManagement, + "TH Failure: Error adding the second InvokeResponse"); + } + } + + VerifyOrDieWithMsg(invokeRequestsReader.Next() == CHIP_END_OF_TLV, DataManagement, + "DUT Failure: Unexpected TLV ending of InvokeRequests"); + VerifyOrDieWithMsg(invokeRequestMessage.ExitContainer() == CHIP_NO_ERROR, DataManagement, + "DUT Failure: InvokeRequestMessage TLV is not properly terminated"); +} +#endif // CHIP_WITH_NLFAULTINJECTION + } // namespace app } // namespace chip diff --git a/src/app/CommandHandler.h b/src/app/CommandHandler.h index b90cb821244336..f7acd709b26808 100644 --- a/src/app/CommandHandler.h +++ b/src/app/CommandHandler.h @@ -429,6 +429,35 @@ class CommandHandler return mResponseSender.GetSubjectDescriptor(); } +#if CHIP_WITH_NLFAULTINJECTION + + enum class NlFaultInjectionType : uint8_t + { + SeparateResponseMessages, + SeparateResponseMessagesAndInvertedResponseOrder, + SkipSecondResponse + }; + + /** + * @brief Sends InvokeResponseMessages with injected faults for certification testing. + * + * The Test Harness (TH) uses this to simulate various server response behaviors, + * ensuring the Device Under Test (DUT) handles responses per specification. + * + * This function strictly validates the DUT's InvokeRequestMessage against the test plan. + * If deviations occur, the TH terminates with a detailed error message. + * + * @param ec Exchange context for sending InvokeResponseMessages to the client. + * @param payload Payload of the incoming InvokeRequestMessage from the client. + * @param isTimedInvoke Indicates whether the interaction is timed. + * @param faultType The specific type of fault to inject into the response. + */ + // TODO(#30453): After refactoring CommandHandler for better unit testability, create a + // unit test specifically for the fault injection behavior. + void TestOnlyInvokeCommandRequestWithFaultsInjected(Messaging::ExchangeContext * ec, System::PacketBufferHandle && payload, + bool isTimedInvoke, NlFaultInjectionType faultType); +#endif // CHIP_WITH_NLFAULTINJECTION + private: friend class TestCommandInteraction; friend class CommandHandler::Handle; diff --git a/src/app/CommandSender.cpp b/src/app/CommandSender.cpp index 7f77d6c98c2bad..03ce2786b93d8d 100644 --- a/src/app/CommandSender.cpp +++ b/src/app/CommandSender.cpp @@ -75,6 +75,9 @@ CommandSender::CommandSender(ExtendableCallback * apExtendableCallback, Messagin mTimedRequest(aIsTimedRequest), mUseExtendableCallback(true) { assertChipStackLockedByCurrentThread(); +#if CHIP_CONFIG_COMMAND_SENDER_BUILTIN_SUPPORT_FOR_BATCHED_COMMANDS + mpPendingResponseTracker = &mNonTestPendingResponseTracker; +#endif // CHIP_CONFIG_COMMAND_SENDER_BUILTIN_SUPPORT_FOR_BATCHED_COMMANDS } CommandSender::~CommandSender() @@ -222,9 +225,9 @@ CHIP_ERROR CommandSender::OnMessageReceived(Messaging::ExchangeContext * apExcha if (aPayloadHeader.HasMessageType(MsgType::InvokeCommandResponse)) { + mInvokeResponseMessageCount++; err = ProcessInvokeResponse(std::move(aPayload), moreChunkedMessages); SuccessOrExit(err); - mInvokeResponseMessageCount++; if (moreChunkedMessages) { StatusResponse::Send(Status::Success, apExchangeContext, /*aExpectResponse = */ true); @@ -258,6 +261,10 @@ CHIP_ERROR CommandSender::OnMessageReceived(Messaging::ExchangeContext * apExcha if (mState != State::AwaitingResponse) { + if (err == CHIP_NO_ERROR) + { + FlushNoCommandResponse(); + } Close(); } // Else we got a response to a Timed Request and just sent the invoke. @@ -331,12 +338,25 @@ void CommandSender::OnResponseTimeout(Messaging::ExchangeContext * apExchangeCon Close(); } +void CommandSender::FlushNoCommandResponse() +{ + if (mpPendingResponseTracker && mUseExtendableCallback && mCallbackHandle.extendableCallback) + { + Optional commandRef = mpPendingResponseTracker->PopPendingResponse(); + while (commandRef.HasValue()) + { + NoResponseData noResponseData = { commandRef.Value() }; + mCallbackHandle.extendableCallback->OnNoResponse(this, noResponseData); + commandRef = mpPendingResponseTracker->PopPendingResponse(); + } + } +} + void CommandSender::Close() { mSuppressResponse = false; mTimedRequest = false; MoveToState(State::AwaitingDestruction); - OnDoneCallback(); } @@ -350,10 +370,10 @@ CHIP_ERROR CommandSender::ProcessInvokeResponseIB(InvokeResponseIB::Parser & aIn StatusIB statusIB; { - bool commandRefExpected = (mFinishedCommandCount > 1); - bool hasDataResponse = false; + bool hasDataResponse = false; TLV::TLVReader commandDataReader; Optional commandRef; + bool commandRefExpected = mpPendingResponseTracker && (mpPendingResponseTracker->Count() > 1); CommandStatusIB::Parser commandStatus; err = aInvokeResponse.GetStatus(&commandStatus); @@ -409,6 +429,27 @@ CHIP_ERROR CommandSender::ProcessInvokeResponseIB(InvokeResponseIB::Parser & aIn } ReturnErrorOnFailure(err); + if (commandRef.HasValue() && mpPendingResponseTracker != nullptr) + { + err = mpPendingResponseTracker->Remove(commandRef.Value()); + if (err != CHIP_NO_ERROR) + { + // This can happen for two reasons: + // 1. The current InvokeResponse is a duplicate (based on its commandRef). + // 2. The current InvokeResponse is for a request we never sent (based on its commandRef). + // Used when logging errors related to server violating spec. + [[maybe_unused]] ScopedNodeId remoteScopedNode; + if (mExchangeCtx.Get()->HasSessionHandle()) + { + remoteScopedNode = mExchangeCtx.Get()->GetSessionHandle()->GetPeer(); + } + ChipLogError(DataManagement, + "Received Unexpected Response from remote node " ChipLogFormatScopedNodeId ", commandRef=%u", + ChipLogValueScopedNodeId(remoteScopedNode), commandRef.Value()); + return err; + } + } + // When using ExtendableCallbacks, we are adhering to a different API contract where path // specific errors are sent to the OnResponse callback. For more information on the history // of this issue please see https://github.com/project-chip/connectedhomeip/issues/30991 @@ -430,17 +471,19 @@ CHIP_ERROR CommandSender::ProcessInvokeResponseIB(InvokeResponseIB::Parser & aIn CHIP_ERROR CommandSender::SetCommandSenderConfig(CommandSender::ConfigParameters & aConfigParams) { -#if CHIP_CONFIG_SENDING_BATCH_COMMANDS_ENABLED VerifyOrReturnError(mState == State::Idle, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(aConfigParams.remoteMaxPathsPerInvoke > 0, CHIP_ERROR_INVALID_ARGUMENT); + if (mpPendingResponseTracker != nullptr) + { - mRemoteMaxPathsPerInvoke = aConfigParams.remoteMaxPathsPerInvoke; - mBatchCommandsEnabled = (aConfigParams.remoteMaxPathsPerInvoke > 1); - return CHIP_NO_ERROR; -#else - VerifyOrReturnError(aConfigParams.remoteMaxPathsPerInvoke == 1, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + mRemoteMaxPathsPerInvoke = aConfigParams.remoteMaxPathsPerInvoke; + mBatchCommandsEnabled = (aConfigParams.remoteMaxPathsPerInvoke > 1); + } + else + { + VerifyOrReturnError(aConfigParams.remoteMaxPathsPerInvoke == 1, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + } return CHIP_NO_ERROR; -#endif } CHIP_ERROR CommandSender::PrepareCommand(const CommandPathParams & aCommandPathParams, @@ -453,12 +496,19 @@ CHIP_ERROR CommandSender::PrepareCommand(const CommandPathParams & aCommandPathP // bool canAddAnotherCommand = (mState == State::AddedCommand && mBatchCommandsEnabled && mUseExtendableCallback); VerifyOrReturnError(mState == State::Idle || canAddAnotherCommand, CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mFinishedCommandCount < mRemoteMaxPathsPerInvoke, CHIP_ERROR_MAXIMUM_PATHS_PER_INVOKE_EXCEEDED); + + if (mpPendingResponseTracker != nullptr) + { + size_t pendingCount = mpPendingResponseTracker->Count(); + VerifyOrReturnError(pendingCount < mRemoteMaxPathsPerInvoke, CHIP_ERROR_MAXIMUM_PATHS_PER_INVOKE_EXCEEDED); + } if (mBatchCommandsEnabled) { + VerifyOrReturnError(mpPendingResponseTracker != nullptr, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(aPrepareCommandParams.commandRef.HasValue(), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(aPrepareCommandParams.commandRef.Value() == mFinishedCommandCount, CHIP_ERROR_INVALID_ARGUMENT); + uint16_t commandRef = aPrepareCommandParams.commandRef.Value(); + VerifyOrReturnError(!mpPendingResponseTracker->IsTracked(commandRef), CHIP_ERROR_INVALID_ARGUMENT); } InvokeRequests::Builder & invokeRequests = mInvokeRequestBuilder.GetInvokeRequests(); @@ -482,8 +532,10 @@ CHIP_ERROR CommandSender::FinishCommand(FinishCommandParameters & aFinishCommand { if (mBatchCommandsEnabled) { + VerifyOrReturnError(mpPendingResponseTracker != nullptr, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(aFinishCommandParams.commandRef.HasValue(), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(aFinishCommandParams.commandRef.Value() == mFinishedCommandCount, CHIP_ERROR_INVALID_ARGUMENT); + uint16_t commandRef = aFinishCommandParams.commandRef.Value(); + VerifyOrReturnError(!mpPendingResponseTracker->IsTracked(commandRef), CHIP_ERROR_INVALID_ARGUMENT); } return FinishCommandInternal(aFinishCommandParams); @@ -511,7 +563,10 @@ CHIP_ERROR CommandSender::FinishCommandInternal(FinishCommandParameters & aFinis MoveToState(State::AddedCommand); - mFinishedCommandCount++; + if (mpPendingResponseTracker && aFinishCommandParams.commandRef.HasValue()) + { + mpPendingResponseTracker->Add(aFinishCommandParams.commandRef.Value()); + } if (aFinishCommandParams.timedInvokeTimeoutMs.HasValue()) { diff --git a/src/app/CommandSender.h b/src/app/CommandSender.h index fa213ac0699832..ef1a5f97dd3e85 100644 --- a/src/app/CommandSender.h +++ b/src/app/CommandSender.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,16 @@ class CommandSender final : public Messaging::ExchangeDelegate Optional commandRef; }; + // CommandSender::ExtendableCallback::OnNoResponse is public SDK API, so we cannot break + // source compatibility for it. To allow for additional values to be added at a future + // time without constantly changing the function's declaration parameter list, we are + // defining the struct NoResponseData and adding that to the parameter list to allow for + // future extendability. + struct NoResponseData + { + uint16_t commandRef; + }; + // CommandSender::ExtendableCallback::OnError is public SDK API, so we cannot break source // compatibility for it. To allow for additional values to be added at a future time // without constantly changing the function's declaration parameter list, we are @@ -127,9 +138,21 @@ class CommandSender final : public Messaging::ExchangeDelegate * @param[in] apCommandSender The command sender object that initiated the command transaction. * @param[in] aResponseData Information pertaining to the response. */ - ; virtual void OnResponse(CommandSender * commandSender, const ResponseData & aResponseData) {} + /** + * Called for each request that failed to receive a response after the server indicates completion of all requests. + * + * This callback may be omitted if clients have alternative ways to track non-responses. + * + * The CommandSender object MUST continue to exist after this call is completed. The application shall wait until it + * receives an OnDone call to destroy the object. + * + * @param apCommandSender The CommandSender object that initiated the transaction. + * @param aNoResponseData Details about the request without a response. + */ + virtual void OnNoResponse(CommandSender * commandSender, const NoResponseData & aNoResponseData) {} + /** * OnError will be called when a non-path-specific error occurs *after* a successful call to SendCommandRequest(). * @@ -229,12 +252,6 @@ class CommandSender final : public Messaging::ExchangeDelegate // early in PrepareCommand, even though it's not used until FinishCommand. This proactive // validation helps prevent unnecessary writing an InvokeRequest into the packet that later // needs to be undone. - // - // Currently, provided commandRefs for the first request must start at 0 and increment by one - // for each subsequent request. This requirement can be relaxed in the future if a compelling - // need arises. - // TODO(#30453): After introducing Request/Response tracking, remove statement above about - // this currently enforced requirement on commandRefs. Optional commandRef; // If the InvokeRequest needs to be in a state with a started data TLV struct container bool startDataStruct = false; @@ -278,6 +295,10 @@ class CommandSender final : public Messaging::ExchangeDelegate bool endDataStruct = false; }; + class TestOnlyMarker + { + }; + /* * Constructor. * @@ -287,12 +308,20 @@ class CommandSender final : public Messaging::ExchangeDelegate */ CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest = false, bool aSuppressResponse = false); - CommandSender(ExtendableCallback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest = false, - bool aSuppressResponse = false); CommandSender(std::nullptr_t, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest = false, bool aSuppressResponse = false) : CommandSender(static_cast(nullptr), apExchangeMgr, aIsTimedRequest, aSuppressResponse) {} + CommandSender(ExtendableCallback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest = false, + bool aSuppressResponse = false); + // TODO(#32138): After there is a macro that is always defined for all unit tests, the constructor with + // TestOnlyMarker should only be compiled if that macro is defined. + CommandSender(TestOnlyMarker aTestMarker, ExtendableCallback * apCallback, Messaging::ExchangeManager * apExchangeMgr, + PendingResponseTracker * apPendingResponseTracker, bool aIsTimedRequest = false, bool aSuppressResponse = false) : + CommandSender(apCallback, apExchangeMgr, aIsTimedRequest, aSuppressResponse) + { + mpPendingResponseTracker = apPendingResponseTracker; + } ~CommandSender(); /** @@ -307,11 +336,14 @@ class CommandSender final : public Messaging::ExchangeDelegate * based on how many paths the remote peer claims to support. * * @return CHIP_ERROR_INCORRECT_STATE - * If device has previously called `PrepareCommand`. + * If device has previously called `PrepareCommand`. * @return CHIP_ERROR_INVALID_ARGUMENT - * Invalid argument value. + * Invalid argument value. * @return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE - * Device has not enabled CHIP_CONFIG_SENDING_BATCH_COMMANDS_ENABLED. + * Device has not enabled batch command support. To enable: + * 1. Enable the CHIP_CONFIG_COMMAND_SENDER_BUILTIN_SUPPORT_FOR_BATCHED_COMMANDS + * configuration option. + * 2. Ensure you provide ExtendableCallback. */ CHIP_ERROR SetCommandSenderConfig(ConfigParameters & aConfigParams); @@ -497,6 +529,7 @@ class CommandSender final : public Messaging::ExchangeDelegate System::PacketBufferHandle && aPayload) override; void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override; + void FlushNoCommandResponse(); // // Called internally to signal the completion of all work on this object, gracefully close the // exchange (by calling into the base class) and finally, signal to the application that it's @@ -580,8 +613,12 @@ class CommandSender final : public Messaging::ExchangeDelegate chip::System::PacketBufferTLVWriter mCommandMessageWriter; +#if CHIP_CONFIG_COMMAND_SENDER_BUILTIN_SUPPORT_FOR_BATCHED_COMMANDS + PendingResponseTrackerImpl mNonTestPendingResponseTracker; +#endif // CHIP_CONFIG_COMMAND_SENDER_BUILTIN_SUPPORT_FOR_BATCHED_COMMANDS + PendingResponseTracker * mpPendingResponseTracker = nullptr; + uint16_t mInvokeResponseMessageCount = 0; - uint16_t mFinishedCommandCount = 0; uint16_t mRemoteMaxPathsPerInvoke = 1; State mState = State::Idle; diff --git a/src/app/ConcreteAttributePath.h b/src/app/ConcreteAttributePath.h index 076575dcafa2a1..253b590ef90739 100644 --- a/src/app/ConcreteAttributePath.h +++ b/src/app/ConcreteAttributePath.h @@ -87,6 +87,10 @@ struct ConcreteReadAttributePath : public ConcreteAttributePath mListIndex.SetValue(aListIndex); } + bool operator==(const ConcreteReadAttributePath & aOther) const = delete; + bool operator!=(const ConcreteReadAttributePath & aOther) const = delete; + bool operator<(const ConcreteReadAttributePath & aOther) const = delete; + Optional mListIndex; }; @@ -138,6 +142,12 @@ struct ConcreteDataAttributePath : public ConcreteAttributePath ChipLogValueMEI(mClusterId), ChipLogValueMEI(mAttributeId)); } + bool MatchesConcreteAttributePath(const ConcreteAttributePath & aOther) { return ConcreteAttributePath::operator==(aOther); } + + bool operator==(const ConcreteDataAttributePath & aOther) const = delete; + bool operator!=(const ConcreteDataAttributePath & aOther) const = delete; + bool operator<(const ConcreteDataAttributePath & aOther) const = delete; + // // This index is only valid if `mListOp` is set to a list item operation, i.e // ReplaceItem, DeleteItem or AppendItem. Otherwise, it is to be ignored. diff --git a/src/app/ConcreteCommandPath.h b/src/app/ConcreteCommandPath.h index 5020aa0ba6d2c0..42845b64241053 100644 --- a/src/app/ConcreteCommandPath.h +++ b/src/app/ConcreteCommandPath.h @@ -33,6 +33,8 @@ struct ConcreteCommandPath : public ConcreteClusterPath ConcreteClusterPath(aEndpointId, aClusterId), mCommandId(aCommandId) {} + ConcreteCommandPath() : ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId), mCommandId(kInvalidCommandId) {} + bool operator==(const ConcreteCommandPath & aOther) const { return ConcreteClusterPath::operator==(aOther) && (mCommandId == aOther.mCommandId); diff --git a/src/app/EventLoggingTypes.h b/src/app/EventLoggingTypes.h index 35fd37a25045ca..04a843ebcfbd60 100644 --- a/src/app/EventLoggingTypes.h +++ b/src/app/EventLoggingTypes.h @@ -19,11 +19,11 @@ #include #include -#include #include #include #include #include +#include #include inline constexpr size_t kNumPriorityLevel = 3; @@ -151,10 +151,10 @@ struct EventLoadOutContext EventNumber mStartingEventNumber = 0; Timestamp mPreviousTime; Timestamp mCurrentTime; - EventNumber mCurrentEventNumber = 0; - size_t mEventCount = 0; - const ObjectList * mpInterestedEventPaths = nullptr; - bool mFirst = true; + EventNumber mCurrentEventNumber = 0; + size_t mEventCount = 0; + const SingleLinkedListNode * mpInterestedEventPaths = nullptr; + bool mFirst = true; Access::SubjectDescriptor mSubjectDescriptor; }; } // namespace app diff --git a/src/app/EventManagement.cpp b/src/app/EventManagement.cpp index aa3abd67f828d8..8e6d53c24c9636 100644 --- a/src/app/EventManagement.cpp +++ b/src/app/EventManagement.cpp @@ -639,7 +639,7 @@ CHIP_ERROR EventManagement::CopyEventsSince(const TLVReader & aReader, size_t aD return err; } -CHIP_ERROR EventManagement::FetchEventsSince(TLVWriter & aWriter, const ObjectList * apEventPathList, +CHIP_ERROR EventManagement::FetchEventsSince(TLVWriter & aWriter, const SingleLinkedListNode * apEventPathList, EventNumber & aEventMin, size_t & aEventCount, const Access::SubjectDescriptor & aSubjectDescriptor) { diff --git a/src/app/EventManagement.h b/src/app/EventManagement.h index 228c26cca94a68..950efdc2bae867 100644 --- a/src/app/EventManagement.h +++ b/src/app/EventManagement.h @@ -31,10 +31,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -359,7 +359,7 @@ class EventManagement * available. * */ - CHIP_ERROR FetchEventsSince(chip::TLV::TLVWriter & aWriter, const ObjectList * apEventPathList, + CHIP_ERROR FetchEventsSince(chip::TLV::TLVWriter & aWriter, const SingleLinkedListNode * apEventPathList, EventNumber & aEventMin, size_t & aEventCount, const Access::SubjectDescriptor & aSubjectDescriptor); /** diff --git a/src/app/InteractionModelDelegatePointers.cpp b/src/app/InteractionModelDelegatePointers.cpp new file mode 100644 index 00000000000000..af4c85ee1bb1c2 --- /dev/null +++ b/src/app/InteractionModelDelegatePointers.cpp @@ -0,0 +1,36 @@ +/* + * + * 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 "InteractionModelDelegatePointers.h" + +#if CHIP_CONFIG_STATIC_GLOBAL_INTERACTION_MODEL_ENGINE + +// TODO: It would be nice to not need to couple the pointers class +// to the global interaction model engine +#include "InteractionModelEngine.h" + +namespace chip { + +template <> +app::TimedHandlerDelegate * GlobalInstanceProvider::InstancePointer() +{ + return app::InteractionModelEngine::GetInstance(); +} + +} // namespace chip + +#endif diff --git a/src/app/InteractionModelDelegatePointers.h b/src/app/InteractionModelDelegatePointers.h new file mode 100644 index 00000000000000..6677022b5561cb --- /dev/null +++ b/src/app/InteractionModelDelegatePointers.h @@ -0,0 +1,37 @@ +/* + * + * 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 + +namespace chip { + +#if CHIP_CONFIG_STATIC_GLOBAL_INTERACTION_MODEL_ENGINE + +template +using InteractionModelDelegatePointer = chip::CheckedGlobalInstanceReference; + +#else + +template +using InteractionModelDelegatePointer = chip::SimpleInstanceReference; + +#endif // CHIP_CONFIG_STATIC_GLOBAL_INTERATION_MODEL_ENGINE + +} // namespace chip diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp index 98cb6ff156a653..8e4b5a80e3df7d 100644 --- a/src/app/InteractionModelEngine.cpp +++ b/src/app/InteractionModelEngine.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -411,6 +412,21 @@ Status InteractionModelEngine::OnInvokeCommandRequest(Messaging::ExchangeContext ChipLogProgress(InteractionModel, "no resource for Invoke interaction"); return Status::Busy; } + CHIP_FAULT_INJECT( + FaultInjection::kFault_IMInvoke_SeparateResponses, + commandHandler->TestOnlyInvokeCommandRequestWithFaultsInjected( + apExchangeContext, std::move(aPayload), aIsTimedInvoke, CommandHandler::NlFaultInjectionType::SeparateResponseMessages); + return Status::Success;); + CHIP_FAULT_INJECT(FaultInjection::kFault_IMInvoke_SeparateResponsesInvertResponseOrder, + commandHandler->TestOnlyInvokeCommandRequestWithFaultsInjected( + apExchangeContext, std::move(aPayload), aIsTimedInvoke, + CommandHandler::NlFaultInjectionType::SeparateResponseMessagesAndInvertedResponseOrder); + return Status::Success;); + CHIP_FAULT_INJECT( + FaultInjection::kFault_IMInvoke_SkipSecondResponse, + commandHandler->TestOnlyInvokeCommandRequestWithFaultsInjected(apExchangeContext, std::move(aPayload), aIsTimedInvoke, + CommandHandler::NlFaultInjectionType::SkipSecondResponse); + return Status::Success;); commandHandler->OnInvokeCommandRequest(apExchangeContext, aPayloadHeader, std::move(aPayload), aIsTimedInvoke); return Status::Success; } @@ -434,7 +450,7 @@ CHIP_ERROR InteractionModelEngine::ParseAttributePaths(const Access::SubjectDesc // This avoids the 'parse all paths' approach that is employed in ReadHandler since we want to // avoid allocating out of the path store during this minimal initial processing stage. // - ObjectList paramsList; + SingleLinkedListNode paramsList; ReturnErrorOnFailure(path.Init(pathReader)); ReturnErrorOnFailure(path.ParsePath(paramsList.mValue)); @@ -840,7 +856,7 @@ CHIP_ERROR InteractionModelEngine::OnTimedRequest(Messaging::ExchangeContext * a const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload, Protocols::InteractionModel::Status & aStatus) { - TimedHandler * handler = mTimedHandlers.CreateObject(); + TimedHandler * handler = mTimedHandlers.CreateObject(this); if (handler == nullptr) { ChipLogProgress(InteractionModel, "no resource for Timed interaction"); @@ -1497,12 +1513,12 @@ bool InteractionModelEngine::HasConflictWriteRequests(const WriteHandler * apWri return false; } -void InteractionModelEngine::ReleaseAttributePathList(ObjectList *& aAttributePathList) +void InteractionModelEngine::ReleaseAttributePathList(SingleLinkedListNode *& aAttributePathList) { ReleasePool(aAttributePathList, mAttributePathPool); } -CHIP_ERROR InteractionModelEngine::PushFrontAttributePathList(ObjectList *& aAttributePathList, +CHIP_ERROR InteractionModelEngine::PushFrontAttributePathList(SingleLinkedListNode *& aAttributePathList, AttributePathParams & aAttributePath) { CHIP_ERROR err = PushFront(aAttributePathList, aAttributePath, mAttributePathPool); @@ -1514,10 +1530,10 @@ CHIP_ERROR InteractionModelEngine::PushFrontAttributePathList(ObjectList *& aAttributePaths) +void InteractionModelEngine::RemoveDuplicateConcreteAttributePath(SingleLinkedListNode *& aAttributePaths) { - ObjectList * prev = nullptr; - auto * path1 = aAttributePaths; + SingleLinkedListNode * prev = nullptr; + auto * path1 = aAttributePaths; while (path1 != nullptr) { @@ -1569,12 +1585,12 @@ void InteractionModelEngine::RemoveDuplicateConcreteAttributePath(ObjectList *& aEventPathList) +void InteractionModelEngine::ReleaseEventPathList(SingleLinkedListNode *& aEventPathList) { ReleasePool(aEventPathList, mEventPathPool); } -CHIP_ERROR InteractionModelEngine::PushFrontEventPathParamsList(ObjectList *& aEventPathList, +CHIP_ERROR InteractionModelEngine::PushFrontEventPathParamsList(SingleLinkedListNode *& aEventPathList, EventPathParams & aEventPath) { CHIP_ERROR err = PushFront(aEventPathList, aEventPath, mEventPathPool); @@ -1586,12 +1602,12 @@ CHIP_ERROR InteractionModelEngine::PushFrontEventPathParamsList(ObjectList *& aDataVersionFilterList) +void InteractionModelEngine::ReleaseDataVersionFilterList(SingleLinkedListNode *& aDataVersionFilterList) { ReleasePool(aDataVersionFilterList, mDataVersionFilterPool); } -CHIP_ERROR InteractionModelEngine::PushFrontDataVersionFilterList(ObjectList *& aDataVersionFilterList, +CHIP_ERROR InteractionModelEngine::PushFrontDataVersionFilterList(SingleLinkedListNode *& aDataVersionFilterList, DataVersionFilter & aDataVersionFilter) { CHIP_ERROR err = PushFront(aDataVersionFilterList, aDataVersionFilter, mDataVersionFilterPool); @@ -1604,12 +1620,13 @@ CHIP_ERROR InteractionModelEngine::PushFrontDataVersionFilterList(ObjectList -void InteractionModelEngine::ReleasePool(ObjectList *& aObjectList, ObjectPool, N> & aObjectPool) +void InteractionModelEngine::ReleasePool(SingleLinkedListNode *& aObjectList, + ObjectPool, N> & aObjectPool) { - ObjectList * current = aObjectList; + SingleLinkedListNode * current = aObjectList; while (current != nullptr) { - ObjectList * nextObject = current->mpNext; + SingleLinkedListNode * nextObject = current->mpNext; aObjectPool.ReleaseObject(current); current = nextObject; } @@ -1618,9 +1635,10 @@ void InteractionModelEngine::ReleasePool(ObjectList *& aObjectList, ObjectPoo } template -CHIP_ERROR InteractionModelEngine::PushFront(ObjectList *& aObjectList, T & aData, ObjectPool, N> & aObjectPool) +CHIP_ERROR InteractionModelEngine::PushFront(SingleLinkedListNode *& aObjectList, T & aData, + ObjectPool, N> & aObjectPool) { - ObjectList * object = aObjectPool.CreateObject(); + SingleLinkedListNode * object = aObjectPool.CreateObject(); if (object == nullptr) { return CHIP_ERROR_NO_MEMORY; diff --git a/src/app/InteractionModelEngine.h b/src/app/InteractionModelEngine.h index 8ed201a0d934e6..1c05767299dfbb 100644 --- a/src/app/InteractionModelEngine.h +++ b/src/app/InteractionModelEngine.h @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -54,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -80,7 +80,8 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler, public CommandHandler::Callback, public ReadHandler::ManagementCallback, public FabricTable::Delegate, - public SubscriptionsInfoProvider + public SubscriptionsInfoProvider, + public TimedHandlerDelegate { public: /** @@ -186,22 +187,22 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler, reporting::ReportScheduler * GetReportScheduler() { return mReportScheduler; } - void ReleaseAttributePathList(ObjectList *& aAttributePathList); + void ReleaseAttributePathList(SingleLinkedListNode *& aAttributePathList); - CHIP_ERROR PushFrontAttributePathList(ObjectList *& aAttributePathList, + CHIP_ERROR PushFrontAttributePathList(SingleLinkedListNode *& aAttributePathList, AttributePathParams & aAttributePath); // If a concrete path indicates an attribute that is also referenced by a wildcard path in the request, // the path SHALL be removed from the list. - void RemoveDuplicateConcreteAttributePath(ObjectList *& aAttributePaths); + void RemoveDuplicateConcreteAttributePath(SingleLinkedListNode *& aAttributePaths); - void ReleaseEventPathList(ObjectList *& aEventPathList); + void ReleaseEventPathList(SingleLinkedListNode *& aEventPathList); - CHIP_ERROR PushFrontEventPathParamsList(ObjectList *& aEventPathList, EventPathParams & aEventPath); + CHIP_ERROR PushFrontEventPathParamsList(SingleLinkedListNode *& aEventPathList, EventPathParams & aEventPath); - void ReleaseDataVersionFilterList(ObjectList *& aDataVersionFilterList); + void ReleaseDataVersionFilterList(SingleLinkedListNode *& aDataVersionFilterList); - CHIP_ERROR PushFrontDataVersionFilterList(ObjectList *& aDataVersionFilterList, + CHIP_ERROR PushFrontDataVersionFilterList(SingleLinkedListNode *& aDataVersionFilterList, DataVersionFilter & aDataVersionFilter); CHIP_ERROR RegisterCommandHandler(CommandHandlerInterface * handler); @@ -218,26 +219,12 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler, } void UnregisterReadHandlerAppCallback() { mpReadHandlerApplicationCallback = nullptr; } - /** - * Called when a timed interaction has failed (i.e. the exchange it was - * happening on has closed while the exchange delegate was the timed - * handler). - */ - void OnTimedInteractionFailed(TimedHandler * apTimedHandler); - - /** - * Called when a timed invoke is received. This function takes over all - * handling of the exchange, status reporting, and so forth. - */ + // TimedHandlerDelegate implementation + void OnTimedInteractionFailed(TimedHandler * apTimedHandler) override; void OnTimedInvoke(TimedHandler * apTimedHandler, Messaging::ExchangeContext * apExchangeContext, - const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload); - - /** - * Called when a timed write is received. This function takes over all - * handling of the exchange, status reporting, and so forth. - */ + const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) override; void OnTimedWrite(TimedHandler * apTimedHandler, Messaging::ExchangeContext * apExchangeContext, - const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload); + const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) override; #if CHIP_CONFIG_ENABLE_READ_CLIENT /** @@ -589,9 +576,9 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler, static void ResumeSubscriptionsTimerCallback(System::Layer * apSystemLayer, void * apAppState); template - void ReleasePool(ObjectList *& aObjectList, ObjectPool, N> & aObjectPool); + void ReleasePool(SingleLinkedListNode *& aObjectList, ObjectPool, N> & aObjectPool); template - CHIP_ERROR PushFront(ObjectList *& aObjectList, T & aData, ObjectPool, N> & aObjectPool); + CHIP_ERROR PushFront(SingleLinkedListNode *& aObjectList, T & aData, ObjectPool, N> & aObjectPool); Messaging::ExchangeManager * mpExchangeMgr = nullptr; @@ -619,13 +606,13 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler, "CHIP_IM_MAX_NUM_READS is too small to match the requirements of spec 8.5.1"); #endif - ObjectPool, + ObjectPool, CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS + CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS> mAttributePathPool; - ObjectPool, + ObjectPool, CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS + CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS> mEventPathPool; - ObjectPool, + ObjectPool, CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS + CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS> mDataVersionFilterPool; diff --git a/src/app/PendingResponseTracker.h b/src/app/PendingResponseTracker.h new file mode 100644 index 00000000000000..47bb37dd026629 --- /dev/null +++ b/src/app/PendingResponseTracker.h @@ -0,0 +1,75 @@ +/* + * 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 + +namespace chip { +namespace app { + +/** + * @brief Interface for tracking responses to outbound InvokeRequests. + * + * This interface enables clients to: + * * Verify that received responses correspond to issued InvokeRequests. + * * Detect outstanding responses after the server indicates completion, helpful for identifying response omissions. + */ +class PendingResponseTracker +{ +public: + virtual ~PendingResponseTracker() = default; + + /** + * Start tracking the given `aCommandRef` + * + * @return CHIP_ERROR_INVALID_ARGUMENT if `aCommandRef` is already being tracked. + */ + virtual CHIP_ERROR Add(uint16_t aCommandRef) = 0; + + /** + * Removes tracking for the given `aCommandRef` + * + * @return CHIP_ERROR_KEY_NOT_FOUND if aCommandRef is not currently tracked. + */ + virtual CHIP_ERROR Remove(uint16_t aCommandRef) = 0; + + /** + * Checks if the given `aCommandRef` is being tracked. + */ + virtual bool IsTracked(uint16_t aCommandRef) = 0; + + /** + * Returns the number of pending responses. + */ + virtual size_t Count() = 0; + + /** + * Removes a pending response command reference from the tracker. + * + * Deletes an element from the tracker (order not guaranteed). This function can be called + * repeatedly to remove all tracked pending responses. + * + * @return NullOptional if the tracker is empty. + * @return Optional containing the CommandReference of a removed pending response. + */ + virtual Optional PopPendingResponse() = 0; +}; + +} // namespace app +} // namespace chip diff --git a/src/app/PendingResponseTrackerImpl.cpp b/src/app/PendingResponseTrackerImpl.cpp new file mode 100644 index 00000000000000..72f5fb8a197697 --- /dev/null +++ b/src/app/PendingResponseTrackerImpl.cpp @@ -0,0 +1,61 @@ +/* + * 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 + +namespace chip { +namespace app { + +CHIP_ERROR PendingResponseTrackerImpl::Add(uint16_t aCommandRef) +{ + VerifyOrReturnError(!IsTracked(aCommandRef), CHIP_ERROR_INVALID_ARGUMENT); + mCommandReferenceSet.insert(aCommandRef); + return CHIP_NO_ERROR; +} + +CHIP_ERROR PendingResponseTrackerImpl::Remove(uint16_t aCommandRef) +{ + VerifyOrReturnError(IsTracked(aCommandRef), CHIP_ERROR_KEY_NOT_FOUND); + mCommandReferenceSet.erase(aCommandRef); + return CHIP_NO_ERROR; +} + +bool PendingResponseTrackerImpl::IsTracked(uint16_t aCommandRef) +{ + return mCommandReferenceSet.find(aCommandRef) != mCommandReferenceSet.end(); +} + +size_t PendingResponseTrackerImpl::Count() +{ + return mCommandReferenceSet.size(); +} + +Optional PendingResponseTrackerImpl::PopPendingResponse() +{ + if (Count() == 0) + { + return NullOptional; + } + uint16_t commandRef = *mCommandReferenceSet.begin(); + mCommandReferenceSet.erase(mCommandReferenceSet.begin()); + return MakeOptional(commandRef); +} + +} // namespace app +} // namespace chip diff --git a/src/app/PendingResponseTrackerImpl.h b/src/app/PendingResponseTrackerImpl.h new file mode 100644 index 00000000000000..8d6ade2ae5bb69 --- /dev/null +++ b/src/app/PendingResponseTrackerImpl.h @@ -0,0 +1,44 @@ +/* + * 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 + +namespace chip { +namespace app { + +/** + * @brief An implementation of PendingResponseTracker. + */ +class PendingResponseTrackerImpl : public PendingResponseTracker +{ +public: + CHIP_ERROR Add(uint16_t aCommandRef) override; + CHIP_ERROR Remove(uint16_t aCommandRef) override; + bool IsTracked(uint16_t aCommandRef) override; + size_t Count() override; + Optional PopPendingResponse() override; + +private: + std::unordered_set mCommandReferenceSet; +}; + +} // namespace app +} // namespace chip diff --git a/src/app/ReadClient.cpp b/src/app/ReadClient.cpp index 4a123fe01b6291..57ef57362a25fa 100644 --- a/src/app/ReadClient.cpp +++ b/src/app/ReadClient.cpp @@ -799,9 +799,8 @@ CHIP_ERROR ReadClient::ProcessAttributeReportIBs(TLV::TLVReader & aAttributeRepo attributePath.mListOp = ConcreteDataAttributePath::ListOperation::ReplaceAll; } - if (attributePath == - ConcreteDataAttributePath(kRootEndpointId, Clusters::IcdManagement::Id, - Clusters::IcdManagement::Attributes::OperatingMode::Id)) + if (attributePath.MatchesConcreteAttributePath(ConcreteAttributePath( + kRootEndpointId, Clusters::IcdManagement::Id, Clusters::IcdManagement::Attributes::OperatingMode::Id))) { PeerType peerType; TLV::TLVReader operatingModeTlvReader; diff --git a/src/app/ReadHandler.cpp b/src/app/ReadHandler.cpp index b5fc34484ea8ff..63da2a53aa7470 100644 --- a/src/app/ReadHandler.cpp +++ b/src/app/ReadHandler.cpp @@ -134,7 +134,7 @@ void ReadHandler::OnSubscriptionResumed(const SessionHandle & sessionHandle, MoveToState(HandlerState::CanStartReporting); - ObjectList * attributePath = mpAttributePathList; + SingleLinkedListNode * attributePath = mpAttributePathList; while (attributePath) { mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().SetDirty(attributePath->mValue); diff --git a/src/app/ReadHandler.h b/src/app/ReadHandler.h index 71070c357147df..c597bac8a58d70 100644 --- a/src/app/ReadHandler.h +++ b/src/app/ReadHandler.h @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -45,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -224,9 +224,9 @@ class ReadHandler : public Messaging::ExchangeDelegate ReadHandler(ManagementCallback & apCallback, Observer * observer); #endif - const ObjectList * GetAttributePathList() const { return mpAttributePathList; } - const ObjectList * GetEventPathList() const { return mpEventPathList; } - const ObjectList * GetDataVersionFilterList() const { return mpDataVersionFilterList; } + const SingleLinkedListNode * GetAttributePathList() const { return mpAttributePathList; } + const SingleLinkedListNode * GetEventPathList() const { return mpEventPathList; } + const SingleLinkedListNode * GetDataVersionFilterList() const { return mpDataVersionFilterList; } void GetReportingIntervals(uint16_t & aMinInterval, uint16_t & aMaxInterval) const { @@ -550,9 +550,9 @@ class ReadHandler : public Messaging::ExchangeDelegate Messaging::ExchangeManager * mExchangeMgr = nullptr; #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE - ObjectList * mpAttributePathList = nullptr; - ObjectList * mpEventPathList = nullptr; - ObjectList * mpDataVersionFilterList = nullptr; + SingleLinkedListNode * mpAttributePathList = nullptr; + SingleLinkedListNode * mpEventPathList = nullptr; + SingleLinkedListNode * mpDataVersionFilterList = nullptr; ManagementCallback & mManagementCallback; diff --git a/src/app/SubscriptionResumptionStorage.h b/src/app/SubscriptionResumptionStorage.h index 316adc3bd3c2e3..19342599f36bbc 100644 --- a/src/app/SubscriptionResumptionStorage.h +++ b/src/app/SubscriptionResumptionStorage.h @@ -78,15 +78,15 @@ class SubscriptionResumptionStorage bool mFabricFiltered; Platform::ScopedMemoryBufferWithSize mAttributePaths; Platform::ScopedMemoryBufferWithSize mEventPaths; - CHIP_ERROR SetAttributePaths(const ObjectList * pAttributePathList) + CHIP_ERROR SetAttributePaths(const SingleLinkedListNode * pAttributePathList) { mAttributePaths.Free(); if (!pAttributePathList) { return CHIP_NO_ERROR; } - const ObjectList * attributePath = pAttributePathList; - size_t attributePathCount = 0; + const SingleLinkedListNode * attributePath = pAttributePathList; + size_t attributePathCount = 0; while (attributePath) { attributePathCount++; @@ -103,15 +103,15 @@ class SubscriptionResumptionStorage } return CHIP_NO_ERROR; } - CHIP_ERROR SetEventPaths(const ObjectList * pEventPathList) + CHIP_ERROR SetEventPaths(const SingleLinkedListNode * pEventPathList) { mEventPaths.Free(); if (!pEventPathList) { return CHIP_NO_ERROR; } - const ObjectList * eventPath = pEventPathList; - size_t eventPathCount = 0; + const SingleLinkedListNode * eventPath = pEventPathList; + size_t eventPathCount = 0; while (eventPath) { eventPathCount++; diff --git a/src/app/TimedHandler.cpp b/src/app/TimedHandler.cpp index d448784721ac59..8df0246ba26728 100644 --- a/src/app/TimedHandler.cpp +++ b/src/app/TimedHandler.cpp @@ -17,7 +17,7 @@ */ #include "TimedHandler.h" -#include +#include #include #include #include @@ -74,19 +74,17 @@ CHIP_ERROR TimedHandler::OnMessageReceived(Messaging::ExchangeContext * aExchang if (aPayloadHeader.HasMessageType(MsgType::InvokeCommandRequest)) { - auto * imEngine = InteractionModelEngine::GetInstance(); ChipLogDetail(DataManagement, "Handing timed invoke to IM engine: handler %p exchange " ChipLogFormatExchange, this, ChipLogValueExchange(aExchangeContext)); - imEngine->OnTimedInvoke(this, aExchangeContext, aPayloadHeader, std::move(aPayload)); + mDelegate->OnTimedInvoke(this, aExchangeContext, aPayloadHeader, std::move(aPayload)); return CHIP_NO_ERROR; } if (aPayloadHeader.HasMessageType(MsgType::WriteRequest)) { - auto * imEngine = InteractionModelEngine::GetInstance(); ChipLogDetail(DataManagement, "Handing timed write to IM engine: handler %p exchange " ChipLogFormatExchange, this, ChipLogValueExchange(aExchangeContext)); - imEngine->OnTimedWrite(this, aExchangeContext, aPayloadHeader, std::move(aPayload)); + mDelegate->OnTimedWrite(this, aExchangeContext, aPayloadHeader, std::move(aPayload)); return CHIP_NO_ERROR; } } @@ -101,7 +99,7 @@ CHIP_ERROR TimedHandler::OnMessageReceived(Messaging::ExchangeContext * aExchang void TimedHandler::OnExchangeClosing(Messaging::ExchangeContext *) { - InteractionModelEngine::GetInstance()->OnTimedInteractionFailed(this); + mDelegate->OnTimedInteractionFailed(this); } CHIP_ERROR TimedHandler::HandleTimedRequestAction(Messaging::ExchangeContext * aExchangeContext, diff --git a/src/app/TimedHandler.h b/src/app/TimedHandler.h index 47faa9d5940946..e47bfb7b49e1e6 100644 --- a/src/app/TimedHandler.h +++ b/src/app/TimedHandler.h @@ -15,15 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * @file - * Definition of a handler for timed interactions. - * - */ - #pragma once +#include #include #include #include @@ -31,6 +25,11 @@ #include #include +namespace chip { +namespace app { + +class TimedHandler; + /** * A TimedHandler handles a Timed Request action and then waits for a * subsequent Invoke or Write action and hands those on to @@ -43,14 +42,37 @@ * either the exchange is closed or the interaction is handed on to the * InteractionModelEngine. */ +class TimedHandlerDelegate +{ +public: + virtual ~TimedHandlerDelegate() = default; -namespace chip { -namespace app { + /** + * Called when a timed invoke is received. This function takes over all + * handling of the exchange, status reporting, and so forth. + */ + virtual void OnTimedInvoke(TimedHandler * apTimedHandler, Messaging::ExchangeContext * apExchangeContext, + const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) = 0; + + /** + * Called when a timed write is received. This function takes over all + * handling of the exchange, status reporting, and so forth. + */ + virtual void OnTimedWrite(TimedHandler * apTimedHandler, Messaging::ExchangeContext * apExchangeContext, + const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) = 0; + + /** + * Called when a timed interaction has failed (i.e. the exchange it was + * happening on has closed while the exchange delegate was the timed + * handler). + */ + virtual void OnTimedInteractionFailed(TimedHandler * apTimedHandler) = 0; +}; class TimedHandler : public Messaging::ExchangeDelegate { public: - TimedHandler() {} + TimedHandler(TimedHandlerDelegate * delegate) : mDelegate(delegate) {} ~TimedHandler() override {} // ExchangeDelegate implementation. @@ -83,15 +105,31 @@ class TimedHandler : public Messaging::ExchangeDelegate kExpectingFollowingAction, // Expecting write or invoke. }; - // Because we have a vtable pointer and mTimeLimit needs to be 8-byte - // aligned on ARM, putting mState first here means we fit in 16 bytes on - // 32-bit ARM, whereas if we put it second we'd be 24 bytes. - // On platforms where either vtable pointers are 8 bytes or 64-bit ints can - // be 4-byte-aligned the ordering here does not matter. State mState = State::kExpectingTimedAction; + + /// This may be "fake" pointer or a real delegate pointer, depending + /// on CHIP_CONFIG_STATIC_GLOBAL_INTERACTION_MODEL_ENGINE setting. + /// + /// When this is not a real pointer, it checks that the value is always + /// set to the global InteractionModelEngine and the size of this + /// member is 1 byte. + InteractionModelDelegatePointer mDelegate; + // We keep track of the time limit for message reception, in case our // exchange's "response expected" timer gets delayed and does not fire when // the time runs out. + // + // NOTE: mTimeLimit needs to be 8-byte aligned on ARM so we place this last, + // to allow previous values to potentially use remaining packing space. + // Rationale: + // - vtable is 4-byte aligned on 32-bit arm + // - mTimeLimit requires 8-byte aligment + // => As a result we may gain 4 bytes if we place mTimeLimit last. + // Expectation of memory layout: + // - vtable pointer (4 bytes & 4 byte alignment) + // - other members (2 bytes on embedded "global pointer" arm) + // (2 bytes padding for 8-byte alignment) + // - mTimeLimit (8 bytes & 8 byte alignment) System::Clock::Timestamp mTimeLimit; }; diff --git a/src/app/clusters/diagnostic-logs-server/diagnostic-logs-server.cpp b/src/app/clusters/diagnostic-logs-server/diagnostic-logs-server.cpp index 95d9a332819ae3..7b1b036ee4857b 100644 --- a/src/app/clusters/diagnostic-logs-server/diagnostic-logs-server.cpp +++ b/src/app/clusters/diagnostic-logs-server/diagnostic-logs-server.cpp @@ -115,6 +115,9 @@ void DiagnosticLogsServer::HandleLogRequestForResponsePayload(CommandHandler * c Optional timeStamp; Optional timeSinceBoot; + auto size = delegate->GetSizeForIntent(intent); + VerifyOrReturn(size != 0, AddResponse(commandObj, path, StatusEnum::kNoLogs)); + auto err = delegate->GetLogForIntent(intent, logContent, timeStamp, timeSinceBoot); VerifyOrReturn(CHIP_ERROR_NOT_FOUND != err, AddResponse(commandObj, path, StatusEnum::kNoLogs)); VerifyOrReturn(CHIP_NO_ERROR == err, AddResponse(commandObj, path, StatusEnum::kDenied)); @@ -129,6 +132,8 @@ void DiagnosticLogsServer::HandleLogRequestForBdx(CommandHandler * commandObj, c // INVALID_COMMAND. VerifyOrReturn(transferFileDesignator.HasValue(), commandObj->AddStatus(path, Status::InvalidCommand)); + VerifyOrReturn(transferFileDesignator.Value().size() > 0, commandObj->AddStatus(path, Status::ConstraintError)); + VerifyOrReturn(transferFileDesignator.Value().size() <= kMaxFileDesignatorLen, commandObj->AddStatus(path, Status::ConstraintError)); @@ -136,10 +141,13 @@ void DiagnosticLogsServer::HandleLogRequestForBdx(CommandHandler * commandObj, c auto * delegate = GetDiagnosticLogsProviderDelegate(path.mEndpointId); VerifyOrReturn(nullptr != delegate, AddResponse(commandObj, path, StatusEnum::kNoLogs)); + auto size = delegate->GetSizeForIntent(intent); + // In the case where the size is 0 sets the Status field of the RetrieveLogsResponse to NoLogs and do not start a BDX session. + VerifyOrReturn(size != 0, HandleLogRequestForResponsePayload(commandObj, path, intent, StatusEnum::kNoLogs)); + // In the case where the Node is able to fit the entirety of the requested logs within the LogContent field, the Status field of // the RetrieveLogsResponse SHALL be set to Exhausted and a BDX session SHALL NOT be initiated. - VerifyOrReturn(delegate->GetSizeForIntent(intent) > kMaxLogContentSize, - HandleLogRequestForResponsePayload(commandObj, path, intent, StatusEnum::kExhausted)); + VerifyOrReturn(size > kMaxLogContentSize, HandleLogRequestForResponsePayload(commandObj, path, intent, StatusEnum::kExhausted)); // If the RequestedProtocol is set to BDX and either the Node does not support BDX or it is not possible for the Node // to establish a BDX session, then the Node SHALL utilize the LogContent field of the RetrieveLogsResponse command diff --git a/src/app/clusters/messages-server/messages-delegate.h b/src/app/clusters/messages-server/messages-delegate.h index b836a6b34c3ab2..aba771aad23953 100644 --- a/src/app/clusters/messages-server/messages-delegate.h +++ b/src/app/clusters/messages-server/messages-delegate.h @@ -29,19 +29,23 @@ namespace app { namespace Clusters { namespace Messages { -using MessageResponseOption = chip::app::Clusters::Messages::Structs::MessageResponseOptionStruct::Type; +constexpr static size_t kMessageIdLength = 16; +constexpr static size_t kMessageTextLengthMax = 256; +constexpr static size_t kMessageMaxOptionCount = 4; +constexpr static size_t kMessageResponseIdMin = 1; +constexpr static size_t kMessageResponseLabelMaxLength = 32; class Delegate { public: // Commands - virtual void - HandlePresentMessagesRequest(const ByteSpan & messageId, const MessagePriorityEnum & priority, - const chip::BitMask & messageControl, - const DataModel::Nullable & startTime, const DataModel::Nullable & duration, - const CharSpan & messageText, - const chip::Optional> & responses) = 0; - virtual void HandleCancelMessagesRequest(const DataModel::DecodableList & messageIds) = 0; + virtual CHIP_ERROR HandlePresentMessagesRequest( + const ByteSpan & messageId, const MessagePriorityEnum & priority, + const chip::BitMask & messageControl, const DataModel::Nullable & startTime, + const DataModel::Nullable & duration, const CharSpan & messageText, + const chip::Optional> & + responses) = 0; + virtual CHIP_ERROR HandleCancelMessagesRequest(const DataModel::DecodableList & messageIds) = 0; // Attributes virtual CHIP_ERROR HandleGetMessages(app::AttributeValueEncoder & aEncoder) = 0; diff --git a/src/app/clusters/messages-server/messages-server.cpp b/src/app/clusters/messages-server/messages-server.cpp index 33a403e64b3d86..66594ae732a522 100644 --- a/src/app/clusters/messages-server/messages-server.cpp +++ b/src/app/clusters/messages-server/messages-server.cpp @@ -182,9 +182,58 @@ bool emberAfMessagesClusterPresentMessagesRequestCallback( auto & responses = commandData.responses; Delegate * delegate = GetDelegate(endpoint); - VerifyOrExit(isDelegateNull(delegate, endpoint) != true, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(isDelegateNull(delegate, endpoint) != true, status = Status::NotFound); + + VerifyOrExit(messageId.size() == kMessageIdLength, + ChipLogProgress(Zcl, "emberAfMessagesClusterPresentMessagesRequestCallback invalid message id length"); + status = Status::ConstraintError); + + VerifyOrExit(messageText.size() <= kMessageTextLengthMax, + ChipLogProgress(Zcl, "emberAfMessagesClusterPresentMessagesRequestCallback invalid message text length"); + status = Status::ConstraintError); + + if (responses.HasValue()) + { + size_t size = 0; + err = responses.Value().ComputeSize(&size); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogProgress(Zcl, "emberAfMessagesClusterPresentMessagesRequestCallback size check failed"); + status = Status::ConstraintError); + + VerifyOrExit( + delegate->HasFeature(endpoint, Feature::kConfirmationResponse), + ChipLogProgress( + Zcl, "emberAfMessagesClusterPresentMessagesRequestCallback responses sent but response feature not supported"); + status = Status::InvalidCommand); + + VerifyOrExit(size <= kMessageMaxOptionCount, + ChipLogProgress(Zcl, "emberAfMessagesClusterPresentMessagesRequestCallback too many options"); + status = Status::ConstraintError); + + auto iter = responses.Value().begin(); + while (iter.Next()) + { + auto & response = iter.GetValue(); + + // response feature is checked above + VerifyOrExit(response.messageResponseID.HasValue() && response.label.HasValue(), + ChipLogProgress(Zcl, "emberAfMessagesClusterPresentMessagesRequestCallback missing response id or label"); + status = Status::InvalidCommand); + + VerifyOrExit(response.messageResponseID.Value() >= kMessageResponseIdMin, + ChipLogProgress(Zcl, "emberAfMessagesClusterPresentMessagesRequestCallback responseID value check failed"); + status = Status::ConstraintError); - delegate->HandlePresentMessagesRequest(messageId, priority, messageControl, startTime, duration, messageText, responses); + VerifyOrExit(response.label.Value().size() <= kMessageResponseLabelMaxLength, + ChipLogProgress(Zcl, "emberAfMessagesClusterPresentMessagesRequestCallback label length check failed"); + status = Status::ConstraintError); + } + VerifyOrExit(iter.GetStatus() == CHIP_NO_ERROR, + ChipLogProgress(Zcl, "emberAfMessagesClusterPresentMessagesRequestCallback TLV parsing error"); + status = Status::InvalidAction); + } + + err = delegate->HandlePresentMessagesRequest(messageId, priority, messageControl, startTime, duration, messageText, responses); exit: if (err != CHIP_NO_ERROR) @@ -214,7 +263,21 @@ bool emberAfMessagesClusterCancelMessagesRequestCallback( Delegate * delegate = GetDelegate(endpoint); VerifyOrExit(isDelegateNull(delegate, endpoint) != true, err = CHIP_ERROR_INCORRECT_STATE); - delegate->HandleCancelMessagesRequest(messageIds); + { + auto iter = messageIds.begin(); + while (iter.Next()) + { + auto & id = iter.GetValue(); + VerifyOrExit(id.size() >= kMessageIdLength, + ChipLogProgress(Zcl, "emberAfMessagesClusterCancelMessagesRequestCallback message id size check failed"); + status = Status::ConstraintError); + } + VerifyOrExit(iter.GetStatus() == CHIP_NO_ERROR, + ChipLogProgress(Zcl, "emberAfMessagesClusterCancelMessagesRequestCallback TLV parsing error"); + status = Status::InvalidAction); + } + + err = delegate->HandleCancelMessagesRequest(messageIds); exit: if (err != CHIP_NO_ERROR) diff --git a/src/app/clusters/network-commissioning/network-commissioning.cpp b/src/app/clusters/network-commissioning/network-commissioning.cpp index 6776897efce6fb..8212ea9f8008dc 100644 --- a/src/app/clusters/network-commissioning/network-commissioning.cpp +++ b/src/app/clusters/network-commissioning/network-commissioning.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +90,19 @@ static void EnumerateAndRelease(Iterator * iterator, Func func) } } +template +static size_t CountAndRelease(Iterator * iterator) +{ + size_t count = 0; + if (iterator != nullptr) + { + count = iterator->Count(); + iterator->Release(); + } + + return count; +} + BitFlags WiFiFeatures(WiFiDriver * driver) { BitFlags features = Feature::kWiFiNetworkInterface; @@ -101,21 +116,22 @@ BitFlags WiFiFeatures(WiFiDriver * driver) Instance::Instance(EndpointId aEndpointId, WiFiDriver * apDelegate) : CommandHandlerInterface(Optional(aEndpointId), Id), AttributeAccessInterface(Optional(aEndpointId), Id), - mFeatureFlags(WiFiFeatures(apDelegate)), mpWirelessDriver(apDelegate), mpBaseDriver(apDelegate) + mEndpointId(aEndpointId), mFeatureFlags(WiFiFeatures(apDelegate)), mpWirelessDriver(apDelegate), mpBaseDriver(apDelegate) { mpDriver.Set(apDelegate); } Instance::Instance(EndpointId aEndpointId, ThreadDriver * apDelegate) : CommandHandlerInterface(Optional(aEndpointId), Id), AttributeAccessInterface(Optional(aEndpointId), Id), - mFeatureFlags(Feature::kThreadNetworkInterface), mpWirelessDriver(apDelegate), mpBaseDriver(apDelegate) + mEndpointId(aEndpointId), mFeatureFlags(Feature::kThreadNetworkInterface), mpWirelessDriver(apDelegate), + mpBaseDriver(apDelegate) { mpDriver.Set(apDelegate); } Instance::Instance(EndpointId aEndpointId, EthernetDriver * apDelegate) : CommandHandlerInterface(Optional(aEndpointId), Id), AttributeAccessInterface(Optional(aEndpointId), Id), - mFeatureFlags(Feature::kEthernetNetworkInterface), mpWirelessDriver(nullptr), mpBaseDriver(apDelegate) + mEndpointId(aEndpointId), mFeatureFlags(Feature::kEthernetNetworkInterface), mpWirelessDriver(nullptr), mpBaseDriver(apDelegate) {} CHIP_ERROR Instance::Init() @@ -135,6 +151,62 @@ void Instance::Shutdown() mpBaseDriver->Shutdown(); } +#if !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION +void Instance::SendNonConcurrentConnectNetworkResponse() +{ + auto commandHandleRef = std::move(mAsyncCommandHandle); + auto commandHandle = commandHandleRef.Get(); + if (commandHandle == nullptr) + { + return; + } + +#if CONFIG_NETWORK_LAYER_BLE + DeviceLayer::ConnectivityMgr().GetBleLayer()->IndicateBleClosing(); +#endif // CONFIG_NETWORK_LAYER_BLE + ChipLogProgress(NetworkProvisioning, "Non-concurrent mode. Send ConnectNetworkResponse(Success)"); + Commands::ConnectNetworkResponse::Type response; + response.networkingStatus = NetworkCommissioning::Status::kSuccess; + commandHandle->AddResponse(mPath, response); +} +#endif // CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION + +void Instance::SetLastNetworkingStatusValue(Attributes::LastNetworkingStatus::TypeInfo::Type networkingStatusValue) +{ + if (mLastNetworkingStatusValue.Update(networkingStatusValue)) + { + MatterReportingAttributeChangeCallback(mEndpointId, Clusters::NetworkCommissioning::Id, + Attributes::LastNetworkingStatus::TypeInfo::GetAttributeId()); + } +} + +void Instance::SetLastConnectErrorValue(Attributes::LastConnectErrorValue::TypeInfo::Type connectErrorValue) +{ + if (mLastConnectErrorValue.Update(connectErrorValue)) + { + MatterReportingAttributeChangeCallback(mEndpointId, Clusters::NetworkCommissioning::Id, + Attributes::LastConnectErrorValue::TypeInfo::GetAttributeId()); + } +} + +void Instance::SetLastNetworkId(ByteSpan lastNetworkId) +{ + ByteSpan prevLastNetworkId{ mLastNetworkID, mLastNetworkIDLen }; + VerifyOrReturn(lastNetworkId.size() <= kMaxNetworkIDLen); + VerifyOrReturn(!prevLastNetworkId.data_equal(lastNetworkId)); + + memcpy(mLastNetworkID, lastNetworkId.data(), lastNetworkId.size()); + mLastNetworkIDLen = static_cast(lastNetworkId.size()); + MatterReportingAttributeChangeCallback(mEndpointId, Clusters::NetworkCommissioning::Id, + Attributes::LastNetworkID::TypeInfo::GetAttributeId()); +} + +void Instance::ReportNetworksListChanged() const +{ + MatterReportingAttributeChangeCallback(mEndpointId, Clusters::NetworkCommissioning::Id, + Attributes::Networks::TypeInfo::GetAttributeId()); +} + void Instance::InvokeCommand(HandlerContext & ctxt) { if (mAsyncCommandHandle.Get() != nullptr) @@ -177,12 +249,7 @@ void Instance::InvokeCommand(HandlerContext & ctxt) case Commands::ConnectNetwork::Id: { VerifyOrReturn(mFeatureFlags.Has(Feature::kWiFiNetworkInterface) || mFeatureFlags.Has(Feature::kThreadNetworkInterface)); -#if CONFIG_NETWORK_LAYER_BLE && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION - // If commissionee does not support Concurrent Connections, request the BLE to be stopped. - // Start the ConnectNetwork, but this will not complete until the BLE is off. - ChipLogProgress(NetworkProvisioning, "Closing BLE connections due to non-concurrent mode"); - DeviceLayer::DeviceControlServer::DeviceControlSvr().PostCloseAllBLEConnectionsToOperationalNetworkEvent(); -#endif + HandleCommand( ctxt, [this](HandlerContext & ctx, const auto & req) { HandleConnectNetwork(ctx, req); }); return; @@ -363,34 +430,34 @@ CHIP_ERROR Instance::Write(const ConcreteDataAttributePath & aPath, AttributeVal void Instance::OnNetworkingStatusChange(Status aCommissioningError, Optional aNetworkId, Optional aConnectStatus) { - if (aNetworkId.HasValue() && aNetworkId.Value().size() > kMaxNetworkIDLen) - { - ChipLogError(DeviceLayer, "Invalid network id received when calling OnNetworkingStatusChange"); - return; - } - mLastNetworkingStatusValue.SetNonNull(aCommissioningError); if (aNetworkId.HasValue()) { - memcpy(mLastNetworkID, aNetworkId.Value().data(), aNetworkId.Value().size()); - mLastNetworkIDLen = static_cast(aNetworkId.Value().size()); - } - else - { - mLastNetworkIDLen = 0; + if (aNetworkId.Value().size() > kMaxNetworkIDLen) + { + ChipLogError(DeviceLayer, "Overly large network ID received when calling OnNetworkingStatusChange"); + } + else + { + SetLastNetworkId(aNetworkId.Value()); + } } + + SetLastNetworkingStatusValue(MakeNullable(aCommissioningError)); if (aConnectStatus.HasValue()) { - mLastConnectErrorValue.SetNonNull(aConnectStatus.Value()); + SetLastConnectErrorValue(MakeNullable(aConnectStatus.Value())); } else { - mLastConnectErrorValue.SetNull(); + SetLastConnectErrorValue(NullNullable); } } void Instance::HandleScanNetworks(HandlerContext & ctx, const Commands::ScanNetworks::DecodableType & req) { MATTER_TRACE_SCOPE("HandleScanNetwork", "NetworkCommissioning"); + + mScanningWasDirected = false; if (mFeatureFlags.Has(Feature::kWiFiNetworkInterface)) { ByteSpan ssid; @@ -410,9 +477,13 @@ void Instance::HandleScanNetworks(HandlerContext & ctx, const Commands::ScanNetw } if (ssid.size() > DeviceLayer::Internal::kMaxWiFiSSIDLength) { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + // Clients should never use too large a SSID. + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError); + SetLastNetworkingStatusValue(MakeNullable(Status::kUnknownError)); return; } + + mScanningWasDirected = !ssid.empty(); mCurrentOperationBreadcrumb = req.breadcrumb; mAsyncCommandHandle = CommandHandler::Handle(&ctx.mCommandHandler); ctx.mCommandHandler.FlushAcksRightAwayOnSlowCommand(); @@ -420,6 +491,13 @@ void Instance::HandleScanNetworks(HandlerContext & ctx, const Commands::ScanNetw } else if (mFeatureFlags.Has(Feature::kThreadNetworkInterface)) { + // SSID present on Thread violates the `[WI]` conformance. + if (req.ssid.HasValue()) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + return; + } + mCurrentOperationBreadcrumb = req.breadcrumb; mAsyncCommandHandle = CommandHandler::Handle(&ctx.mCommandHandler); ctx.mCommandHandler.FlushAcksRightAwayOnSlowCommand(); @@ -467,7 +545,7 @@ void Instance::HandleAddOrUpdateWiFiNetwork(HandlerContext & ctx, const Commands if (req.ssid.empty() || req.ssid.size() > DeviceLayer::Internal::kMaxWiFiSSIDLength) { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand, "ssid"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError, "ssid"); return; } @@ -508,7 +586,7 @@ void Instance::HandleAddOrUpdateWiFiNetwork(HandlerContext & ctx, const Commands { if (!isxdigit(req.credentials.data()[d])) { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError); return; } } @@ -516,7 +594,7 @@ void Instance::HandleAddOrUpdateWiFiNetwork(HandlerContext & ctx, const Commands else { // Invalid length - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError); return; } @@ -531,6 +609,7 @@ void Instance::HandleAddOrUpdateWiFiNetwork(HandlerContext & ctx, const Commands if (response.networkingStatus == Status::kSuccess) { UpdateBreadcrumb(req.breadcrumb); + ReportNetworksListChanged(); } } @@ -541,7 +620,7 @@ void Instance::HandleAddOrUpdateWiFiNetworkWithPDC(HandlerContext & ctx, // Credentials must be empty when configuring for PDC, it's only present to keep the command shape compatible. if (!req.credentials.empty()) { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand, "credentials"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError, "credentials"); return; } @@ -549,20 +628,20 @@ void Instance::HandleAddOrUpdateWiFiNetworkWithPDC(HandlerContext & ctx, if (networkIdentity.size() > kMaxCHIPCompactNetworkIdentityLength || Credentials::ValidateChipNetworkIdentity(networkIdentity) != CHIP_NO_ERROR) { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand, "networkIdentity"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError, "networkIdentity"); return; } if (req.clientIdentifier.HasValue() && req.clientIdentifier.Value().size() != CertificateKeyId::size()) { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand, "clientIdentifier"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError, "clientIdentifier"); return; } bool provePossession = req.possessionNonce.HasValue(); if (provePossession && req.possessionNonce.Value().size() != kPossessionNonceSize) { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand, "possessionNonce"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError, "possessionNonce"); return; } @@ -624,6 +703,7 @@ void Instance::HandleAddOrUpdateWiFiNetworkWithPDC(HandlerContext & ctx, response.possessionSignature.SetValue(possessionSignature.Value().Span()); } + ReportNetworksListChanged(); UpdateBreadcrumb(req.breadcrumb); } @@ -655,6 +735,7 @@ void Instance::HandleAddOrUpdateThreadNetwork(HandlerContext & ctx, const Comman ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); if (response.networkingStatus == Status::kSuccess) { + ReportNetworksListChanged(); UpdateBreadcrumb(req.breadcrumb); } } @@ -688,7 +769,16 @@ void Instance::HandleRemoveNetwork(HandlerContext & ctx, const Commands::RemoveN ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); if (response.networkingStatus == Status::kSuccess) { + ReportNetworksListChanged(); UpdateBreadcrumb(req.breadcrumb); + + // If no networks are left, clear-out errors; + if (CountAndRelease(mpBaseDriver->GetNetworks()) == 0) + { + SetLastNetworkId(ByteSpan{}); + SetLastConnectErrorValue(NullNullable); + SetLastNetworkingStatusValue(NullNullable); + } } } @@ -697,7 +787,7 @@ void Instance::HandleConnectNetwork(HandlerContext & ctx, const Commands::Connec MATTER_TRACE_SCOPE("HandleConnectNetwork", "NetworkCommissioning"); if (req.networkID.size() > kMaxNetworkIDLen) { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidValue); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError); return; } @@ -708,18 +798,22 @@ void Instance::HandleConnectNetwork(HandlerContext & ctx, const Commands::Connec mAsyncCommandHandle = CommandHandler::Handle(&ctx.mCommandHandler); mCurrentOperationBreadcrumb = req.breadcrumb; - // In Non-concurrent mode postpone the final execution of ConnectNetwork until the operational - // network has been fully brought up and kWiFiDeviceAvailable is delivered. - // mConnectingNetworkIDLen and mConnectingNetworkID contains the received SSID #if CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION mpWirelessDriver->ConnectNetwork(req.networkID, this); +#else + // In Non-concurrent mode postpone the final execution of ConnectNetwork until the operational + // network has been fully brought up and kOperationalNetworkStarted is delivered. + // mConnectingNetworkIDLen and mConnectingNetworkID contain the received SSID + // As per spec, send the ConnectNetworkResponse(Success) prior to releasing the commissioning channel + SendNonConcurrentConnectNetworkResponse(); #endif } void Instance::HandleNonConcurrentConnectNetwork() { ByteSpan nonConcurrentNetworkID = ByteSpan(mConnectingNetworkID, mConnectingNetworkIDLen); - ChipLogProgress(NetworkProvisioning, "HandleNonConcurrentConnectNetwork() SSID=%s", mConnectingNetworkID); + ChipLogProgress(NetworkProvisioning, "Non-concurrent mode, Connect to Network SSID=%.*s", mConnectingNetworkIDLen, + mConnectingNetworkID); mpWirelessDriver->ConnectNetwork(nonConcurrentNetworkID, this); } @@ -734,6 +828,7 @@ void Instance::HandleReorderNetwork(HandlerContext & ctx, const Commands::Reorde ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); if (response.networkingStatus == Status::kSuccess) { + ReportNetworksListChanged(); UpdateBreadcrumb(req.breadcrumb); } } @@ -745,7 +840,7 @@ void Instance::HandleQueryIdentity(HandlerContext & ctx, const Commands::QueryId if (req.keyIdentifier.size() != CertificateKeyId::size()) { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand, "keyIdentifier"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError, "keyIdentifier"); return; } CertificateKeyId keyIdentifier(req.keyIdentifier.data()); @@ -753,7 +848,7 @@ void Instance::HandleQueryIdentity(HandlerContext & ctx, const Commands::QueryId bool provePossession = req.possessionNonce.HasValue(); if (provePossession && req.possessionNonce.Value().size() != kPossessionNonceSize) { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand, "possessionNonce"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ConstraintError, "possessionNonce"); return; } @@ -826,13 +921,19 @@ void Instance::HandleQueryIdentity(HandlerContext & ctx, const Commands::QueryId void Instance::OnResult(Status commissioningError, CharSpan debugText, int32_t interfaceStatus) { auto commandHandleRef = std::move(mAsyncCommandHandle); - auto commandHandle = commandHandleRef.Get(); + + // In Non-concurrent mode the commandHandle will be null here, the ConnectNetworkResponse + // has already been sent and the BLE will have been stopped, however the other functionality + // is still required +#if CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION + auto commandHandle = commandHandleRef.Get(); if (commandHandle == nullptr) { // When the platform shutted down, interaction model engine will invalidate all commandHandle to avoid dangling references. // We may receive the callback after it and should make it noop. return; } +#endif // CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION Commands::ConnectNetworkResponse::Type response; response.networkingStatus = commissioningError; @@ -844,25 +945,26 @@ void Instance::OnResult(Status commissioningError, CharSpan debugText, int32_t i { DeviceLayer::DeviceControlServer::DeviceControlSvr().PostConnectedToOperationalNetworkEvent( ByteSpan(mLastNetworkID, mLastNetworkIDLen)); - mLastConnectErrorValue.SetNull(); + SetLastConnectErrorValue(NullNullable); } else { response.errorValue.SetNonNull(interfaceStatus); - mLastConnectErrorValue.SetNonNull(interfaceStatus); + SetLastConnectErrorValue(MakeNullable(interfaceStatus)); } - mLastNetworkIDLen = mConnectingNetworkIDLen; - memcpy(mLastNetworkID, mConnectingNetworkID, mLastNetworkIDLen); - mLastNetworkingStatusValue.SetNonNull(commissioningError); + SetLastNetworkId(ByteSpan{ mConnectingNetworkID, mConnectingNetworkIDLen }); + SetLastNetworkingStatusValue(MakeNullable(commissioningError)); #if CONFIG_NETWORK_LAYER_BLE && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION ChipLogProgress(NetworkProvisioning, "Non-concurrent mode, ConnectNetworkResponse will NOT be sent"); // Do not send the ConnectNetworkResponse if in non-concurrent mode - // Issue #30576 raised to modify CommandHandler to notify it if no response required + // TODO(#30576) raised to modify CommandHandler to notify it if no response required + // -----> Is this required here: commandHandle->FinishCommand(); #else commandHandle->AddResponse(mPath, response); -#endif +#endif // CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION + if (commissioningError == Status::kSuccess) { CommitSavedBreadcrumb(); @@ -881,9 +983,7 @@ void Instance::OnFinished(Status status, CharSpan debugText, ThreadScanResponseI return; } - mLastNetworkingStatusValue.SetNonNull(status); - mLastConnectErrorValue.SetNull(); - mLastNetworkIDLen = 0; + SetLastNetworkingStatusValue(MakeNullable(status)); TLV::TLVWriter * writer; TLV::TLVType listContainerType; @@ -908,7 +1008,7 @@ void Instance::OnFinished(Status status, CharSpan debugText, ThreadScanResponseI TLV::TLVType::kTLVType_Array, listContainerType)); // If no network was found, we encode an empty list, don't call a zero-sized alloc. - if (networks->Count() > 0) + if ((status == Status::kSuccess) && (networks->Count() > 0)) { VerifyOrExit(scanResponseArray.Alloc(chip::min(networks->Count(), kMaxNetworksInScanResponse)), err = CHIP_ERROR_NO_MEMORY); for (; networks != nullptr && networks->Next(scanResponse);) @@ -997,9 +1097,14 @@ void Instance::OnFinished(Status status, CharSpan debugText, WiFiScanResponseIte return; } - mLastNetworkingStatusValue.SetNonNull(status); - mLastConnectErrorValue.SetNull(); - mLastNetworkIDLen = 0; + // If drivers are failing to respond NetworkNotFound on empty results, force it for them. + bool resultsMissing = !networks || (networks->Count() == 0); + if ((status == Status::kSuccess) && mScanningWasDirected && resultsMissing) + { + status = Status::kNetworkNotFound; + } + + SetLastNetworkingStatusValue(MakeNullable(status)); TLV::TLVWriter * writer; TLV::TLVType listContainerType; @@ -1021,21 +1126,30 @@ void Instance::OnFinished(Status status, CharSpan debugText, WiFiScanResponseIte SuccessOrExit(err = writer->StartContainer(TLV::ContextTag(Commands::ScanNetworksResponse::Fields::kWiFiScanResults), TLV::TLVType::kTLVType_Array, listContainerType)); - for (; networks != nullptr && networks->Next(scanResponse) && networksEncoded < kMaxNetworksInScanResponse; networksEncoded++) + // Only encode results on success, to avoid stale contents on partial failure. + if ((status == Status::kSuccess) && (networks != nullptr)) { - Structs::WiFiInterfaceScanResultStruct::Type result; - result.security = scanResponse.security; - result.ssid = ByteSpan(scanResponse.ssid, scanResponse.ssidLen); - result.bssid = ByteSpan(scanResponse.bssid, sizeof(scanResponse.bssid)); - result.channel = scanResponse.channel; - result.wiFiBand = scanResponse.wiFiBand; - result.rssi = scanResponse.rssi; - SuccessOrExit(err = DataModel::Encode(*writer, TLV::AnonymousTag(), result)); + while (networks->Next(scanResponse)) + { + Structs::WiFiInterfaceScanResultStruct::Type result; + result.security = scanResponse.security; + result.ssid = ByteSpan(scanResponse.ssid, scanResponse.ssidLen); + result.bssid = ByteSpan(scanResponse.bssid, sizeof(scanResponse.bssid)); + result.channel = scanResponse.channel; + result.wiFiBand = scanResponse.wiFiBand; + result.rssi = scanResponse.rssi; + SuccessOrExit(err = DataModel::Encode(*writer, TLV::AnonymousTag(), result)); + + ++networksEncoded; + if (networksEncoded >= kMaxNetworksInScanResponse) + { + break; + } + } } SuccessOrExit(err = writer->EndContainer(listContainerType)); SuccessOrExit(err = commandHandle->FinishCommand()); - exit: if (err != CHIP_NO_ERROR) { @@ -1063,8 +1177,11 @@ void Instance::OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event { this_->OnFailSafeTimerExpired(); } - else if (event->Type == DeviceLayer::DeviceEventType::kWiFiDeviceAvailable) + else if ((event->Type == DeviceLayer::DeviceEventType::kWiFiDeviceAvailable) || + (event->Type == DeviceLayer::DeviceEventType::kOperationalNetworkStarted)) + { + // In Non-Concurrent mode connect the operational channel, as BLE has been stopped this_->HandleNonConcurrentConnectNetwork(); } } @@ -1084,6 +1201,17 @@ void Instance::OnFailSafeTimerExpired() ChipLogDetail(Zcl, "Failsafe timeout, tell platform driver to revert network credentials."); mpWirelessDriver->RevertConfiguration(); mAsyncCommandHandle.Release(); + + // Mark the network list changed since `mpWirelessDriver->RevertConfiguration()` may have updated it. + ReportNetworksListChanged(); + + // If no networks are left, clear-out errors; + if (mpBaseDriver && (CountAndRelease(mpBaseDriver->GetNetworks()) == 0)) + { + SetLastNetworkId(ByteSpan{}); + SetLastConnectErrorValue(NullNullable); + SetLastNetworkingStatusValue(NullNullable); + } } CHIP_ERROR Instance::EnumerateAcceptedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context) diff --git a/src/app/clusters/network-commissioning/network-commissioning.h b/src/app/clusters/network-commissioning/network-commissioning.h index 03fa72f6bfbd26..cd2d5909c566d1 100644 --- a/src/app/clusters/network-commissioning/network-commissioning.h +++ b/src/app/clusters/network-commissioning/network-commissioning.h @@ -77,7 +77,11 @@ class Instance : public CommandHandlerInterface, static void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg); void OnCommissioningComplete(); void OnFailSafeTimerExpired(); +#if !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION + void SendNonConcurrentConnectNetworkResponse(); +#endif + EndpointId mEndpointId = kInvalidEndpointId; const BitFlags mFeatureFlags; DeviceLayer::NetworkCommissioning::Internal::WirelessDriver * const mpWirelessDriver; @@ -93,14 +97,19 @@ class Instance : public CommandHandlerInterface, // Setting these values don't have to care about parallel requests, since we will reject other requests when there is another // request ongoing. // These values can be updated via OnNetworkingStatusChange callback, ScanCallback::OnFinished and ConnectCallback::OnResult. - DataModel::Nullable mLastNetworkingStatusValue; + Attributes::LastNetworkingStatus::TypeInfo::Type mLastNetworkingStatusValue; Attributes::LastConnectErrorValue::TypeInfo::Type mLastConnectErrorValue; uint8_t mConnectingNetworkID[DeviceLayer::NetworkCommissioning::kMaxNetworkIDLen]; uint8_t mConnectingNetworkIDLen = 0; uint8_t mLastNetworkID[DeviceLayer::NetworkCommissioning::kMaxNetworkIDLen]; uint8_t mLastNetworkIDLen = 0; - Optional mCurrentOperationBreadcrumb; + bool mScanningWasDirected = false; + + void SetLastNetworkingStatusValue(Attributes::LastNetworkingStatus::TypeInfo::Type networkingStatusValue); + void SetLastConnectErrorValue(Attributes::LastConnectErrorValue::TypeInfo::Type connectErrorValue); + void SetLastNetworkId(ByteSpan lastNetworkId); + void ReportNetworksListChanged() const; // Commits the breadcrumb value saved in mCurrentOperationBreadcrumb to the breadcrumb attribute in GeneralCommissioning // cluster. Will set mCurrentOperationBreadcrumb to NullOptional. diff --git a/src/app/clusters/power-topology-server/power-topology-server.cpp b/src/app/clusters/power-topology-server/power-topology-server.cpp new file mode 100644 index 00000000000000..3aff74760343bc --- /dev/null +++ b/src/app/clusters/power-topology-server/power-topology-server.cpp @@ -0,0 +1,129 @@ +/* + * + * 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 "power-topology-server.h" + +#include + +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::DataModel; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::PowerTopology; +using namespace chip::app::Clusters::PowerTopology::Attributes; + +using chip::Protocols::InteractionModel::Status; + +namespace chip { +namespace app { +namespace Clusters { +namespace PowerTopology { + +CHIP_ERROR Instance::Init() +{ + VerifyOrReturnError(registerAttributeAccessOverride(this), CHIP_ERROR_INCORRECT_STATE); + return CHIP_NO_ERROR; +} + +void Instance::Shutdown() +{ + unregisterAttributeAccessOverride(this); +} + +bool Instance::HasFeature(Feature aFeature) const +{ + return mFeature.Has(aFeature); +} + +bool Instance::SupportsOptAttr(OptionalAttributes aOptionalAttrs) const +{ + return mOptionalAttrs.Has(aOptionalAttrs); +} + +// AttributeAccessInterface +CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + switch (aPath.mAttributeId) + { + case FeatureMap::Id: + ReturnErrorOnFailure(aEncoder.Encode(mFeature)); + break; + case AvailableEndpoints::Id: + return ReadAvailableEndpoints(aEncoder); + case ActiveEndpoints::Id: + return ReadActiveEndpoints(aEncoder); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR Instance::ReadAvailableEndpoints(AttributeValueEncoder & aEncoder) +{ + if (!SupportsOptAttr(OptionalAttributes::kOptionalAttributeAvailableEndpoints)) + { + return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute); + } + VerifyOrReturnError(HasFeature(Feature::kSetTopology), CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE, + ChipLogError(Zcl, "Power Topology: can not get AvailableEndpoints, feature is not supported")); + + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + for (uint8_t i = 0; true; i++) + { + EndpointId endpointId; + auto err = mDelegate.GetAvailableEndpointAtIndex(i, endpointId); + if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) + { + return CHIP_NO_ERROR; + } + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(encoder.Encode(endpointId)); + } + }); +} + +CHIP_ERROR Instance::ReadActiveEndpoints(AttributeValueEncoder & aEncoder) +{ + if (!SupportsOptAttr(OptionalAttributes::kOptionalAttributeActiveEndpoints)) + { + return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute); + } + VerifyOrReturnError(HasFeature(Feature::kDynamicPowerFlow), CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE, + ChipLogError(Zcl, "Power Topology: can not get ActiveEndpoints, feature is not supported")); + + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + for (uint8_t i = 0; true; i++) + { + EndpointId endpointId; + auto err = mDelegate.GetActiveEndpointAtIndex(i, endpointId); + if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) + { + return CHIP_NO_ERROR; + } + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(encoder.Encode(endpointId)); + } + }); +} + +} // namespace PowerTopology +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/clusters/power-topology-server/power-topology-server.h b/src/app/clusters/power-topology-server/power-topology-server.h new file mode 100644 index 00000000000000..4d34b951ea6650 --- /dev/null +++ b/src/app/clusters/power-topology-server/power-topology-server.h @@ -0,0 +1,91 @@ +/* + * + * 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 + +namespace chip { +namespace app { +namespace Clusters { +namespace PowerTopology { + +class Delegate +{ +public: + virtual ~Delegate() = default; + + /** + * Get the Nth EndpointId in the list of available endpoints. + * @param index The index of the EndpointId to be returned. + * @param endpointId A reference to the EndpointId. + * @return Returns a CHIP_NO_ERROR if there was no error and the EndpointId was returned successfully. + * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index is greater than or equal to the length of the list of available endpoints. + */ + virtual CHIP_ERROR GetAvailableEndpointAtIndex(size_t index, EndpointId & endpointId) = 0; + + /** + * Get the Nth EndpointId in the list of active endpoints. + * @param index The index of the EndpointId to be returned. + * @param endpointId A reference to the EndpointId. + * @return Returns a CHIP_NO_ERROR if there was no error and the EndpointId was returned successfully. + * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index is greater than or equal to the length of the list of active endpoints. + */ + virtual CHIP_ERROR GetActiveEndpointAtIndex(size_t index, EndpointId & endpointId) = 0; +}; + +enum class OptionalAttributes : uint32_t +{ + kOptionalAttributeAvailableEndpoints = 0x1, + kOptionalAttributeActiveEndpoints = 0x2, +}; + +class Instance : public AttributeAccessInterface +{ +public: + Instance(EndpointId aEndpointId, Delegate & aDelegate, BitMask aFeature, + BitMask aOptionalAttributes) : + AttributeAccessInterface(MakeOptional(aEndpointId), Id), + mDelegate(aDelegate), mFeature(aFeature), mOptionalAttrs(aOptionalAttributes) + {} + ~Instance() { Shutdown(); } + + CHIP_ERROR Init(); + void Shutdown(); + + bool HasFeature(Feature aFeature) const; + bool SupportsOptAttr(OptionalAttributes aOptionalAttrs) const; + +private: + Delegate & mDelegate; + BitMask mFeature; + BitMask mOptionalAttrs; + + // AttributeAccessInterface + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + CHIP_ERROR ReadAvailableEndpoints(AttributeValueEncoder & aEncoder); + CHIP_ERROR ReadActiveEndpoints(AttributeValueEncoder & aEncoder); +}; + +} // namespace PowerTopology +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/clusters/scenes-server/scenes-server.cpp b/src/app/clusters/scenes-server/scenes-server.cpp index fc0c656d17fffd..d05d7da84f9a53 100644 --- a/src/app/clusters/scenes-server/scenes-server.cpp +++ b/src/app/clusters/scenes-server/scenes-server.cpp @@ -66,6 +66,10 @@ CHIP_ERROR AddResponseOnError(CommandHandlerInterface::HandlerContext & ctx, Res { resp.status = to_underlying(Protocols::InteractionModel::Status::NotFound); } + else if (CHIP_ERROR_NO_MEMORY == err) + { + resp.status = to_underlying(Protocols::InteractionModel::Status::ResourceExhausted); + } else { resp.status = to_underlying(StatusIB(err).mStatus); @@ -168,7 +172,6 @@ CHIP_ERROR UpdateFabricSceneInfo(EndpointId endpoint, FabricIndex fabric, Option /// @brief Gets the SceneInfoStruct array associated to an endpoint /// @param endpoint target endpoint -/// @param fabric target fabric /// @return Optional with no value not found, Span of SceneInfoStruct Span ScenesServer::FabricSceneInfo::GetFabricSceneInfo(EndpointId endpoint) { @@ -675,13 +678,21 @@ void ScenesServer::InvokeCommand(HandlerContext & ctxt) // AttributeAccessInterface CHIP_ERROR ScenesServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) { + uint16_t endpointTableSize = 0; + ReturnErrorOnFailure(StatusIB(Attributes::SceneTableSize::Get(aPath.mEndpointId, &endpointTableSize)).ToChipError()); + + // Get Scene Table Instance + SceneTable * sceneTable = scenes::GetSceneTableImpl(aPath.mEndpointId, endpointTableSize); + switch (aPath.mAttributeId) { case Attributes::FabricSceneInfo::Id: { - return aEncoder.EncodeList([&](const auto & encoder) -> CHIP_ERROR { + return aEncoder.EncodeList([&, sceneTable](const auto & encoder) -> CHIP_ERROR { Span fabricSceneInfoSpan = mFabricSceneInfo.GetFabricSceneInfo(aPath.mEndpointId); for (auto & info : fabricSceneInfoSpan) { + // Update the SceneInfoStruct's Capacity in case it's capacity was limited by other fabrics + sceneTable->GetRemainingCapacity(info.fabricIndex, info.remainingCapacity); ReturnErrorOnFailure(encoder.Encode(info)); } return CHIP_NO_ERROR; @@ -918,12 +929,10 @@ void ScenesServer::HandleStoreScene(HandlerContext & ctx, const Commands::StoreS CHIP_ERROR err = StoreSceneParse(ctx.mCommandHandler.GetAccessingFabricIndex(), ctx.mRequestPath.mEndpointId, req.groupID, req.sceneID, mGroupProvider); - if (CHIP_NO_ERROR == err) - { - ReturnOnFailure(UpdateLastConfiguredBy(ctx, response)); - } + ReturnOnFailure(AddResponseOnError(ctx, response, err)); - response.status = to_underlying(StatusIB(err).mStatus); + ReturnOnFailure(UpdateLastConfiguredBy(ctx, response)); + response.status = to_underlying(Protocols::InteractionModel::Status::Success); ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); } @@ -1031,6 +1040,13 @@ void ScenesServer::HandleCopyScene(HandlerContext & ctx, const Commands::CopySce ReturnOnFailure(AddResponseOnError(ctx, response, sceneTable->GetRemainingCapacity(ctx.mCommandHandler.GetAccessingFabricIndex(), capacity))); + if (0 == capacity) + { + response.status = to_underlying(Protocols::InteractionModel::Status::ResourceExhausted); + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); + return; + } + // Checks if we copy a single scene or all of them if (req.mode.GetField(app::Clusters::ScenesManagement::CopyModeBitmap::kCopyAllScenes)) { @@ -1043,13 +1059,6 @@ void ScenesServer::HandleCopyScene(HandlerContext & ctx, const Commands::CopySce ctx, response, sceneTable->GetAllSceneIdsInGroup(ctx.mCommandHandler.GetAccessingFabricIndex(), req.groupIdentifierFrom, sceneList))); - if (0 == capacity) - { - response.status = to_underlying(Protocols::InteractionModel::Status::ResourceExhausted); - ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); - return; - } - for (auto & sceneId : sceneList) { SceneTableEntry scene(SceneStorageId(sceneId, req.groupIdentifierFrom)); @@ -1062,13 +1071,13 @@ void ScenesServer::HandleCopyScene(HandlerContext & ctx, const Commands::CopySce ReturnOnFailure(AddResponseOnError( ctx, response, sceneTable->SetSceneTableEntry(ctx.mCommandHandler.GetAccessingFabricIndex(), scene))); - } - // Update SceneInfoStruct Attributes - ReturnOnFailure( - AddResponseOnError(ctx, response, - UpdateFabricSceneInfo(ctx.mRequestPath.mEndpointId, ctx.mCommandHandler.GetAccessingFabricIndex(), - Optional(), Optional(), Optional()))); + // Update SceneInfoStruct Attributes after each insert in case we hit max capacity in the middle of the loop + ReturnOnFailure(AddResponseOnError( + ctx, response, + UpdateFabricSceneInfo(ctx.mRequestPath.mEndpointId, ctx.mCommandHandler.GetAccessingFabricIndex(), + Optional(), Optional(), Optional() /* = sceneValid*/))); + } ReturnOnFailure(UpdateLastConfiguredBy(ctx, response)); diff --git a/src/app/common/BUILD.gn b/src/app/common/BUILD.gn index 193d4c362e537e..1af268a477efaf 100644 --- a/src/app/common/BUILD.gn +++ b/src/app/common/BUILD.gn @@ -27,7 +27,9 @@ static_library("cluster-objects") { ] public_deps = [ + "${chip_root}/src/app:paths", "${chip_root}/src/app/data-model", + "${chip_root}/src/app/util:types", "${chip_root}/src/lib/core", "${chip_root}/src/lib/support", "${chip_root}/src/protocols/interaction_model", diff --git a/src/app/data-model/BUILD.gn b/src/app/data-model/BUILD.gn index 49a49033f0e9f2..9b04882a60ec9c 100644 --- a/src/app/data-model/BUILD.gn +++ b/src/app/data-model/BUILD.gn @@ -37,8 +37,8 @@ source_set("data-model") { # of this, in part due to zap-generated code dependency. # # - app/util/attribute-storage-null-handling.h - # - app/ConcreteAttributePath.h # + "${chip_root}/src/app:paths", "${chip_root}/src/app/common:enums", "${chip_root}/src/lib/core", "${chip_root}/src/lib/support", diff --git a/src/app/data-model/Nullable.h b/src/app/data-model/Nullable.h index d926c5465dacf1..cea3dea5b5361b 100644 --- a/src/app/data-model/Nullable.h +++ b/src/app/data-model/Nullable.h @@ -80,6 +80,19 @@ struct Nullable : protected Optional return true; } + // Set the nullable to the `other` nullable, returning true if something actually changed. + // This can be used to determine if changes occurred on assignment, so that reporting can be triggered + // only on actual changes. + constexpr bool Update(const Nullable & other) + { + bool changed = *this != other; + if (changed) + { + *this = other; + } + return changed; + } + // The only fabric-scoped objects in the spec are commands, events and structs inside lists, and none of those can be nullable. static constexpr bool kIsFabricScoped = false; diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp index 80dec7ed6d3cd1..2dd730c358fe0a 100644 --- a/src/app/reporting/Engine.cpp +++ b/src/app/reporting/Engine.cpp @@ -58,7 +58,7 @@ void Engine::Shutdown() mGlobalDirtySet.ReleaseAll(); } -bool Engine::IsClusterDataVersionMatch(const ObjectList * aDataVersionFilterList, +bool Engine::IsClusterDataVersionMatch(const SingleLinkedListNode * aDataVersionFilterList, const ConcreteReadAttributePath & aPath) { bool existPathMatch = false; diff --git a/src/app/reporting/Engine.h b/src/app/reporting/Engine.h index 47483d9096bfec..fccf9e08ab020f 100644 --- a/src/app/reporting/Engine.h +++ b/src/app/reporting/Engine.h @@ -179,7 +179,7 @@ class Engine // of those will fail to match. This function should return false if either nothing in the list matches the given // endpoint+cluster in the path or there is an entry in the list that matches the endpoint+cluster in the path but does not // match the current data version of that cluster. - bool IsClusterDataVersionMatch(const ObjectList * aDataVersionFilterList, + bool IsClusterDataVersionMatch(const SingleLinkedListNode * aDataVersionFilterList, const ConcreteReadAttributePath & aPath); /** diff --git a/src/app/server/BUILD.gn b/src/app/server/BUILD.gn index 4d63afda77ad42..7c661464bbaea3 100644 --- a/src/app/server/BUILD.gn +++ b/src/app/server/BUILD.gn @@ -30,6 +30,7 @@ static_library("server") { sources = [ "AclStorage.cpp", "AclStorage.h", + "AppDelegate.h", "CommissioningModeProvider.h", "CommissioningWindowManager.cpp", "CommissioningWindowManager.h", diff --git a/src/app/server/CommissioningWindowManager.cpp b/src/app/server/CommissioningWindowManager.cpp index 01509a41a2acd0..c523564382904c 100644 --- a/src/app/server/CommissioningWindowManager.cpp +++ b/src/app/server/CommissioningWindowManager.cpp @@ -89,8 +89,8 @@ void CommissioningWindowManager::OnPlatformEvent(const DeviceLayer::ChipDeviceEv #if CONFIG_NETWORK_LAYER_BLE else if (event->Type == DeviceLayer::DeviceEventType::kCloseAllBleConnections) { - ChipLogProgress(AppServer, "Received kCloseAllBleConnections"); - mServer->GetBleLayerObject()->CloseAllBleConnections(); + ChipLogProgress(AppServer, "Received kCloseAllBleConnections:%d", static_cast(event->Type)); + mServer->GetBleLayerObject()->Shutdown(); } #endif } diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index d8f80e20162fc3..e4ab60329f218e 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -135,6 +135,7 @@ chip_test_suite_using_nltest("tests") { "TestClusterInfo.cpp", "TestCommandInteraction.cpp", "TestCommandPathParams.cpp", + "TestConcreteAttributePath.cpp", "TestDataModelSerialization.cpp", "TestDefaultOTARequestorStorage.cpp", "TestEventLoggingNoUTCTime.cpp", @@ -143,9 +144,11 @@ chip_test_suite_using_nltest("tests") { "TestFabricScopedEventLogging.cpp", "TestInteractionModelEngine.cpp", "TestMessageDef.cpp", + "TestNullable.cpp", "TestNumericAttributeTraits.cpp", "TestOperationalStateClusterObjects.cpp", "TestPendingNotificationMap.cpp", + "TestPendingResponseTrackerImpl.cpp", "TestPowerSourceCluster.cpp", "TestReadInteraction.cpp", "TestReportingEngine.cpp", diff --git a/src/app/tests/TestAttributePathExpandIterator.cpp b/src/app/tests/TestAttributePathExpandIterator.cpp index d4da4fc95a2b8c..e5505320193b81 100644 --- a/src/app/tests/TestAttributePathExpandIterator.cpp +++ b/src/app/tests/TestAttributePathExpandIterator.cpp @@ -20,12 +20,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include @@ -41,7 +41,7 @@ using P = app::ConcreteAttributePath; void TestAllWildcard(nlTestSuite * apSuite, void * apContext) { - app::ObjectList clusInfo; + SingleLinkedListNode clusInfo; app::ConcreteAttributePath path; P paths[] = { @@ -144,7 +144,7 @@ void TestAllWildcard(nlTestSuite * apSuite, void * apContext) void TestWildcardEndpoint(nlTestSuite * apSuite, void * apContext) { - app::ObjectList clusInfo; + SingleLinkedListNode clusInfo; clusInfo.mValue.mClusterId = Test::MockClusterId(3); clusInfo.mValue.mAttributeId = Test::MockAttributeId(3); @@ -167,7 +167,7 @@ void TestWildcardEndpoint(nlTestSuite * apSuite, void * apContext) void TestWildcardCluster(nlTestSuite * apSuite, void * apContext) { - app::ObjectList clusInfo; + SingleLinkedListNode clusInfo; clusInfo.mValue.mEndpointId = Test::kMockEndpoint3; clusInfo.mValue.mAttributeId = app::Clusters::Globals::Attributes::ClusterRevision::Id; @@ -193,7 +193,7 @@ void TestWildcardCluster(nlTestSuite * apSuite, void * apContext) void TestWildcardClusterGlobalAttributeNotInMetadata(nlTestSuite * apSuite, void * apContext) { - app::ObjectList clusInfo; + SingleLinkedListNode clusInfo; clusInfo.mValue.mEndpointId = Test::kMockEndpoint3; clusInfo.mValue.mAttributeId = app::Clusters::Globals::Attributes::AttributeList::Id; @@ -219,7 +219,7 @@ void TestWildcardClusterGlobalAttributeNotInMetadata(nlTestSuite * apSuite, void void TestWildcardAttribute(nlTestSuite * apSuite, void * apContext) { - app::ObjectList clusInfo; + SingleLinkedListNode clusInfo; clusInfo.mValue.mEndpointId = Test::kMockEndpoint2; clusInfo.mValue.mClusterId = Test::MockClusterId(3); @@ -252,7 +252,7 @@ void TestWildcardAttribute(nlTestSuite * apSuite, void * apContext) void TestNoWildcard(nlTestSuite * apSuite, void * apContext) { - app::ObjectList clusInfo; + SingleLinkedListNode clusInfo; clusInfo.mValue.mEndpointId = Test::kMockEndpoint2; clusInfo.mValue.mClusterId = Test::MockClusterId(3); clusInfo.mValue.mAttributeId = Test::MockAttributeId(3); @@ -277,21 +277,21 @@ void TestNoWildcard(nlTestSuite * apSuite, void * apContext) void TestMultipleClusInfo(nlTestSuite * apSuite, void * apContext) { - app::ObjectList clusInfo1; + SingleLinkedListNode clusInfo1; - app::ObjectList clusInfo2; + SingleLinkedListNode clusInfo2; clusInfo2.mValue.mClusterId = Test::MockClusterId(3); clusInfo2.mValue.mAttributeId = Test::MockAttributeId(3); - app::ObjectList clusInfo3; + SingleLinkedListNode clusInfo3; clusInfo3.mValue.mEndpointId = Test::kMockEndpoint3; clusInfo3.mValue.mAttributeId = app::Clusters::Globals::Attributes::ClusterRevision::Id; - app::ObjectList clusInfo4; + SingleLinkedListNode clusInfo4; clusInfo4.mValue.mEndpointId = Test::kMockEndpoint2; clusInfo4.mValue.mClusterId = Test::MockClusterId(3); - app::ObjectList clusInfo5; + SingleLinkedListNode clusInfo5; clusInfo5.mValue.mEndpointId = Test::kMockEndpoint2; clusInfo5.mValue.mClusterId = Test::MockClusterId(3); clusInfo5.mValue.mAttributeId = Test::MockAttributeId(3); diff --git a/src/app/tests/TestCommandInteraction.cpp b/src/app/tests/TestCommandInteraction.cpp index d67b389b1df6aa..6aab66ec8549c3 100644 --- a/src/app/tests/TestCommandInteraction.cpp +++ b/src/app/tests/TestCommandInteraction.cpp @@ -85,7 +85,8 @@ constexpr CommandId kTestCommandIdCommandSpecificResponse = 6; constexpr CommandId kTestCommandIdFillResponseMessage = 7; constexpr CommandId kTestNonExistCommandId = 0; -const app::CommandHandler::TestOnlyMarker kThisIsForTestOnly; +const app::CommandHandler::TestOnlyMarker kCommandHandlerTestOnlyMarker; +const app::CommandSender::TestOnlyMarker kCommandSenderTestOnlyMarker; } // namespace namespace app { @@ -328,7 +329,8 @@ class TestCommandInteraction static void TestCommandSenderLegacyCallbackUnsupportedCommand(nlTestSuite * apSuite, void * apContext); static void TestCommandSenderExtendableCallbackUnsupportedCommand(nlTestSuite * apSuite, void * apContext); static void TestCommandSenderLegacyCallbackBuildingBatchCommandFails(nlTestSuite * apSuite, void * apContext); - static void TestCommandSenderExtendableCallbackBuildingBatchCommandFails(nlTestSuite * apSuite, void * apContext); + static void TestCommandSenderExtendableCallbackBuildingBatchDuplicateCommandRefFails(nlTestSuite * apSuite, void * apContext); + static void TestCommandSenderExtendableCallbackBuildingBatchCommandSuccess(nlTestSuite * apSuite, void * apContext); static void TestCommandSenderCommandSuccessResponseFlow(nlTestSuite * apSuite, void * apContext); static void TestCommandSenderCommandAsyncSuccessResponseFlow(nlTestSuite * apSuite, void * apContext); static void TestCommandSenderCommandFailureResponseFlow(nlTestSuite * apSuite, void * apContext); @@ -1271,8 +1273,12 @@ void TestCommandInteraction::TestCommandSenderLegacyCallbackBuildingBatchCommand prepareCommandParams.SetStartDataStruct(true).SetCommandRef(0); finishCommandParams.SetEndDataStruct(true).SetCommandRef(0); - commandSender.mBatchCommandsEnabled = true; - commandSender.mRemoteMaxPathsPerInvoke = 2; + CommandSender::ConfigParameters config; + config.SetRemoteMaxPathsPerInvoke(2); + err = commandSender.SetCommandSenderConfig(config); + NL_TEST_ASSERT(apSuite, err == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + // Even though we got an error saying invalid argument we are going to attempt + // to add two commands. auto commandPathParams = MakeTestCommandPath(); err = commandSender.PrepareCommand(commandPathParams, prepareCommandParams); @@ -1291,20 +1297,64 @@ void TestCommandInteraction::TestCommandSenderLegacyCallbackBuildingBatchCommand NL_TEST_ASSERT(apSuite, ctx.GetExchangeManager().GetNumActiveExchanges() == 0); } -void TestCommandInteraction::TestCommandSenderExtendableCallbackBuildingBatchCommandFails(nlTestSuite * apSuite, void * apContext) +void TestCommandInteraction::TestCommandSenderExtendableCallbackBuildingBatchDuplicateCommandRefFails(nlTestSuite * apSuite, + void * apContext) { TestContext & ctx = *static_cast(apContext); CHIP_ERROR err = CHIP_NO_ERROR; mockCommandSenderExtendedDelegate.ResetCounter(); - app::CommandSender commandSender(&mockCommandSenderExtendedDelegate, &ctx.GetExchangeManager()); + PendingResponseTrackerImpl pendingResponseTracker; + app::CommandSender commandSender(kCommandSenderTestOnlyMarker, &mockCommandSenderExtendedDelegate, &ctx.GetExchangeManager(), + &pendingResponseTracker); app::CommandSender::PrepareCommandParameters prepareCommandParams; app::CommandSender::FinishCommandParameters finishCommandParams; + + CommandSender::ConfigParameters config; + config.SetRemoteMaxPathsPerInvoke(2); + err = commandSender.SetCommandSenderConfig(config); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + prepareCommandParams.SetStartDataStruct(true).SetCommandRef(0); finishCommandParams.SetEndDataStruct(true).SetCommandRef(0); + auto commandPathParams = MakeTestCommandPath(); + err = commandSender.PrepareCommand(commandPathParams, prepareCommandParams); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + chip::TLV::TLVWriter * writer = commandSender.GetCommandDataIBTLVWriter(); + err = writer->PutBoolean(chip::TLV::ContextTag(1), true); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + err = commandSender.FinishCommand(finishCommandParams); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + // Preparing second command. + prepareCommandParams.SetCommandRef(0); + err = commandSender.PrepareCommand(commandPathParams, prepareCommandParams); + NL_TEST_ASSERT(apSuite, err == CHIP_ERROR_INVALID_ARGUMENT); - commandSender.mBatchCommandsEnabled = true; - commandSender.mRemoteMaxPathsPerInvoke = 2; + NL_TEST_ASSERT(apSuite, GetNumActiveHandlerObjects() == 0); + NL_TEST_ASSERT(apSuite, ctx.GetExchangeManager().GetNumActiveExchanges() == 0); +} +void TestCommandInteraction::TestCommandSenderExtendableCallbackBuildingBatchCommandSuccess(nlTestSuite * apSuite, void * apContext) +{ + TestContext & ctx = *static_cast(apContext); + CHIP_ERROR err = CHIP_NO_ERROR; + mockCommandSenderExtendedDelegate.ResetCounter(); + PendingResponseTrackerImpl pendingResponseTracker; + app::CommandSender commandSender(kCommandSenderTestOnlyMarker, &mockCommandSenderExtendedDelegate, &ctx.GetExchangeManager(), + &pendingResponseTracker); + app::CommandSender::PrepareCommandParameters prepareCommandParams; + app::CommandSender::FinishCommandParameters finishCommandParams; + + CommandSender::ConfigParameters config; + config.SetRemoteMaxPathsPerInvoke(2); + err = commandSender.SetCommandSenderConfig(config); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + // The specific values chosen here are arbitrary. This test primarily verifies that we can + // use a larger command reference value followed by a smaller one for subsequent command. + uint16_t firstCommandRef = 40; + uint16_t secondCommandRef = 2; + prepareCommandParams.SetStartDataStruct(true).SetCommandRef(firstCommandRef); + finishCommandParams.SetEndDataStruct(true).SetCommandRef(firstCommandRef); auto commandPathParams = MakeTestCommandPath(); err = commandSender.PrepareCommand(commandPathParams, prepareCommandParams); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1314,8 +1364,8 @@ void TestCommandInteraction::TestCommandSenderExtendableCallbackBuildingBatchCom err = commandSender.FinishCommand(finishCommandParams); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); // Preparing second command. - prepareCommandParams.SetCommandRef(1); - finishCommandParams.SetCommandRef(1); + prepareCommandParams.SetCommandRef(secondCommandRef); + finishCommandParams.SetCommandRef(secondCommandRef); err = commandSender.PrepareCommand(commandPathParams, prepareCommandParams); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); writer = commandSender.GetCommandDataIBTLVWriter(); @@ -1650,7 +1700,7 @@ void TestCommandInteraction::TestCommandHandlerRejectMultipleCommandsWhenHandler } BasicCommandPathRegistry<4> mBasicCommandPathRegistry; - CommandHandler commandHandler(kThisIsForTestOnly, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); + CommandHandler commandHandler(kCommandHandlerTestOnlyMarker, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); TestExchangeDelegate delegate; auto exchange = ctx.NewExchangeToAlice(&delegate, false); commandHandler.mResponseSender.SetExchangeContext(exchange); @@ -1724,7 +1774,7 @@ void TestCommandInteraction::TestCommandHandlerAcceptMultipleCommands(nlTestSuit } BasicCommandPathRegistry<4> mBasicCommandPathRegistry; - CommandHandler commandHandler(kThisIsForTestOnly, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); + CommandHandler commandHandler(kCommandHandlerTestOnlyMarker, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); TestExchangeDelegate delegate; auto exchange = ctx.NewExchangeToAlice(&delegate, false); commandHandler.mResponseSender.SetExchangeContext(exchange); @@ -1756,7 +1806,7 @@ void TestCommandInteraction::TestCommandHandler_FillUpInvokeResponseMessageWhere nlTestSuite * apSuite, void * apContext) { BasicCommandPathRegistry<4> mBasicCommandPathRegistry; - CommandHandler commandHandler(kThisIsForTestOnly, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); + CommandHandler commandHandler(kCommandHandlerTestOnlyMarker, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); commandHandler.mReserveSpaceForMoreChunkMessages = true; ConcreteCommandPath requestCommandPath1 = { kTestEndpointId, kTestClusterId, kTestCommandIdFillResponseMessage }; ConcreteCommandPath requestCommandPath2 = { kTestEndpointId, kTestClusterId, kTestCommandIdCommandSpecificResponse }; @@ -1782,7 +1832,7 @@ void TestCommandInteraction::TestCommandHandler_FillUpInvokeResponseMessageWhere nlTestSuite * apSuite, void * apContext) { BasicCommandPathRegistry<4> mBasicCommandPathRegistry; - CommandHandler commandHandler(kThisIsForTestOnly, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); + CommandHandler commandHandler(kCommandHandlerTestOnlyMarker, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); commandHandler.mReserveSpaceForMoreChunkMessages = true; ConcreteCommandPath requestCommandPath1 = { kTestEndpointId, kTestClusterId, kTestCommandIdFillResponseMessage }; ConcreteCommandPath requestCommandPath2 = { kTestEndpointId, kTestClusterId, kTestCommandIdCommandSpecificResponse }; @@ -1808,7 +1858,7 @@ void TestCommandInteraction::TestCommandHandler_FillUpInvokeResponseMessageWhere void * apContext) { BasicCommandPathRegistry<4> mBasicCommandPathRegistry; - CommandHandler commandHandler(kThisIsForTestOnly, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); + CommandHandler commandHandler(kCommandHandlerTestOnlyMarker, &mockCommandHandlerDelegate, &mBasicCommandPathRegistry); commandHandler.mReserveSpaceForMoreChunkMessages = true; ConcreteCommandPath requestCommandPath1 = { kTestEndpointId, kTestClusterId, kTestCommandIdFillResponseMessage }; ConcreteCommandPath requestCommandPath2 = { kTestEndpointId, kTestClusterId, kTestCommandIdCommandSpecificResponse }; @@ -1902,7 +1952,8 @@ const nlTest sTests[] = NL_TEST_DEF("TestCommandSenderLegacyCallbackUnsupportedCommand", chip::app::TestCommandInteraction::TestCommandSenderLegacyCallbackUnsupportedCommand), NL_TEST_DEF("TestCommandSenderExtendableCallbackUnsupportedCommand", chip::app::TestCommandInteraction::TestCommandSenderExtendableCallbackUnsupportedCommand), NL_TEST_DEF("TestCommandSenderLegacyCallbackBuildingBatchCommandFails", chip::app::TestCommandInteraction::TestCommandSenderLegacyCallbackBuildingBatchCommandFails), - NL_TEST_DEF("TestCommandSenderExtendableCallbackBuildingBatchCommandFails", chip::app::TestCommandInteraction::TestCommandSenderExtendableCallbackBuildingBatchCommandFails), + NL_TEST_DEF("TestCommandSenderExtendableCallbackBuildingBatchDuplicateCommandRefFails", chip::app::TestCommandInteraction::TestCommandSenderExtendableCallbackBuildingBatchDuplicateCommandRefFails), + NL_TEST_DEF("TestCommandSenderExtendableCallbackBuildingBatchCommandSuccess", chip::app::TestCommandInteraction::TestCommandSenderExtendableCallbackBuildingBatchCommandSuccess), NL_TEST_DEF("TestCommandSenderCommandSuccessResponseFlow", chip::app::TestCommandInteraction::TestCommandSenderCommandSuccessResponseFlow), NL_TEST_DEF("TestCommandSenderCommandAsyncSuccessResponseFlow", chip::app::TestCommandInteraction::TestCommandSenderCommandAsyncSuccessResponseFlow), NL_TEST_DEF("TestCommandSenderCommandSpecificResponseFlow", chip::app::TestCommandInteraction::TestCommandSenderCommandSpecificResponseFlow), diff --git a/src/app/tests/TestConcreteAttributePath.cpp b/src/app/tests/TestConcreteAttributePath.cpp new file mode 100644 index 00000000000000..6e3451be26a78f --- /dev/null +++ b/src/app/tests/TestConcreteAttributePath.cpp @@ -0,0 +1,94 @@ +/* + * + * 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 + +using namespace chip; +using namespace chip::app; + +namespace { + +void TestConcreteAttributePathEqualityDefaultConstructor(nlTestSuite * aSuite, void * aContext) +{ + ConcreteAttributePath path_one; + ConcreteAttributePath path_two; + NL_TEST_ASSERT(aSuite, path_one == path_two); +} + +void TestConcreteAttributePathEquality(nlTestSuite * aSuite, void * aContext) +{ + ConcreteAttributePath path_one(/*aEndpointId=*/1, /*aClusterId=*/2, /*aAttributeId=*/3); + ConcreteAttributePath path_two(/*aEndpointId=*/1, /*aClusterId=*/2, /*aAttributeId=*/3); + NL_TEST_ASSERT(aSuite, path_one == path_two); +} + +void TestConcreteAttributePathInequalityDifferentAttributeId(nlTestSuite * aSuite, void * aContext) +{ + ConcreteAttributePath path_one(/*aEndpointId=*/1, /*aClusterId=*/2, /*aAttributeId=*/3); + ConcreteAttributePath path_two(/*aEndpointId=*/1, /*aClusterId=*/2, /*aAttributeId=*/4); + NL_TEST_ASSERT(aSuite, path_one != path_two); +} + +void TestConcreteDataAttributePathMatchesConcreteAttributePathEquality(nlTestSuite * aSuite, void * aContext) +{ + ConcreteAttributePath path(/*aEndpointId=*/1, /*aClusterId=*/2, /*aAttributeId=*/3); + ConcreteDataAttributePath data_path(/*aEndpointId=*/1, /*aClusterId=*/2, /*aAttributeId=*/3); + ConcreteDataAttributePath data_path_with_version(/*aEndpointId=*/1, /*aClusterId=*/2, /*aAttributeId=*/3, + /*aDataVersion=*/MakeOptional(4U)); + ConcreteDataAttributePath data_path_with_list(/*aEndpointId=*/1, /*aClusterId=*/2, /*aAttributeId=*/3, + /*aListOp=*/ConcreteDataAttributePath::ListOperation::ReplaceAll, + /*aListIndex=*/5U); + + NL_TEST_ASSERT(aSuite, data_path.MatchesConcreteAttributePath(path)); + NL_TEST_ASSERT(aSuite, data_path_with_version.MatchesConcreteAttributePath(path)); + NL_TEST_ASSERT(aSuite, data_path_with_list.MatchesConcreteAttributePath(path)); +} + +void TestConcreteDataAttributePathMatchesConcreteAttributePathInequality(nlTestSuite * aSuite, void * aContext) +{ + ConcreteAttributePath path(/*aEndpointId=*/1, /*aClusterId=*/2, /*aAttributeId=*/3); + ConcreteDataAttributePath data_path(/*aEndpointId=*/1, /*aClusterId=*/2, /*aAttributeId=*/4); + + NL_TEST_ASSERT(aSuite, !data_path.MatchesConcreteAttributePath(path)); +} + +const nlTest sTests[] = { + NL_TEST_DEF("TestConcreteAttributePathEqualityDefaultConstructor", TestConcreteAttributePathEqualityDefaultConstructor), + NL_TEST_DEF("TestConcreteAttributePathEquality", TestConcreteAttributePathEquality), + NL_TEST_DEF("TestConcreteAttributePathInequalityDifferentAttributeId", TestConcreteAttributePathInequalityDifferentAttributeId), + NL_TEST_DEF("TestConcreteDataAttributePathMatchesConcreteAttributePathEquality", + TestConcreteDataAttributePathMatchesConcreteAttributePathEquality), + NL_TEST_DEF("TestConcreteDataAttributePathMatchesConcreteAttributePathInequality", + TestConcreteDataAttributePathMatchesConcreteAttributePathInequality), + NL_TEST_SENTINEL() +}; + +} // anonymous namespace + +int TestConcreteAttributePath() +{ + nlTestSuite theSuite = { "ConcreteAttributePath", &sTests[0], nullptr, nullptr }; + + nlTestRunner(&theSuite, nullptr); + + return (nlTestRunnerStats(&theSuite)); +} + +CHIP_REGISTER_TEST_SUITE(TestConcreteAttributePath) diff --git a/src/app/tests/TestEventLogging.cpp b/src/app/tests/TestEventLogging.cpp index 08f950517acfde..baf43d6b398707 100644 --- a/src/app/tests/TestEventLogging.cpp +++ b/src/app/tests/TestEventLogging.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -37,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -133,7 +133,7 @@ static void CheckLogState(nlTestSuite * apSuite, chip::app::EventManagement & aL } static void CheckLogReadOut(nlTestSuite * apSuite, chip::app::EventManagement & alogMgmt, chip::EventNumber startingEventNumber, - size_t expectedNumEvents, chip::app::ObjectList * clusterInfo) + size_t expectedNumEvents, chip::SingleLinkedListNode * clusterInfo) { CHIP_ERROR err; chip::TLV::TLVReader reader; @@ -236,7 +236,7 @@ static void CheckLogEventWithEvictToNextBuffer(nlTestSuite * apSuite, void * apC NL_TEST_ASSERT(apSuite, (eid4 + 1) == eid5); NL_TEST_ASSERT(apSuite, (eid5 + 1) == eid6); - chip::app::ObjectList paths[2]; + chip::SingleLinkedListNode paths[2]; paths[0].mValue.mEndpointId = kTestEndpointId1; paths[0].mValue.mClusterId = kLivenessClusterId; @@ -257,7 +257,7 @@ static void CheckLogEventWithEvictToNextBuffer(nlTestSuite * apSuite, void * apC // interested paths are path list, expect to retrieve all events for those interested paths CheckLogReadOut(apSuite, logMgmt, 0, 6, paths); - chip::app::ObjectList pathsWithWildcard[2]; + chip::SingleLinkedListNode pathsWithWildcard[2]; paths[0].mValue.mEndpointId = kTestEndpointId1; paths[0].mValue.mClusterId = kLivenessClusterId; diff --git a/src/app/tests/TestEventLoggingNoUTCTime.cpp b/src/app/tests/TestEventLoggingNoUTCTime.cpp index 43df98a790e2ba..8360f9a0813e98 100644 --- a/src/app/tests/TestEventLoggingNoUTCTime.cpp +++ b/src/app/tests/TestEventLoggingNoUTCTime.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -177,7 +177,7 @@ static void CheckLogState(nlTestSuite * apSuite, chip::app::EventManagement & aL } static void CheckLogReadOut(nlTestSuite * apSuite, chip::app::EventManagement & alogMgmt, chip::EventNumber startingEventNumber, - size_t expectedNumEvents, chip::app::ObjectList * clusterInfo) + size_t expectedNumEvents, chip::SingleLinkedListNode * clusterInfo) { CHIP_ERROR err; chip::TLV::TLVReader reader; @@ -279,7 +279,7 @@ static void CheckLogEventWithEvictToNextBuffer(nlTestSuite * apSuite, void * apC NL_TEST_ASSERT(apSuite, (eid4 + 1) == eid5); NL_TEST_ASSERT(apSuite, (eid5 + 1) == eid6); - chip::app::ObjectList paths[2]; + chip::SingleLinkedListNode paths[2]; paths[0].mValue.mEndpointId = kTestEndpointId1; paths[0].mValue.mClusterId = kLivenessClusterId; @@ -300,7 +300,7 @@ static void CheckLogEventWithEvictToNextBuffer(nlTestSuite * apSuite, void * apC // interested paths are path list, expect to retrieve all events for those interested paths CheckLogReadOut(apSuite, logMgmt, 0, 6, paths); - chip::app::ObjectList pathsWithWildcard[2]; + chip::SingleLinkedListNode pathsWithWildcard[2]; paths[0].mValue.mEndpointId = kTestEndpointId1; paths[0].mValue.mClusterId = kLivenessClusterId; diff --git a/src/app/tests/TestFabricScopedEventLogging.cpp b/src/app/tests/TestFabricScopedEventLogging.cpp index f55ac63b687491..d016ad5183e1c0 100644 --- a/src/app/tests/TestFabricScopedEventLogging.cpp +++ b/src/app/tests/TestFabricScopedEventLogging.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -37,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -137,7 +137,7 @@ static void CheckLogState(nlTestSuite * apSuite, chip::app::EventManagement & aL } static void CheckLogReadOut(nlTestSuite * apSuite, chip::app::EventManagement & alogMgmt, chip::EventNumber startingEventNumber, - size_t expectedNumEvents, chip::app::ObjectList * clusterInfo, + size_t expectedNumEvents, chip::SingleLinkedListNode * clusterInfo, const chip::Access::SubjectDescriptor & aSubjectDescriptor) { CHIP_ERROR err; @@ -220,7 +220,7 @@ static void CheckLogEventWithEvictToNextBuffer(nlTestSuite * apSuite, void * apC NL_TEST_ASSERT(apSuite, (eid2 + 1) == eid3); NL_TEST_ASSERT(apSuite, (eid3 + 1) == eid4); - chip::app::ObjectList paths[2]; + chip::SingleLinkedListNode paths[2]; paths[0].mValue.mEndpointId = kTestEndpointId1; paths[0].mValue.mClusterId = kLivenessClusterId; @@ -247,7 +247,7 @@ static void CheckLogEventWithEvictToNextBuffer(nlTestSuite * apSuite, void * apC CheckLogReadOut(apSuite, logMgmt, 0, 1, paths, descriptor); // Fabric event + wildcard test, only have one fabric-scoped event with fabric 2 - chip::app::ObjectList pathsWithWildcard[2]; + chip::SingleLinkedListNode pathsWithWildcard[2]; paths[0].mValue.mEndpointId = kTestEndpointId1; paths[0].mValue.mClusterId = kLivenessClusterId; diff --git a/src/app/tests/TestInteractionModelEngine.cpp b/src/app/tests/TestInteractionModelEngine.cpp index f4450635ac0b8f..fcdc7d53e1594f 100644 --- a/src/app/tests/TestInteractionModelEngine.cpp +++ b/src/app/tests/TestInteractionModelEngine.cpp @@ -52,13 +52,13 @@ class TestInteractionModelEngine #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS && CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION static void TestSubscriptionResumptionTimer(nlTestSuite * apSuite, void * apContext); #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS && CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION - static int GetAttributePathListLength(ObjectList * apattributePathParamsList); + static int GetAttributePathListLength(SingleLinkedListNode * apattributePathParamsList); }; -int TestInteractionModelEngine::GetAttributePathListLength(ObjectList * apAttributePathParamsList) +int TestInteractionModelEngine::GetAttributePathListLength(SingleLinkedListNode * apAttributePathParamsList) { - int length = 0; - ObjectList * runner = apAttributePathParamsList; + int length = 0; + SingleLinkedListNode * runner = apAttributePathParamsList; while (runner != nullptr) { runner = runner->mpNext; @@ -74,7 +74,7 @@ void TestInteractionModelEngine::TestAttributePathParamsPushRelease(nlTestSuite err = InteractionModelEngine::GetInstance()->Init(&ctx.GetExchangeManager(), &ctx.GetFabricTable(), app::reporting::GetDefaultReportScheduler()); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - ObjectList * attributePathParamsList = nullptr; + SingleLinkedListNode * attributePathParamsList = nullptr; AttributePathParams attributePathParams1; AttributePathParams attributePathParams2; AttributePathParams attributePathParams3; @@ -112,7 +112,7 @@ void TestInteractionModelEngine::TestRemoveDuplicateConcreteAttribute(nlTestSuit err = InteractionModelEngine::GetInstance()->Init(&ctx.GetExchangeManager(), &ctx.GetFabricTable(), app::reporting::GetDefaultReportScheduler()); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - ObjectList * attributePathParamsList = nullptr; + SingleLinkedListNode * attributePathParamsList = nullptr; AttributePathParams attributePathParams1; AttributePathParams attributePathParams2; AttributePathParams attributePathParams3; diff --git a/src/app/tests/TestNullable.cpp b/src/app/tests/TestNullable.cpp new file mode 100644 index 00000000000000..c1290c1a0cef66 --- /dev/null +++ b/src/app/tests/TestNullable.cpp @@ -0,0 +1,303 @@ +/* + * + * 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 +#include +#include + +using namespace chip; +using namespace chip::app::DataModel; + +namespace { + +// Counts calls to constructor and destructor, to determine if the right +// semantics applied in cases where destruction is expected. +struct CtorDtorCounter +{ + CtorDtorCounter(int i) : m(i) { ++created; } + ~CtorDtorCounter() { ++destroyed; } + + CtorDtorCounter(const CtorDtorCounter & o) : m(o.m) { ++created; } + CtorDtorCounter & operator=(const CtorDtorCounter &) = default; + + CtorDtorCounter(CtorDtorCounter && o) : m(o.m) { ++created; } + CtorDtorCounter & operator=(CtorDtorCounter &&) = default; + + bool operator==(const CtorDtorCounter & o) const { return m == o.m; } + + int m; + + static void ResetCounter() + { + created = 0; + destroyed = 0; + } + + static int created; + static int destroyed; +}; + +struct MovableCtorDtorCounter : public CtorDtorCounter +{ +public: + MovableCtorDtorCounter(int i) : CtorDtorCounter(i) {} + + MovableCtorDtorCounter(const MovableCtorDtorCounter & o) = delete; + MovableCtorDtorCounter & operator=(const MovableCtorDtorCounter &) = delete; + + MovableCtorDtorCounter(MovableCtorDtorCounter && o) = default; + MovableCtorDtorCounter & operator=(MovableCtorDtorCounter &&) = default; +}; + +int CtorDtorCounter::created = 0; +int CtorDtorCounter::destroyed = 0; + +} // namespace + +static void TestBasic(nlTestSuite * inSuite, void * inContext) +{ + // Set up our test CtorDtorCounter objects, which will mess with counts, before we reset the + // counts. + CtorDtorCounter c100(100), c101(101), c102(102); + + CtorDtorCounter::ResetCounter(); + + { + auto testNullable = MakeNullable(100); + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 1 && CtorDtorCounter::destroyed == 0); + NL_TEST_ASSERT(inSuite, !testNullable.IsNull() && testNullable.Value().m == 100); + NL_TEST_ASSERT(inSuite, testNullable == c100); + NL_TEST_ASSERT(inSuite, testNullable != c101); + NL_TEST_ASSERT(inSuite, testNullable != c102); + + testNullable.SetNull(); + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 1 && CtorDtorCounter::destroyed == 1); + NL_TEST_ASSERT(inSuite, !!testNullable.IsNull()); + NL_TEST_ASSERT(inSuite, testNullable != c100); + NL_TEST_ASSERT(inSuite, testNullable != c101); + NL_TEST_ASSERT(inSuite, testNullable != c102); + + testNullable.SetNonNull(CtorDtorCounter(101)); + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 3 && CtorDtorCounter::destroyed == 2); + NL_TEST_ASSERT(inSuite, !testNullable.IsNull() && testNullable.Value().m == 101); + NL_TEST_ASSERT(inSuite, testNullable != c100); + NL_TEST_ASSERT(inSuite, testNullable == c101); + NL_TEST_ASSERT(inSuite, testNullable != c102); + + testNullable.SetNonNull(102); + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 4 && CtorDtorCounter::destroyed == 3); + NL_TEST_ASSERT(inSuite, !testNullable.IsNull() && testNullable.Value().m == 102); + NL_TEST_ASSERT(inSuite, testNullable != c100); + NL_TEST_ASSERT(inSuite, testNullable != c101); + NL_TEST_ASSERT(inSuite, testNullable == c102); + } + + // Our test CtorDtorCounter objects are still in scope here. + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 4 && CtorDtorCounter::destroyed == 4); +} + +static void TestMake(nlTestSuite * inSuite, void * inContext) +{ + CtorDtorCounter::ResetCounter(); + + { + auto testNullable = MakeNullable(200); + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 1 && CtorDtorCounter::destroyed == 0); + NL_TEST_ASSERT(inSuite, !testNullable.IsNull() && testNullable.Value().m == 200); + } + + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 1 && CtorDtorCounter::destroyed == 1); +} + +static void TestCopy(nlTestSuite * inSuite, void * inContext) +{ + CtorDtorCounter::ResetCounter(); + + { + auto testSrc = MakeNullable(300); + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 1 && CtorDtorCounter::destroyed == 0); + NL_TEST_ASSERT(inSuite, !testSrc.IsNull() && testSrc.Value().m == 300); + + { + Nullable testDst(testSrc); + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 0); + NL_TEST_ASSERT(inSuite, !testDst.IsNull() && testDst.Value().m == 300); + } + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 1); + + { + Nullable testDst; + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 1); + NL_TEST_ASSERT(inSuite, !!testDst.IsNull()); + + testDst = testSrc; + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 3 && CtorDtorCounter::destroyed == 1); + NL_TEST_ASSERT(inSuite, !testDst.IsNull() && testDst.Value().m == 300); + } + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 3 && CtorDtorCounter::destroyed == 2); + } + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 3 && CtorDtorCounter::destroyed == 3); +} + +static void TestMove(nlTestSuite * inSuite, void * inContext) +{ + CtorDtorCounter::ResetCounter(); + + { + auto testSrc = MakeNullable(400); + Nullable testDst(std::move(testSrc)); + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 1); + NL_TEST_ASSERT(inSuite, !testDst.IsNull() && testDst.Value().m == 400); + } + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 2); + + { + Nullable testDst; + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 2); + NL_TEST_ASSERT(inSuite, !!testDst.IsNull()); + + auto testSrc = MakeNullable(401); + testDst = std::move(testSrc); + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 4 && CtorDtorCounter::destroyed == 3); + NL_TEST_ASSERT(inSuite, !testDst.IsNull() && testDst.Value().m == 401); + } + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 4 && CtorDtorCounter::destroyed == 4); +} + +static void TestUpdate(nlTestSuite * inSuite, void * inContext) +{ + using SmallArray = std::array; + // Arrays + { + auto nullable1 = MakeNullable({ 1, 2, 3 }); + auto nullable2 = MakeNullable({ 1, 2, 3 }); + + NL_TEST_ASSERT(inSuite, !nullable1.IsNull()); + NL_TEST_ASSERT(inSuite, !nullable2.IsNull()); + NL_TEST_ASSERT(inSuite, nullable1 == nullable2); + + // No-op on change to same. + NL_TEST_ASSERT(inSuite, nullable1.Update(nullable2) == false); + NL_TEST_ASSERT(inSuite, nullable1 == nullable2); + + nullable1.Value()[0] = 100; + + NL_TEST_ASSERT(inSuite, nullable1 != nullable2); + NL_TEST_ASSERT(inSuite, nullable2.Update(nullable1) == true); + NL_TEST_ASSERT(inSuite, nullable1 == nullable2); + } + + // Structs + { + struct SomeObject + { + uint8_t a; + uint8_t b; + + bool operator==(const SomeObject & other) const { return (a == other.a) && (b == other.b); } + }; + + auto nullable1 = MakeNullable({ 1, 2 }); + auto nullable2 = MakeNullable({ 1, 2 }); + + NL_TEST_ASSERT(inSuite, !nullable1.IsNull()); + NL_TEST_ASSERT(inSuite, !nullable2.IsNull()); + NL_TEST_ASSERT(inSuite, nullable1 == nullable2); + + // No-op on change to same. + NL_TEST_ASSERT(inSuite, nullable1.Update(nullable2) == false); + NL_TEST_ASSERT(inSuite, nullable1 == nullable2); + + nullable1.Value().a = 100; + + NL_TEST_ASSERT(inSuite, nullable1 != nullable2); + NL_TEST_ASSERT(inSuite, nullable2.Update(nullable1) == true); + NL_TEST_ASSERT(inSuite, nullable1 == nullable2); + } + + // Scalar cases + { + auto nullable1 = MakeNullable(static_cast(1)); + + NL_TEST_ASSERT(inSuite, !nullable1.IsNull()); + + // Non-null to non-null same value + NL_TEST_ASSERT(inSuite, nullable1.Update(nullable1) == false); + NL_TEST_ASSERT(inSuite, !nullable1.IsNull()); + + // Non-null to null + NL_TEST_ASSERT(inSuite, nullable1.Update(NullNullable) == true); + NL_TEST_ASSERT(inSuite, nullable1.IsNull()); + + // Null to null + NL_TEST_ASSERT(inSuite, nullable1.Update(NullNullable) == false); + NL_TEST_ASSERT(inSuite, nullable1.IsNull()); + + // Null to non-null + NL_TEST_ASSERT(inSuite, nullable1.Update(MakeNullable(static_cast(1))) == true); + NL_TEST_ASSERT(inSuite, !nullable1.IsNull()); + NL_TEST_ASSERT(inSuite, nullable1.Value() == 1); + + // Non-null to non-null different value + NL_TEST_ASSERT(inSuite, nullable1.Update(MakeNullable(static_cast(2))) == true); + NL_TEST_ASSERT(inSuite, !nullable1.IsNull()); + NL_TEST_ASSERT(inSuite, nullable1.Value() == 2); + + // Non-null to extent of range --> changes to "invalid" value in range. + NL_TEST_ASSERT(inSuite, nullable1.Update(MakeNullable(static_cast(255))) == true); + NL_TEST_ASSERT(inSuite, !nullable1.IsNull()); + NL_TEST_ASSERT(inSuite, nullable1.Value() == 255); + } +} + +// clang-format off +static const nlTest sTests[] = +{ + NL_TEST_DEF("NullableBasic", TestBasic), + NL_TEST_DEF("NullableMake", TestMake), + NL_TEST_DEF("NullableCopy", TestCopy), + NL_TEST_DEF("NullableMove", TestMove), + NL_TEST_DEF("Nullable Update operation", TestUpdate), + NL_TEST_SENTINEL() +}; +// clang-format on + +int TestNullable() +{ + // clang-format off + nlTestSuite theSuite = + { + "Test for Nullable abstraction", + &sTests[0], + nullptr, + nullptr + }; + // clang-format on + + nlTestRunner(&theSuite, nullptr); + + return (nlTestRunnerStats(&theSuite)); +} + +CHIP_REGISTER_TEST_SUITE(TestNullable) diff --git a/src/app/tests/TestPendingResponseTrackerImpl.cpp b/src/app/tests/TestPendingResponseTrackerImpl.cpp new file mode 100644 index 00000000000000..da6239434cd3b1 --- /dev/null +++ b/src/app/tests/TestPendingResponseTrackerImpl.cpp @@ -0,0 +1,135 @@ +/* + * 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 + +namespace { + +using namespace chip; + +void TestPendingResponseTracker_FillEntireTracker(nlTestSuite * inSuite, void * inContext) +{ + chip::app::PendingResponseTrackerImpl pendingResponseTracker; + for (uint16_t commandRef = 0; commandRef < std::numeric_limits::max(); commandRef++) + { + NL_TEST_ASSERT(inSuite, false == pendingResponseTracker.IsTracked(commandRef)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == pendingResponseTracker.Add(commandRef)); + NL_TEST_ASSERT(inSuite, true == pendingResponseTracker.IsTracked(commandRef)); + } + + NL_TEST_ASSERT(inSuite, std::numeric_limits::max() == pendingResponseTracker.Count()); + + for (uint16_t commandRef = 0; commandRef < std::numeric_limits::max(); commandRef++) + { + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == pendingResponseTracker.Remove(commandRef)); + NL_TEST_ASSERT(inSuite, false == pendingResponseTracker.IsTracked(commandRef)); + } + NL_TEST_ASSERT(inSuite, 0 == pendingResponseTracker.Count()); +} + +void TestPendingResponseTracker_FillSingleEntryInTracker(nlTestSuite * inSuite, void * inContext) +{ + chip::app::PendingResponseTrackerImpl pendingResponseTracker; + + // The value 40 is arbitrary; any value would work for this purpose. + uint16_t commandRefToSet = 40; + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == pendingResponseTracker.Add(commandRefToSet)); + + for (uint16_t commandRef = 0; commandRef < std::numeric_limits::max(); commandRef++) + { + bool expectedIsSetResult = (commandRef == commandRefToSet); + NL_TEST_ASSERT(inSuite, expectedIsSetResult == pendingResponseTracker.IsTracked(commandRef)); + } +} + +void TestPendingResponseTracker_RemoveNonExistentEntryInTrackerFails(nlTestSuite * inSuite, void * inContext) +{ + chip::app::PendingResponseTrackerImpl pendingResponseTracker; + + // The value 40 is arbitrary; any value would work for this purpose. + uint16_t commandRef = 40; + NL_TEST_ASSERT(inSuite, false == pendingResponseTracker.IsTracked(commandRef)); + NL_TEST_ASSERT(inSuite, CHIP_ERROR_KEY_NOT_FOUND == pendingResponseTracker.Remove(commandRef)); +} + +void TestPendingResponseTracker_AddingSecondEntryFails(nlTestSuite * inSuite, void * inContext) +{ + chip::app::PendingResponseTrackerImpl pendingResponseTracker; + + // The value 40 is arbitrary; any value would work for this purpose. + uint16_t commandRef = 40; + NL_TEST_ASSERT(inSuite, false == pendingResponseTracker.IsTracked(commandRef)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == pendingResponseTracker.Add(commandRef)); + NL_TEST_ASSERT(inSuite, true == pendingResponseTracker.IsTracked(commandRef)); + NL_TEST_ASSERT(inSuite, CHIP_ERROR_INVALID_ARGUMENT == pendingResponseTracker.Add(commandRef)); +} + +void TestPendingResponseTracker_PopFindsAllPendingRequests(nlTestSuite * inSuite, void * inContext) +{ + chip::app::PendingResponseTrackerImpl pendingResponseTracker; + + // The specific values in requestsToAdd are not significant; they are chosen arbitrarily for testing purposes. + std::vector requestsToAdd = { 0, 50, 2, 2000 }; + for (const uint16_t & commandRef : requestsToAdd) + { + NL_TEST_ASSERT(inSuite, false == pendingResponseTracker.IsTracked(commandRef)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == pendingResponseTracker.Add(commandRef)); + NL_TEST_ASSERT(inSuite, true == pendingResponseTracker.IsTracked(commandRef)); + } + + NL_TEST_ASSERT(inSuite, requestsToAdd.size() == pendingResponseTracker.Count()); + + for (size_t i = 0; i < requestsToAdd.size(); i++) + { + auto commandRef = pendingResponseTracker.PopPendingResponse(); + NL_TEST_ASSERT(inSuite, true == commandRef.HasValue()); + bool expectedCommandRef = std::find(requestsToAdd.begin(), requestsToAdd.end(), commandRef.Value()) != requestsToAdd.end(); + NL_TEST_ASSERT(inSuite, true == expectedCommandRef); + } + NL_TEST_ASSERT(inSuite, 0 == pendingResponseTracker.Count()); + auto commandRef = pendingResponseTracker.PopPendingResponse(); + NL_TEST_ASSERT(inSuite, false == commandRef.HasValue()); +} + +} // namespace + +#define NL_TEST_DEF_FN(fn) NL_TEST_DEF("Test " #fn, fn) +/** + * Test Suite. It lists all the test functions. + */ +static const nlTest sTests[] = { NL_TEST_DEF_FN(TestPendingResponseTracker_FillEntireTracker), + NL_TEST_DEF_FN(TestPendingResponseTracker_FillSingleEntryInTracker), + NL_TEST_DEF_FN(TestPendingResponseTracker_RemoveNonExistentEntryInTrackerFails), + NL_TEST_DEF_FN(TestPendingResponseTracker_AddingSecondEntryFails), + NL_TEST_DEF_FN(TestPendingResponseTracker_PopFindsAllPendingRequests), + NL_TEST_SENTINEL() }; + +int TestPendingResponseTracker() +{ + nlTestSuite theSuite = { "CHIP PendingResponseTrackerImpl tests", &sTests[0], nullptr, nullptr }; + + // Run test suite against one context. + nlTestRunner(&theSuite, nullptr); + return nlTestRunnerStats(&theSuite); +} + +CHIP_REGISTER_TEST_SUITE(TestPendingResponseTracker) diff --git a/src/app/tests/suites/DL_UsersAndCredentials.yaml b/src/app/tests/suites/DL_UsersAndCredentials.yaml index 0a344d4883eba6..e86fbbe56dc053 100644 --- a/src/app/tests/suites/DL_UsersAndCredentials.yaml +++ b/src/app/tests/suites/DL_UsersAndCredentials.yaml @@ -562,7 +562,7 @@ tests: - name: "UserUniqueID" value: 0xBABA - name: "UserStatus" - value: 2 + value: UserStatusEnum.UnknownEnumValue(2) - name: "UserType" value: null - name: "CredentialRule" @@ -1031,7 +1031,7 @@ tests: - name: "UserIndex" value: null - name: "UserStatus" - value: 2 + value: UserStatusEnum.UnknownEnumValue(2) - name: "UserType" value: null response: diff --git a/src/app/tests/suites/TestAccessControlConstraints.yaml b/src/app/tests/suites/TestAccessControlConstraints.yaml index 82e66b8d347c10..1a54ea48f92365 100644 --- a/src/app/tests/suites/TestAccessControlConstraints.yaml +++ b/src/app/tests/suites/TestAccessControlConstraints.yaml @@ -130,7 +130,7 @@ tests: { FabricIndex: 0, Privilege: 3, - AuthMode: 4, # INVALID + AuthMode: AccessControlEntryAuthModeEnum.UnknownEnumValue, Subjects: [], Targets: null, }, @@ -231,7 +231,7 @@ tests: }, { FabricIndex: 0, - Privilege: 6, # INVALID + Privilege: AccessControlEntryPrivilegeEnum.UnknownEnumValue, AuthMode: 2, # CASE Subjects: null, Targets: null, diff --git a/src/app/tests/suites/TestCluster.yaml b/src/app/tests/suites/TestCluster.yaml index d51aea86b777f6..017d6ce6b6daf4 100644 --- a/src/app/tests/suites/TestCluster.yaml +++ b/src/app/tests/suites/TestCluster.yaml @@ -1066,7 +1066,7 @@ tests: - name: "arg1" value: 20003 - name: "arg2" - value: 101 + value: SimpleEnum.UnknownEnumValue response: # Attempting to echo back the invalid enum value should fail. error: FAILURE @@ -2814,7 +2814,7 @@ tests: command: "writeAttribute" attribute: "nullable_enum_attr" arguments: - value: 255 + value: SimpleEnum.UnknownEnumValue(255) response: error: CONSTRAINT_ERROR diff --git a/src/app/tests/suites/TestDiagnosticLogs.yaml b/src/app/tests/suites/TestDiagnosticLogs.yaml index 57ab8cb0fa04f8..2e512d962678c3 100644 --- a/src/app/tests/suites/TestDiagnosticLogs.yaml +++ b/src/app/tests/suites/TestDiagnosticLogs.yaml @@ -443,7 +443,7 @@ tests: arguments: values: - name: "Intent" - value: 128 # undefined value + value: IntentEnum.UnknownEnumValue(128) - name: "RequestedProtocol" value: 0 # ResponsePayload response: @@ -456,7 +456,7 @@ tests: - name: "Intent" value: 0 # EndUserSupport - name: "RequestedProtocol" - value: 128 # undefined value + value: TransferProtocolEnum.UnknownEnumValue(128) response: error: "INVALID_COMMAND" diff --git a/src/app/tests/suites/TestDiscovery.yaml b/src/app/tests/suites/TestDiscovery.yaml index c4f1afc08be9f8..77c0615a27bc8d 100644 --- a/src/app/tests/suites/TestDiscovery.yaml +++ b/src/app/tests/suites/TestDiscovery.yaml @@ -203,7 +203,7 @@ tests: - name: "productId" value: productId - - label: "Optional TXT key for MRP Sleepy Idle Interval (SII)" + - label: "Optional TXT key for MRP Session Idle Interval (SII)" PICS: MCORE.SC.SII_COMM_DISCOVERY_KEY cluster: "DiscoveryCommands" command: "FindCommissionable" @@ -214,7 +214,7 @@ tests: minValue: 0 maxValue: 3600000 - - label: "Optional TXT key for MRP Sleepy Active Interval (SAI)" + - label: "Optional TXT key for MRP Session Active Interval (SAI)" PICS: MCORE.SC.SAI_COMM_DISCOVERY_KEY cluster: "DiscoveryCommands" command: "FindCommissionable" diff --git a/src/app/tests/suites/TestScenesMaxCapacity.yaml b/src/app/tests/suites/TestScenesMaxCapacity.yaml new file mode 100644 index 00000000000000..b9ec7593237812 --- /dev/null +++ b/src/app/tests/suites/TestScenesMaxCapacity.yaml @@ -0,0 +1,890 @@ +# 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. + +# !!!!!!!!!! TEST INFORMATION !!!!!!!!!!!!!!!!!! +# This test covers multi fabric support for scenes cluster attributes such as LastConfiguredBy and FabricSceneInfo + +name: Scenes Multi-fabric testing + +PICS: + - MCORE.ROLE.COMMISSIONEE + - APPDEVICE.S + +config: + nodeId: 0x12344321 + cluster: "Scenes Management" + endpoint: 1 + payload: + type: char_string + defaultValue: "MT:-24J0AFN00KA0648G00" + discriminator: + type: int16u + defaultValue: 3840 + waitAfterCommissioning: + type: int16u + defaultValue: 5000 + PakeVerifier: + type: octet_string + defaultValue: "hex:b96170aae803346884724fe9a3b287c30330c2a660375d17bb205a8cf1aecb350457f8ab79ee253ab6a8e46bb09e543ae422736de501e3db37d441fe344920d09548e4c18240630c4ff4913c53513839b7c07fcc0627a1b8573a149fcd1fa466cf" + G1: + type: group_id + defaultValue: 0x0001 + G2: + type: group_id + defaultValue: 0x0002 + +tests: + - label: "Commission DUT to TH1" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "TH1 reads the fabric index" + cluster: "Operational Credentials" + endpoint: 0 + command: "readAttribute" + attribute: "CurrentFabricIndex" + response: + saveAs: th1FabricIndex + + - label: "Read the commissioner node ID from the alpha fabric" + identity: "alpha" + endpoint: 0 + cluster: "CommissionerCommands" + command: "GetCommissionerNodeId" + response: + values: + - name: "nodeId" + saveAs: commissionerNodeIdAlpha + + - label: "Open Commissioning Window from alpha" + endpoint: 0 + cluster: "Administrator Commissioning" + command: "OpenCommissioningWindow" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "CommissioningTimeout" + value: 180 + - name: "PAKEPasscodeVerifier" + value: PakeVerifier + - name: "Discriminator" + value: discriminator + - name: "Iterations" + value: 1000 + - name: "Salt" + value: "SPAKE2P Key Salt" + + - label: "Waiting after opening commissioning window" + cluster: "DelayCommands" + command: "WaitForMs" + arguments: + values: + - name: "ms" + value: waitAfterCommissioning + + - label: "Commission from TH2" + identity: "beta" + endpoint: 0 + cluster: "CommissionerCommands" + command: "PairWithCode" + arguments: + values: + - name: "nodeId" + value: nodeId + - name: "payload" + value: payload + + - label: "Wait for the commissioned device to be retrieved for TH2" + endpoint: 0 + identity: beta + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "TH2 reads the fabric index" + identity: "beta" + endpoint: 0 + cluster: "Operational Credentials" + command: "readAttribute" + attribute: "CurrentFabricIndex" + response: + saveAs: th2FabricIndex + + - label: "Read the commissioner node ID from the beta fabric" + identity: "beta" + endpoint: 0 + cluster: "CommissionerCommands" + command: "GetCommissionerNodeId" + response: + values: + - name: "nodeId" + saveAs: commissionerNodeIdBeta + + - label: "Open Commissioning Window from alpha" + endpoint: 0 + cluster: "Administrator Commissioning" + command: "OpenCommissioningWindow" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "CommissioningTimeout" + value: 180 + - name: "PAKEPasscodeVerifier" + value: PakeVerifier + - name: "Discriminator" + value: discriminator + - name: "Iterations" + value: 1000 + - name: "Salt" + value: "SPAKE2P Key Salt" + + - label: "Waiting after opening commissioning window" + cluster: "DelayCommands" + command: "WaitForMs" + arguments: + values: + - name: "ms" + value: waitAfterCommissioning + + - label: "Commission from TH3" + identity: "gamma" + endpoint: 0 + cluster: "CommissionerCommands" + command: "PairWithCode" + arguments: + values: + - name: "nodeId" + value: nodeId + - name: "payload" + value: payload + + - label: "Wait for the commissioned device to be retrieved for TH3" + endpoint: 0 + identity: gamma + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "TH3 reads the fabric index" + identity: "gamma" + endpoint: 0 + cluster: "Operational Credentials" + command: "readAttribute" + attribute: "CurrentFabricIndex" + response: + saveAs: th3FabricIndex + + - label: "Read the commissioner node ID from the gamma fabric" + identity: "gamma" + endpoint: 0 + cluster: "CommissionerCommands" + command: "GetCommissionerNodeId" + response: + values: + - name: "nodeId" + saveAs: commissionerNodeIdBeta + + - label: "Read the FabricSceneInfo attribute (0x0007) " + command: "readAttribute" + attribute: "FabricSceneInfo" + response: + constraints: + type: list + + - label: "TH reads from the DUT the (0x0006) SceneTableSize attribute" + command: "readAttribute" + attribute: "SceneTableSize" + response: + values: + - name: "SceneTableSize" + saveAs: maxScenes + + - label: "Arithmetic operation to get the maxScenes - 1" + cluster: "Unit Testing" + command: "TestAddArguments" + arguments: + values: + - name: "arg1" + value: maxScenes - 1 + - name: "arg2" + value: 0 + response: + values: + - name: "returnValue" + saveAs: maxScenesMinusOne + value: maxScenes - 1 + + - label: "Arithmetic operation to get the fabric Capacity" + cluster: "Unit Testing" + command: "TestAddArguments" + arguments: + values: + - name: "arg1" + value: maxScenesMinusOne / 2 + - name: "arg2" + value: 0 + response: + values: + - name: "returnValue" + saveAs: fabricCapacity + value: maxScenesMinusOne / 2 + + - label: "Preparation step : TH 1 Add Group KeySet." + cluster: "Group Key Management" + endpoint: 0 + command: "KeySetWrite" + arguments: + values: + - name: "GroupKeySet" + value: + { + GroupKeySetID: 0x01a1, + GroupKeySecurityPolicy: 0, + EpochKey0: "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + EpochStartTime0: 1110000, + EpochKey1: "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf", + EpochStartTime1: 1110001, + EpochKey2: "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + EpochStartTime2: 1110002, + } + + - label: "Preparation step TH1 Map KeySets to GroupId." + cluster: "Group Key Management" + endpoint: 0 + command: "writeAttribute" + attribute: "GroupKeyMap" + arguments: + value: + [ + { FabricIndex: 0, GroupId: G1, GroupKeySetID: 0x01a1 }, + { FabricIndex: 0, GroupId: G2, GroupKeySetID: 0x01a1 }, + ] + + - label: "TH1 sends a RemoveAllGroups command to DUT." + cluster: "Groups" + command: "RemoveAllGroups" + + - label: "TH1 sends a AddGroup command to DUT for G1." + cluster: "Groups" + command: "AddGroup" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "GroupName" + value: "Group1" + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + + - label: "TH1 sends a AddGroup command to DUT for G2." + cluster: "Groups" + command: "AddGroup" + arguments: + values: + - name: "GroupID" + value: G2 + - name: "GroupName" + value: "Group2" + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G2 + + - label: "Preparation step : TH 2 Add Group KeySet." + identity: "beta" + cluster: "Group Key Management" + endpoint: 0 + command: "KeySetWrite" + arguments: + values: + - name: "GroupKeySet" + value: + { + GroupKeySetID: 0x01a2, + GroupKeySecurityPolicy: 0, + EpochKey0: "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + EpochStartTime0: 1120000, + EpochKey1: "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf", + EpochStartTime1: 1120001, + EpochKey2: "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + EpochStartTime2: 1120002, + } + + - label: "Preparation step TH2 Map KeySets to GroupId." + identity: "beta" + cluster: "Group Key Management" + endpoint: 0 + command: "writeAttribute" + attribute: "GroupKeyMap" + arguments: + value: + [ + { FabricIndex: 0, GroupId: G1, GroupKeySetID: 0x01a2 }, + { FabricIndex: 0, GroupId: G2, GroupKeySetID: 0x01a2 }, + ] + + - label: "TH2 sends a AddGroup command to DUT for G1." + identity: "beta" + cluster: "Groups" + command: "AddGroup" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "GroupName" + value: "Group1" + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + + - label: "TH2 sends a AddGroup command to DUT for G2." + identity: "beta" + cluster: "Groups" + command: "AddGroup" + arguments: + values: + - name: "GroupID" + value: G2 + - name: "GroupName" + value: "Group1" + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G2 + + - label: "TH2 confirms the Fabric Capacity is Maximum" + command: "GetSceneMembership" + identity: "beta" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "Capacity" + value: fabricCapacity + - name: "GroupID" + value: G1 + + - label: "Preparation step : TH 3 Add Group KeySet." + identity: "gamma" + cluster: "Group Key Management" + endpoint: 0 + command: "KeySetWrite" + arguments: + values: + - name: "GroupKeySet" + value: + { + GroupKeySetID: 0x01a2, + GroupKeySecurityPolicy: 0, + EpochKey0: "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + EpochStartTime0: 1120000, + EpochKey1: "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf", + EpochStartTime1: 1120001, + EpochKey2: "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + EpochStartTime2: 1120002, + } + + - label: "Preparation step TH3 Map KeySets to GroupId." + identity: "gamma" + cluster: "Group Key Management" + endpoint: 0 + command: "writeAttribute" + attribute: "GroupKeyMap" + arguments: + value: [{ FabricIndex: 0, GroupId: G1, GroupKeySetID: 0x01a2 }] + + - label: "TH3 sends a AddGroup command to DUT for G1." + identity: "gamma" + cluster: "Groups" + command: "AddGroup" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "GroupName" + value: "Group1" + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + + - label: "TH3 confirms the Fabric Capacity is Maximum" + command: "GetSceneMembership" + identity: "gamma" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "Capacity" + value: fabricCapacity + - name: "GroupID" + value: G1 + + - label: "TH1 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0001 + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0001 + + - label: "TH2 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + identity: "beta" + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0001 + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0001 + + - label: "TH3 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + identity: "gamma" + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0001 + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0001 + + - label: "TH1 confirms the Fabric Capacity is 0" + command: "GetSceneMembership" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "Capacity" + value: fabricCapacity - 1 + - name: "GroupID" + value: G1 + + - label: "TH2 confirms the Fabric Capacity is 7" + command: "GetSceneMembership" + identity: "beta" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "Capacity" + value: fabricCapacity - 1 + - name: "GroupID" + value: G1 + + - label: "TH2 confirms the Fabric Capacity is 7" + command: "GetSceneMembership" + identity: "beta" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "Capacity" + value: fabricCapacity - 1 + - name: "GroupID" + value: G1 + + # Now we fill TH1 + - label: "TH1 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0002 + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0002 + + - label: "TH1 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0003 + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0003 + + - label: "TH1 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0004 + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0004 + + - label: "TH1 copies Scenes from G1 to G2" + command: "CopyScene" + arguments: + values: + - name: "Mode" + value: 0x01 + - name: "GroupIdentifierFrom" + value: G1 + - name: "SceneIdentifierFrom" + value: 0x01 + - name: "GroupIdentifierTo" + value: G2 + - name: "SceneIdentifierTo" + value: 0x02 + response: + values: + - name: "Status" + value: 0x89 + - name: "GroupIdentifierFrom" + value: G1 + - name: "SceneIdentifierFrom" + value: 0x01 + + - label: "TH1 Read the FabricSceneInfo attribute (0x0002) " + command: "readAttribute" + attribute: "FabricSceneInfo" + response: + value: + [ + { + SceneCount: 7, + CurrentScene: 0x04, + CurrentGroup: 0x0001, + FabricIndex: th1FabricIndex, + SceneValid: true, + RemainingCapacity: fabricCapacity - 7, + }, + ] + + - label: "TH2 Read the FabricSceneInfo attribute (0x0002) " + identity: "beta" + command: "readAttribute" + attribute: "FabricSceneInfo" + response: + value: + [ + { + SceneCount: 1, + CurrentScene: 0x01, + CurrentGroup: 0x01, + FabricIndex: th2FabricIndex, + SceneValid: true, + RemainingCapacity: fabricCapacity - 1, + }, + ] + + - label: "TH3 Read the FabricSceneInfo attribute (0x0002) " + identity: "gamma" + command: "readAttribute" + attribute: "FabricSceneInfo" + response: + value: + [ + { + SceneCount: 1, + CurrentScene: 0x01, + CurrentGroup: 0x01, + FabricIndex: th3FabricIndex, + SceneValid: true, + RemainingCapacity: fabricCapacity - 1, + }, + ] + + # Now we fill TH2 + - label: "TH2 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + identity: "beta" + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0002 + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0002 + + - label: "TH2 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + identity: "beta" + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0003 + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0003 + + - label: "TH2 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + command: "StoreScene" + identity: "beta" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0004 + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0004 + + - label: "TH2 copies Scenes from G1 to G2" + cluster: "Scenes Management" + identity: "beta" + command: "CopyScene" + arguments: + values: + - name: "Mode" + value: 0x01 + - name: "GroupIdentifierFrom" + value: G1 + - name: "SceneIdentifierFrom" + value: 0x01 + - name: "GroupIdentifierTo" + value: G2 + - name: "SceneIdentifierTo" + value: 0x02 + response: + values: + - name: "Status" + value: 0x89 + - name: "GroupIdentifierFrom" + value: G1 + - name: "SceneIdentifierFrom" + value: 0x01 + + - label: "TH1 Read the FabricSceneInfo attribute (0x0002) " + command: "readAttribute" + attribute: "FabricSceneInfo" + response: + value: + [ + { + SceneCount: 7, + CurrentScene: 0x04, + CurrentGroup: 0x0001, + FabricIndex: th1FabricIndex, + SceneValid: true, + RemainingCapacity: fabricCapacity - 7, + }, + ] + + - label: "TH2 Read the FabricSceneInfo attribute (0x0002) " + identity: "beta" + command: "readAttribute" + attribute: "FabricSceneInfo" + response: + value: + [ + { + SceneCount: 7, + CurrentScene: 0x04, + CurrentGroup: 0x0001, + FabricIndex: th2FabricIndex, + SceneValid: true, + RemainingCapacity: fabricCapacity - 7, + }, + ] + + - label: "TH3 Read the FabricSceneInfo attribute (0x0002) " + identity: "gamma" + command: "readAttribute" + attribute: "FabricSceneInfo" + response: + value: + [ + { + SceneCount: 1, + CurrentScene: 0x01, + CurrentGroup: 0x01, + FabricIndex: th3FabricIndex, + SceneValid: true, + RemainingCapacity: fabricCapacity - 6, + }, + ] + + - label: "TH3 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + identity: "gamma" + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0002 + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0002 + + - label: "TH3 sends a StoreScene command to DUT for G1." + cluster: "Scenes Management" + identity: "gamma" + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0003 + response: + values: + - name: "Status" + value: 0x89 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x0003 + + - label: "TH3 copies Scene 0x01 from G1 to 0x02 in G1" + cluster: "Scenes Management" + identity: "beta" + command: "CopyScene" + arguments: + values: + - name: "Mode" + value: 0x00 + - name: "GroupIdentifierFrom" + value: G1 + - name: "SceneIdentifierFrom" + value: 0x01 + - name: "GroupIdentifierTo" + value: G1 + - name: "SceneIdentifierTo" + value: 0x04 + response: + values: + - name: "Status" + value: 0x89 + - name: "GroupIdentifierFrom" + value: G1 + - name: "SceneIdentifierFrom" + value: 0x01 diff --git a/src/app/tests/suites/certification/PICS.yaml b/src/app/tests/suites/certification/PICS.yaml index 407851320ca31c..49554c37f4e3b6 100644 --- a/src/app/tests/suites/certification/PICS.yaml +++ b/src/app/tests/suites/certification/PICS.yaml @@ -4665,6 +4665,21 @@ PICS: "Does the DUT support the Media Playback server cluster, Seek command?" id: MEDIAPLAYBACK.S.C0b.Rsp + - label: + "Does the DUT support the Media Playback server cluster, + ActivateAudioTrack command?" + id: MEDIAPLAYBACK.S.C0c.Rsp + + - label: + "Does the DUT support the Media Playback server cluster, + ActivateTextTrack command?" + id: MEDIAPLAYBACK.S.C0d.Rsp + + - label: + "Does the DUT support the Media Playback server cluster, + DeactivateTextTrack command?" + id: MEDIAPLAYBACK.S.C0e.Rsp + - label: "Does the DUT support the Audio Output server cluster, SelectOutput command?" @@ -9162,6 +9177,9 @@ PICS: - label: "Does the DUT support testing the failed ChangeToMode command?" id: OTCCM.S.M.CAN_TEST_MODE_FAILURE + - label: "Can the mode change be manually controlled?" + id: OTCCM.S.M.CAN_MANUALLY_CONTROLLED + - label: "Id of mode the device will fail to transition to, given its current state" @@ -10064,3 +10082,114 @@ PICS: # Commands generated - label: "Does the device implement sending the GetTargetsResponse command?" id: EEVSE.S.C00.Tx + + # Energy EVSE Mode Cluster + # server / attributes + - label: "Does the device implement the Energy EVSE cluster as a server?" + id: EEVSEM.S + + - label: "Does the device implement the SupportedModes attribute?" + id: EEVSEM.S.A0000 + + - label: "Does the device implement the CurrentMode attribute?" + id: EEVSEM.S.A0001 + + - label: "Does the device implement the StartUpMode attribute?" + id: EEVSEM.S.A0002 + + - label: "Does the device implement the OnMode attribute?" + id: EEVSEM.S.A0003 + + # Commands received + - label: "Does the device implement sending the ChangeToMode command?" + id: EEVSEM.S.C00.Rsp + + # Commands generated + - label: + "Does the device implement sending the ChangeToModeResponse command?" + id: EEVSEM.S.C01.Tx + + # Manual controllable + - label: "Does the DUT support testing the failed ChangeToMode command?" + id: EEVSEM.S.M.CAN_TEST_MODE_FAILURE + + - label: "Can the mode change be manually controlled?" + id: EEVSEM.S.M.CAN_MANUALLY_CONTROLLED + + #Feature + - label: "Does the DUT(server) support the Hue/Saturation feature?" + id: EEVSEM.S.F00 + + # + # Device Energy Management Mode Cluster + # server / attributes + + - label: "Does the device implement the DEMM cluster as a server?" + id: DEMM.S + + - label: "Does the device implement the SupportedModes attribute?" + id: DEMM.S.A0000 + + - label: "Does the device implement the CurrentMode attribute?" + id: DEMM.S.A0001 + + - label: "Does the device implement the StartUpMode attribute?" + id: DEMM.S.A0002 + + - label: "Does the device implement the OnMode attribute?" + id: DEMM.S.A0003 + + # Commands received + - label: "Does the device implement sending the ChangeToMode command?" + id: DEMM.S.C00.Rsp + + # Commands generated + - label: + "Does the device implement sending the ChangeToModeResponse command?" + id: DEMM.S.C01.Tx + + - label: "Does the DUT support testing the failed ChangeToMode command?" + id: DEMM.S.M.CAN_TEST_MODE_FAILURE + + - label: "Can the mode change be manually controlled?" + id: DEMM.S.M.CAN_MANUALLY_CONTROLLED + + # Manual controllable + - label: "Does the DUT support testing the failed ChangeToMode command?" + id: EEVSEM.S.M.CAN_TEST_MODE_FAILURE + + - label: "Can the mode change be manually controlled?" + id: EEVSEM.S.M.CAN_MANUALLY_CONTROLLED + + # + # Power Topology Cluster + # + - label: "Does the device implement the Power Topology Cluster as a server?" + id: PWRTL.S + + # Features + + - label: + "Does the associated endpoint provide or consume power for the entire + node?" + id: PWRTL.S.F00 + + - label: + "Does the associated endpoint provide or consume power for itself and + its child endpoints?" + id: PWRTL.S.F01 + + - label: + "Does the associated endpoint provide or consume power for a provided + set of endpoints?" + id: PWRTL.S.F02 + + - label: "Can the provided set of endpoints change?" + id: PWRTL.S.F03 + + #Server attributes + - label: "Does the device implement the AvailableEndpoints attribute?" + id: PWRTL.S.A0000 + + - label: "Does the device implement the ActiveEndpoints attribute?" + id: PWRTL.S.A0001 diff --git a/src/app/tests/suites/certification/Test_TC_ACL_2_4.yaml b/src/app/tests/suites/certification/Test_TC_ACL_2_4.yaml index bd173e7eb81427..12a6829c642048 100644 --- a/src/app/tests/suites/certification/Test_TC_ACL_2_4.yaml +++ b/src/app/tests/suites/certification/Test_TC_ACL_2_4.yaml @@ -1164,7 +1164,7 @@ tests: FabricIndex: CurrentFabricIndexValue, }, { - Privilege: 6, + Privilege: AccessControlEntryPrivilegeEnum.UnknownEnumValue, AuthMode: 2, Subjects: null, Targets: null, @@ -1192,7 +1192,7 @@ tests: }, { Privilege: 3, - AuthMode: 4, + AuthMode: AccessControlEntryAuthModeEnum.UnknownEnumValue, Subjects: null, Targets: null, FabricIndex: CurrentFabricIndexValue, diff --git a/src/app/tests/suites/certification/Test_TC_ACL_2_9.yaml b/src/app/tests/suites/certification/Test_TC_ACL_2_9.yaml index 22ce1c1451f5a4..d2db93f33b1cd8 100644 --- a/src/app/tests/suites/certification/Test_TC_ACL_2_9.yaml +++ b/src/app/tests/suites/certification/Test_TC_ACL_2_9.yaml @@ -66,8 +66,8 @@ tests: value: [ { - Privilege: "4", - AuthMode: "2", + Privilege: AccessControlEntryPrivilegeEnum.Manage, + AuthMode: AccessControlEntryAuthModeEnum.CASE, Subjects: [CommissionerNodeId], Targets: null, FabricIndex: CurrentFabricIndexValue, @@ -94,8 +94,8 @@ tests: value: [ { - Privilege: "5", - AuthMode: "2", + Privilege: AccessControlEntryPrivilegeEnum.Administer, + AuthMode: AccessControlEntryAuthModeEnum.CASE, Subjects: [CommissionerNodeId], Targets: null, FabricIndex: CurrentFabricIndexValue, diff --git a/src/app/tests/suites/certification/Test_TC_ALOGIN_12_2.yaml b/src/app/tests/suites/certification/Test_TC_ALOGIN_12_2.yaml index 614a7977ddc59a..5981a416c7983f 100644 --- a/src/app/tests/suites/certification/Test_TC_ALOGIN_12_2.yaml +++ b/src/app/tests/suites/certification/Test_TC_ALOGIN_12_2.yaml @@ -31,8 +31,8 @@ tests: Product maker needs to provide instructions for how to trigger the command on the DUT. For comparison, the DUT behavior for this test step can be simulated using chip-tool (when DUT is a commissioner) or tv-casting-app (when DUT is a commissionee): The following command on the example tv-app will launch a content app on endpoint 4: - ./chip-tool applicationlauncher launch-app '{"catalogVendorID": 123, "applicationID": "exampleid"}' 1 1 - ./chip-tv-casting-app applicationlauncher launch-app '{"catalogVendorID": 123, "applicationID": "exampleid"}' 1 1 + ./chip-tool applicationlauncher launch-app 1 1 --Application '{"catalogVendorID": 123, "applicationID": "exampleid"}' + ./chip-tv-casting-app applicationlauncher launch-app 1 1 --Application '{"catalogVendorID": 123, "applicationID": "exampleid"}' On TH (tv-app), Verify the launch app command is received successfully. 1666779708.066501][24994:24994] CHIP:DMG: InvokeRequestMessage = [1666779708.066504][24994:24994] CHIP:DMG: { diff --git a/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_7_1.yaml b/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_7_1.yaml index 25836f5b6876eb..bd59e1aef2db26 100644 --- a/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_7_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_7_1.yaml @@ -36,10 +36,9 @@ tests: verification: | Product maker needs to provide instructions for how to trigger the command on the DUT. For comparison, the DUT behavior for this test step can be simulated using chip-tool (when DUT is a commissioner) or tv-casting-app (when DUT is a commissionee): - ./chip-tool applicationlauncher launch-app '{"catalogVendorID": 123, "applicationID": "exampleid"}' 1 1 - - ./chip-tv-casting-app applicationlauncher launch-app '{"catalogVendorID": 123, "applicationID": "exampleid"}' 1 1 + ./chip-tool applicationlauncher launch-app 1 1 --Application '{"catalogVendorID": 123, "applicationID": "exampleid"}' + ./chip-tv-casting-app applicationlauncher launch-app 1 1 --Application '{"catalogVendorID": 123, "applicationID": "exampleid"}' On TH (tv-app), Verify the launch app command is received successfully. diff --git a/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_8_1.yaml b/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_8_1.yaml index 1b00e21af2b523..ee4a07e20623dd 100644 --- a/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_8_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_8_1.yaml @@ -35,11 +35,12 @@ tests: verification: | Product maker needs to provide instructions for how to trigger the command on the DUT. For comparison, the DUT behavior for this test step can be simulated using chip-tool (when DUT is a commissioner) or tv-casting-app (when DUT is a commissionee): - ./chip-tool applicationlauncher stop-app '{"catalogVendorID": 123, "applicationID": "exampleid"}' 1 1 + ./chip-tool applicationlauncher stop-app 1 1 --Application '{"catalogVendorID": 123, "applicationID": "exampleid"}' - ./chip-tv-casting-app applicationlauncher stop-app'{"catalogVendorID": 123, "applicationID": "exampleid"}' 1 1 + ./chip-tv-casting-app applicationlauncher stop-app 1 1 --Application '{"catalogVendorID": 123, "applicationID": "exampleid"}' On TH (tv-app), Verify the stop app command is received successfully. + 74562683.652082][12550:12550] CHIP:DMG: InvokeRequestMessage = [1674562683.652085][12550:12550] CHIP:DMG: { [1674562683.652088][12550:12550] CHIP:DMG: suppressResponse = false, diff --git a/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_9_1.yaml b/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_9_1.yaml index 039c9dbdfe6966..efa0dd372f8710 100644 --- a/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_9_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_APPLAUNCHER_3_9_1.yaml @@ -35,12 +35,11 @@ tests: verification: | Product maker needs to provide instructions for how to trigger the command on the DUT. For comparison, the DUT behavior for this test step can be simulated using chip-tool (when DUT is a commissioner) or tv-casting-app (when DUT is a commissionee): - ./chip-tool applicationlauncher hide-app '{"catalogVendorID": 123, "applicationID": "exampleid"}' 1 1 + ./chip-tool applicationlauncher hide-app 1 1 --Application '{"catalogVendorID": 123, "applicationID": "exampleid"}' - ./chip-tv-casting-app applicationlauncher hide-app '{"catalogVendorID": 123, "applicationID": "exampleid"}' 1 1 + ./chip-tv-casting-app applicationlauncher hide-app 1 1 --Application '{"catalogVendorID": 123, "applicationID": "exampleid"}' On TH (tv-app), Verify the hide app command is received successfully. - [1674562762.318820][12550:12550] CHIP:DMG: InvokeRequestMessage = [1674562762.318828][12550:12550] CHIP:DMG: { [1674562762.318834][12550:12550] CHIP:DMG: suppressResponse = false, diff --git a/src/app/tests/suites/certification/Test_TC_APPOBSERVER_13_2.yaml b/src/app/tests/suites/certification/Test_TC_APPOBSERVER_13_2.yaml index b8c3b77fb08a7e..1dcf5b36fef83a 100644 --- a/src/app/tests/suites/certification/Test_TC_APPOBSERVER_13_2.yaml +++ b/src/app/tests/suites/certification/Test_TC_APPOBSERVER_13_2.yaml @@ -11,7 +11,6 @@ # 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default name: 19.15.2. [TC-APPOBSERVER-13.2] Content App Message Verification (DUT as @@ -22,27 +21,41 @@ PICS: config: nodeId: 0x12344321 - cluster: "Basic Information" - endpoint: 0 + cluster: "Content App Observer" + endpoint: 1 + + DataValue: + type: char_string + defaultValue: "exampleData" + EncodingHintValue: + type: char_string + defaultValue: "Zoo" tests: + - label: "Step 1: Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + - label: - "Step 1: TH sends a ContentAppMessage command to the DUT with dummy + "Step 2: TH sends a ContentAppMessage command to the DUT with dummy data and encodingHint strings" PICS: APPOBSERVER.S.C00.Rsp - verification: | - ./chip-tool contentappobserver content-app-message foo 1234 1 --Data bar - On TH(chip-tool), The DUT should respond with a ContentAppMessageResponse response with status 0 (success) and optional data and encodingHint strings. - [1705666572.972558][4778:4780] CHIP:DMG: InteractionModelRevision = 11 - [1705666572.972584][4778:4780] CHIP:DMG: }, - [1705666572.972667][4778:4780] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0510 Command=0x0000_0001 - [1705666572.972720][4778:4780] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0510 Command 0x0000_0001 - [1705666572.972820][4778:4780] CHIP:TOO: ContentAppMessageResponse: { - [1705666572.972862][4778:4780] CHIP:TOO: status: 0 - [1705666572.972888][4778:4780] CHIP:TOO: data: exampleData - [1705666572.972912][4778:4780] CHIP:TOO: encodingHint: foo - [1705666572.972936][4778:4780] CHIP:TOO: } - [1705666572.972989][4778:4780] CHIP:DMG: ICR moving to [AwaitingDe] - [1705666572.973210][4778:4780] CHIP:EM: <<< [E:743i S:54358 M:87646250 (Ack:136640189)] (S) Msg TX to 1:0000000000000001 [A5ED] [UDP:[fe80::e65f:1ff:fe0f:1a01%wlan0]:5540] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1705666572.973340][4778:4780] CHIP:EM: Flushed pending ack for MessageCounter:136640189 on exchange 743i - disabled: true + command: "ContentAppMessage" + arguments: + values: + - name: "Data" + value: DataValue + - name: "EncodingHint" + value: EncodingHintValue + response: + values: + - name: "Status" + value: 0 + - name: "Data" + value: DataValue + - name: "EncodingHint" + value: EncodingHintValue diff --git a/src/app/tests/suites/certification/Test_TC_APPOBSERVER_1_13.yaml b/src/app/tests/suites/certification/Test_TC_APPOBSERVER_1_13.yaml index 046e07a61dde62..509b0232e88ec6 100644 --- a/src/app/tests/suites/certification/Test_TC_APPOBSERVER_1_13.yaml +++ b/src/app/tests/suites/certification/Test_TC_APPOBSERVER_1_13.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Project CHIP Authors +# 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. @@ -22,73 +22,73 @@ PICS: config: nodeId: 0x12344321 - cluster: "Basic Information" - endpoint: 0 + cluster: "ContentAppObserver" + endpoint: 1 tests: + - label: "Step 0: Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + - label: "Step 1: TH reads the ClusterRevision attribute from the DUT" - verification: | - ./chip-tool contentappobserver read cluster-revision 1 1 - Verify " ClusterRevision " value is of unit16 and reflects the highest revision number on the TH(Chip-tool) Log, in RPI the value of ClusterRevision is 1 - [1702624923.223245][5892:5894] CHIP:DMG: InteractionModelRevision = 11 - [1702624923.223299][5892:5894] CHIP:DMG: } - [1702624923.223652][5892:5894] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0510 Attribute 0x0000_FFFD DataVersion: 2272699478 - [1702624923.223820][5892:5894] CHIP:TOO: ClusterRevision: 1 - [1702624923.224324][5892:5894] CHIP:EM: <<< [E:5445i S:15084 M:255037238 (Ack:113660697)] (S) Msg TX to 1:0000000000000001 [EDAD] [UDP:[fe80::e65f:1ff:fe49:ae1a%wlan0]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1702624923.224578][5892:5894] CHIP:EM: Flushed pending ack for MessageCounter:113660697 on exchange 5445i - disabled: true + command: "readAttribute" + attribute: "ClusterRevision" + response: + value: 1 + constraints: + type: int16u - label: "Step 2: TH reads the FeatureMap attribute from the DUT" - verification: | - ./chip-tool contentappobserver read feature-map 1 1 - On TH, verify that DUT sends the FeatureMap attribute has the value 0 or returns a general error that the attribute is not supported - [1702624956.728609][5896:5898] CHIP:DMG: SuppressResponse = true, - [1702624956.728667][5896:5898] CHIP:DMG: InteractionModelRevision = 11 - [1702624956.728720][5896:5898] CHIP:DMG: } - [1702624956.729021][5896:5898] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0510 Attribute 0x0000_FFFC DataVersion: 2272699478 - [1702624956.729138][5896:5898] CHIP:TOO: FeatureMap: 0 - [1702624956.729564][5896:5898] CHIP:EM: <<< [E:26717i S:26806 M:11352307 (Ack:31492418)] (S) Msg TX to 1:0000000000000001 [EDAD] [UDP:[fe80::e65f:1ff:fe49:ae1a%wlan0]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - disabled: true + command: "readAttribute" + attribute: "FeatureMap" + response: + value: 0 + constraints: + type: bitmap32 + + - label: "Step 3: TH reads the AttributeList attribute from the DUT" + PICS: PICS_EVENT_LIST_ENABLED + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [65528, 65529, 65530, 65531, 65532, 65533] - label: "Step 3: TH reads the AttributeList attribute from the DUT" - verification: | - ./chip-tool contentappobserver read attribute-list 1 1 - Verify " AttributeList " value consists the list of mandatory attributes (65533, 65532, 65531, 65529, 65528) on the TH(Chip-tool) Log: - [1702624983.367693][5900:5902] CHIP:DMG: } - [1702624983.368044][5900:5902] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0510 Attribute 0x0000_FFFB DataVersion: 2272699478 - [1702624983.368485][5900:5902] CHIP:TOO: AttributeList: 5 entries - [1702624983.368564][5900:5902] CHIP:TOO: [1]: 65528 - [1702624983.368624][5900:5902] CHIP:TOO: [2]: 65529 - [1702624983.368683][5900:5902] CHIP:TOO: [3]: 65531 - [1702624983.368741][5900:5902] CHIP:TOO: [4]: 65532 - [1702624983.368798][5900:5902] CHIP:TOO: [5]: 65533 - [1702624983.369236][5900:5902] CHIP:EM: <<< [E:55491i S:35892 M:103959395 (Ack:145764997)] (S) Msg TX to 1:0000000000000001 [EDAD] [UDP:[fe80::e65f:1ff:fe49:ae1a%wlan0]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - disabled: true + PICS: "!PICS_EVENT_LIST_ENABLED" + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [65528, 65529, 65531, 65532, 65533] - label: "Step 4: TH reads the AcceptedCommandList attribute from the DUT" - verification: | - ./chip-tool contentappobserver read accepted-command-list 1 1 - Verify " AcceptedCommandList " consists the list of mandatory commands(0)on the TH(Chip-tool) Log: - [1702625012.494394][5905:5907] CHIP:DMG: } - [1702625012.494619][5905:5907] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0510 Attribute 0x0000_FFF9 DataVersion: 2272699478 - [1702625012.494697][5905:5907] CHIP:TOO: AcceptedCommandList: 1 entries - [1702625012.494725][5905:5907] CHIP:TOO: [1]: 0 - [1702625012.494981][5905:5907] CHIP:EM: <<< [E:43961i S:9805 M:165451447 (Ack:180558712)] (S) Msg TX to 1:0000000000000001 [EDAD] [UDP:[fe80::e65f:1ff:fe49:ae1a%wlan0]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - disabled: true + command: "readAttribute" + attribute: "AcceptedCommandList" + response: + constraints: + type: list + contains: [0] - label: "Step 5: TH reads the GeneratedCommandList attribute from the DUT" - verification: | - ./chip-tool contentappobserver read generated-command-list 1 1 - Verify " GeneratedCommandList " consists the list of mandatory commands(1) on the TH(Chip-tool) Log: - [1702625044.200661][5910:5912] CHIP:DMG: } - [1702625044.201052][5910:5912] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0510 Attribute 0x0000_FFF8 DataVersion: 2272699478 - [1702625044.201230][5910:5912] CHIP:TOO: GeneratedCommandList: 1 entries - [1702625044.201298][5910:5912] CHIP:TOO: [1]: 1 - [1702625044.201724][5910:5912] CHIP:EM: <<< [E:33891i S:27945 M:56965554 (Ack:52573112)] (S) Msg TX to 1:0000000000000001 [EDAD] [UDP:[fe80::e65f:1ff:fe49:ae1a%wlan0]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1702625044.201956][5910:5912] CHIP:EM: Flushed pending ack for MessageCounter:52573112 on exchange 33891i - disabled: true + command: "readAttribute" + attribute: "GeneratedCommandList" + response: + constraints: + type: list + contains: [1] - label: "Step 6: TH reads the EventList attribute from the DUT" - verification: | - ./chip-tool contentappobserver read event-list 1 1 - disabled: true + PICS: PICS_EVENT_LIST_ENABLED + command: "readAttribute" + attribute: "EventList" + response: + value: [] + constraints: + type: list diff --git a/src/app/tests/suites/certification/Test_TC_CNET_4_1.yaml b/src/app/tests/suites/certification/Test_TC_CNET_4_1.yaml index fda0797ddbd6e0..54f3f8560b0c5c 100644 --- a/src/app/tests/suites/certification/Test_TC_CNET_4_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_CNET_4_1.yaml @@ -193,5 +193,6 @@ tests: attribute: "SupportedWiFiBands" response: constraints: - type: enum8 + type: list minLength: 1 + maxLength: 6 diff --git a/src/app/tests/suites/certification/Test_TC_CNET_4_10.yaml b/src/app/tests/suites/certification/Test_TC_CNET_4_10.yaml index 1320f1f2c1d8a3..ac024c5644ef45 100644 --- a/src/app/tests/suites/certification/Test_TC_CNET_4_10.yaml +++ b/src/app/tests/suites/certification/Test_TC_CNET_4_10.yaml @@ -125,6 +125,11 @@ tests: "Step 4: TH sends RemoveNetwork Command to the DUT with NetworkID field set to PIXIT.CNET.THREAD_1ST_OPERATIONALDATASET and Breadcrumb field set to 1" + verification: | + Verify that DUT sends NetworkConfigResponse to command with the following fields: + NetworkingStatus is success + + NetworkIndex is 'Userwifi_netidx' PICS: CNET.S.C04.Rsp && CNET.S.C05.Tx command: "RemoveNetwork" arguments: @@ -137,6 +142,8 @@ tests: values: - name: "NetworkingStatus" value: 0 + - name: "NetworkIndex" + value: 0 - label: "Step 5: TH reads Networks attribute from the DUT" PICS: CNET.S.A0001 @@ -264,6 +271,11 @@ tests: "Step 14: TH sends RemoveNetwork Command to the DUT with NetworkID field set to extended PAN ID of PIXIT.CNET.THREAD_1ST_OPERATIONALDATASET and Breadcrumb field set to 1" + verification: | + Verify that DUT sends NetworkConfigResponse to command with the following fields: + NetworkingStatus is success + + NetworkIndex is 'Userwifi_netidx' PICS: CNET.S.C04.Rsp && CNET.S.C05.Tx command: "RemoveNetwork" arguments: @@ -276,6 +288,8 @@ tests: values: - name: "NetworkingStatus" value: 0 + - name: "NetworkIndex" + value: 0 - label: "Step 15: TH sends the CommissioningComplete command to the DUT" PICS: CNET.S.C04.Rsp diff --git a/src/app/tests/suites/certification/Test_TC_CNET_4_11.yaml b/src/app/tests/suites/certification/Test_TC_CNET_4_11.yaml index 01981b364919bf..64335127d530ae 100644 --- a/src/app/tests/suites/certification/Test_TC_CNET_4_11.yaml +++ b/src/app/tests/suites/certification/Test_TC_CNET_4_11.yaml @@ -125,6 +125,11 @@ tests: "Step 4: TH sends RemoveNetwork Command to the DUT with NetworkID field set to PIXIT.CNET.WIFI_1ST_ACCESSPOINT_SSID and Breadcrumb field set to 1" + verification: | + Verify that DUT sends NetworkConfigResponse to command with the following fields: + NetworkingStatus is success + + NetworkIndex is 'Userwifi_netidx' PICS: CNET.S.C04.Rsp && CNET.S.C05.Tx command: "RemoveNetwork" arguments: @@ -137,6 +142,8 @@ tests: values: - name: "NetworkingStatus" value: 0 + - name: "NetworkIndex" + value: 0 - label: "Step 5: TH sends AddOrUpdateWiFiNetwork command to the DUT with SSID @@ -306,6 +313,11 @@ tests: "Step 15: TH sends RemoveNetwork Command to the DUT with NetworkID field set to PIXIT.CNET.WIFI_1ST_ACCESSPOINT_SSID and Breadcrumb field set to 1" + verification: | + Verify that DUT sends NetworkConfigResponse to command with the following fields: + NetworkingStatus is success + + NetworkIndex is 'Userwifi_netidx' PICS: CNET.S.C04.Rsp && CNET.S.C05.Tx command: "RemoveNetwork" arguments: @@ -318,6 +330,8 @@ tests: values: - name: "NetworkingStatus" value: 0 + - name: "NetworkIndex" + value: 0 - label: "Step 16: TH sends AddOrUpdateWiFiNetwork command to the DUT with SSID diff --git a/src/app/tests/suites/certification/Test_TC_CNET_4_22.yaml b/src/app/tests/suites/certification/Test_TC_CNET_4_22.yaml index b8e82aced329fc..b8fed5f79afbc5 100644 --- a/src/app/tests/suites/certification/Test_TC_CNET_4_22.yaml +++ b/src/app/tests/suites/certification/Test_TC_CNET_4_22.yaml @@ -87,15 +87,37 @@ tests: "Step 1: Verify each element in the ThreadScanResults list will have the following fields:" verification: | - Via the TH (all-clusters-app), verify: - -the PanId value is in the range of 0 to 65534. - -the ExtendedPanId value is type of uint64. - -the NetworkName value is type of string with a size of 1 to 16 bytes. - -the Channel is type of uint16 with range 0 to 65535. - -the version value is type of uint8(0 to 255). - -the ExtendedAddress is a hwaddr with a size of 8 bytes - -the RSSI is of type int8 with a range of -120 to 0. - -the LQI is type of uint8(0 to 255). + ./chip-tool networkcommissioning scan-networks 54 0 --Breadcrumb 1 + + Via the TH (chip-tool), verify: + -the NetworkingStatus value as 0 that mentions success. + -the PanId value is in the range of 0 to 65534. + -the ExtendedPanId value is type of uint64. + -the NetworkName value is type of string with a size of 1 to 16 bytes. + -the Channel is type of uint16 with range 0 to 65535. + -the version value is type of uint8(0 to 255). + -the ExtendedAddress is a hwaddr with a size of 8 bytes + -the RSSI is of type int8 with a range of -120 to 0. + -the LQI is type of uint8(0 to 255). + + [1658297246.000815][7679:7684] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0031 Command=0x0000_0001 + [1658297246.001029][7679:7684] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0031 Command 0x0000_0001 + [1658297246.001190][7679:7684] CHIP:TOO: ScanNetworksResponse: { + [1658297246.001270][7679:7684] CHIP:TOO: networkingStatus: 0 + [1658297246.001357][7679:7684] CHIP:TOO: threadScanResults: 1 entries + [1658297246.001485][7679:7684] CHIP:TOO: [1]: { + [1658297246.001548][7679:7684] CHIP:TOO: PanId: 64206 + [1658297246.001607][7679:7684] CHIP:TOO: ExtendedPanId: 3861484836749312 + [1658297246.001665][7679:7684] CHIP:TOO: NetworkName: GRL + [1658297246.001721][7679:7684] CHIP:TOO: Channel: 11 + [1658297246.001777][7679:7684] CHIP:TOO: Version: 4 + [1658297246.001841][7679:7684] CHIP:TOO: ExtendedAddress: 166E0A0000000001 + [1658297246.001900][7679:7684] CHIP:TOO: Rssi: -81 + [1658297246.001955][7679:7684] CHIP:TOO: Lqi: 48 + [1658297246.002010][7679:7684] CHIP:TOO: } + [1658297246.002070][7679:7684] CHIP:TOO: } + [1658297246.002181][7679:7684] CHIP:DMG: ICR moving to [AwaitingDe] + [1658297246.002298][7679:7684] CHIP:EM: Sending Standalone Ack for MessageCounter:124278362 on exchange 24525i cluster: "LogCommands" command: "UserPrompt" PICS: PICS_USER_PROMPT && CNET.S.C00.Rsp && CNET.S.C01.Tx @@ -144,15 +166,47 @@ tests: "Step 3: Verify each element in the ThreadScanResults list will have the following fields:" verification: | - Via the TH (all-clusters-app), verify: - -the PanId value is in the range of 0 to 65534. - -the ExtendedPanId value is type of uint64. - -the NetworkName value is type of string with a size of 1 to 16 bytes. - -the Channel is type of uint16 with range 0 to 65535. - -the version value is type of uint8(0 to 255). - -the ExtendedAddress is a hwaddr with a size of 8 bytes - -the RSSI is of type int8 with a range of -120 to 0. - -the LQI is type of uint8(0 to 255). + ./chip-tool networkcommissioning scan-networks 54 0 --Breadcrumb 2 + + Via the TH (chip-tool), verify: + -the NetworkingStatus value as 0 that mentions success. + -the PanId value is in the range of 0 to 65534. + -the ExtendedPanId value is type of uint64. + -the NetworkName value is type of string with a size of 1 to 16 bytes. + -the Channel is type of uint16 with range 0 to 65535. + -the version value is type of uint8(0 to 255). + -the ExtendedAddress is a hwaddr with a size of 8 bytes + -the RSSI is of type int8 with a range of -120 to 0. + -the LQI is type of uint8(0 to 255). + + [1658297283.141075][7695:7700] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0031 Command=0x0000_0001 + [1658297283.141183][7695:7700] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0031 Command 0x0000_0001 + [1658297283.141356][7695:7700] CHIP:TOO: ScanNetworksResponse: { + [1658297283.141438][7695:7700] CHIP:TOO: networkingStatus: 0 + [1658297283.141534][7695:7700] CHIP:TOO: threadScanResults: 2 entries + [1658297283.141663][7695:7700] CHIP:TOO: [1]: { + [1658297283.141729][7695:7700] CHIP:TOO: PanId: 64206 + [1658297283.141788][7695:7700] CHIP:TOO: ExtendedPanId: 3861484836749312 + [1658297283.141847][7695:7700] CHIP:TOO: NetworkName: GRL + [1658297283.141904][7695:7700] CHIP:TOO: Channel: 11 + [1658297283.141961][7695:7700] CHIP:TOO: Version: 4 + [1658297283.142023][7695:7700] CHIP:TOO: ExtendedAddress: 166E0A0000000001 + [1658297283.142079][7695:7700] CHIP:TOO: Rssi: -80 + [1658297283.142134][7695:7700] CHIP:TOO: Lqi: 52 + [1658297283.142188][7695:7700] CHIP:TOO: } + [1658297283.142271][7695:7700] CHIP:TOO: [2]: { + [1658297283.142331][7695:7700] CHIP:TOO: PanId: 64206 + [1658297283.142386][7695:7700] CHIP:TOO: ExtendedPanId: 3861484836749312 + [1658297283.142443][7695:7700] CHIP:TOO: NetworkName: GRL + [1658297283.142500][7695:7700] CHIP:TOO: Channel: 11 + [1658297283.142551][7695:7700] CHIP:TOO: Version: 4 + [1658297283.142609][7695:7700] CHIP:TOO: ExtendedAddress: 166E0A0000000001 + [1658297283.142665][7695:7700] CHIP:TOO: Rssi: -83 + [1658297283.142718][7695:7700] CHIP:TOO: Lqi: 44 + [1658297283.142771][7695:7700] CHIP:TOO: } + [1658297283.142828][7695:7700] CHIP:TOO: } + [1658297283.142958][7695:7700] CHIP:DMG: ICR moving to [AwaitingDe] + [1658297283.143074][7695:7700] CHIP:EM: Sending Standalone Ack for MessageCounter:115607423 on exchange 55136i cluster: "LogCommands" command: "UserPrompt" PICS: PICS_USER_PROMPT && CNET.S.C00.Rsp && CNET.S.C01.Tx @@ -201,15 +255,38 @@ tests: "Step 5: Verify each element in the ThreadScanResults list will have the following fields:" verification: | - Via the TH (all-clusters-app), verify: - -the PanId value is in the range of 0 to 65534. - -the ExtendedPanId value is type of uint64. - -the NetworkName value is type of string with a size of 1 to 16 bytes. - -the Channel is type of uint16 with range 0 to 65535. - -the version value is type of uint8(0 to 255). - -the ExtendedAddress is a hwaddr with a size of 8 bytes - -the RSSI is of type int8 with a range of -120 to 0. - -the LQI is type of uint8(0 to 255). + ./chip-tool networkcommissioning scan-networks 54 0 --Breadcrumb 3 + + Via the TH (chip-tool), verify: + -the NetworkingStatus value should be as 0 that mentions success. + -the PanId value should be with in the range of 0 to 65534. + -the ExtendedPanId value is type of uint64. + -the NetworkName value is type of string with a size of 1 to 16 bytes. + -the Channel is type of uint16 with range 0 to 65535. + -the version value is type of uint8(0 to 255). + -the ExtendedAddress is a hwaddr with a size of 8 bytes + -the RSSI is of type int8 with a range of -120 to 0. + -the LQI is type of uint8(0 to 255). + + [1658297312.201709][7708:7713] CHIP:DMG: }, + [1658297312.201898][7708:7713] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0031 Command=0x0000_0001 + [1658297312.202021][7708:7713] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0031 Command 0x0000_0001 + [1658297312.202196][7708:7713] CHIP:TOO: ScanNetworksResponse: { + [1658297312.202276][7708:7713] CHIP:TOO: networkingStatus: 0 + [1658297312.202359][7708:7713] CHIP:TOO: threadScanResults: 1 entries + [1658297312.202481][7708:7713] CHIP:TOO: [1]: { + [1658297312.202544][7708:7713] CHIP:TOO: PanId: 64206 + [1658297312.202604][7708:7713] CHIP:TOO: ExtendedPanId: 3861484836749312 + [1658297312.202663][7708:7713] CHIP:TOO: NetworkName: GRL + [1658297312.202718][7708:7713] CHIP:TOO: Channel: 11 + [1658297312.202775][7708:7713] CHIP:TOO: Version: 4 + [1658297312.202838][7708:7713] CHIP:TOO: ExtendedAddress: 166E0A0000000001 + [1658297312.202897][7708:7713] CHIP:TOO: Rssi: -78 + [1658297312.202952][7708:7713] CHIP:TOO: Lqi: 60 + [1658297312.203007][7708:7713] CHIP:TOO: } + [1658297312.203066][7708:7713] CHIP:TOO: } + [1658297312.203176][7708:7713] CHIP:DMG: ICR moving to [AwaitingDe] + [1658297312.203284][7708:7713] CHIP:EM: Sending Standalone Ack for MessageCounter:217378941 on exchange 37389i cluster: "LogCommands" command: "UserPrompt" PICS: PICS_USER_PROMPT && CNET.S.C00.Rsp && CNET.S.C01.Tx diff --git a/src/app/tests/suites/certification/Test_TC_CNET_4_9.yaml b/src/app/tests/suites/certification/Test_TC_CNET_4_9.yaml index a26524e4b59018..66e3207b24c22b 100644 --- a/src/app/tests/suites/certification/Test_TC_CNET_4_9.yaml +++ b/src/app/tests/suites/certification/Test_TC_CNET_4_9.yaml @@ -119,6 +119,11 @@ tests: "Step 4: TH sends RemoveNetwork Command to the DUT with NetworkID field set to PIXIT.CNET.WIFI_1ST_ACCESSPOINT_SSID and Breadcrumb field set to 1" + verification: | + Verify that DUT sends NetworkConfigResponse to command with the following fields: + NetworkingStatus is success + + NetworkIndex is 'Userwifi_netidx' PICS: CNET.S.C04.Rsp && CNET.S.C05.Tx command: "RemoveNetwork" arguments: @@ -131,6 +136,8 @@ tests: values: - name: "NetworkingStatus" value: 0 + - name: "NetworkIndex" + value: 0 - label: "Step 5: TH reads Networks attribute from the DUT" PICS: CNET.S.A0001 @@ -266,6 +273,11 @@ tests: "Step 14: TH sends RemoveNetwork Command to the DUT with NetworkID field set to PIXIT.CNET.WIFI_1ST_ACCESSPOINT_SSID and Breadcrumb field set to 1" + verification: | + Verify that DUT sends NetworkConfigResponse to command with the following fields: + NetworkingStatus is success + + NetworkIndex is 'Userwifi_netidx' PICS: CNET.S.C04.Rsp && CNET.S.C05.Tx command: "RemoveNetwork" arguments: @@ -278,6 +290,8 @@ tests: values: - name: "NetworkingStatus" value: 0 + - name: "NetworkIndex" + value: 0 - label: "Step 15: TH sends the CommissioningComplete command to the DUT" PICS: CNET.S.C04.Rsp diff --git a/src/app/tests/suites/certification/Test_TC_CONTENTLAUNCHER_10_4.yaml b/src/app/tests/suites/certification/Test_TC_CONTENTLAUNCHER_10_4.yaml index f192bc0d11dd7f..1fbbdab81d8a26 100644 --- a/src/app/tests/suites/certification/Test_TC_CONTENTLAUNCHER_10_4.yaml +++ b/src/app/tests/suites/certification/Test_TC_CONTENTLAUNCHER_10_4.yaml @@ -36,40 +36,66 @@ tests: verification: | Product maker needs to provide instructions for how to trigger the command on the DUT. For comparison, the DUT behavior for this test step can be simulated using chip-tool (when DUT is a commissioner) or tv-casting-app (when DUT is a commissionee): - ./chip-tool contentlauncher launch-content '{"parameterList": []}' 1 1 1 - ./chip-tv-casting-app contentlauncher launch-content '{"parameterList": []}' 1 1 1 + ./chip-tool contentlauncher launch-content '{"parameterList": [ { "type": 0, "value": "exampleString", "externalIDList": [ { "name": "exampleName", "value": "exampleValue"} ] } ] }' 0 '{"playbackPosition": 0, "textTrack": {"languageCode": "", "audioOutputIndex": 0}}' 1 1 - On TH (tv-app), Verify the launch content command is received successfully. - [1658531449325] [21924:325733] CHIP: [DMG] InvokeRequestMessage = - [1658531449325] [21924:325733] CHIP: [DMG] { - [1658531449325] [21924:325733] CHIP: [DMG] suppressResponse = false, - [1658531449325] [21924:325733] CHIP: [DMG] timedRequest = false, - [1658531449325] [21924:325733] CHIP: [DMG] InvokeRequests = - [1658531449325] [21924:325733] CHIP: [DMG] [ - [1658531449325] [21924:325733] CHIP: [DMG] CommandDataIB = - [1658531449325] [21924:325733] CHIP: [DMG] { - [1658531449325] [21924:325733] CHIP: [DMG] CommandPathIB = - [1658531449325] [21924:325733] CHIP: [DMG] { - [1658531449325] [21924:325733] CHIP: [DMG] EndpointId = 0x1, - [1658531449325] [21924:325733] CHIP: [DMG] ClusterId = 0x50a, - [1658531449325] [21924:325733] CHIP: [DMG] CommandId = 0x0, - [1658531449325] [21924:325733] CHIP: [DMG] }, - [1658531449325] [21924:325733] CHIP: [DMG] - [1658531449325] [21924:325733] CHIP: [DMG] CommandFields = - [1658531449325] [21924:325733] CHIP: [DMG] { - [1658531449325] [21924:325733] CHIP: [DMG] 0x0 = - [1658531449325] [21924:325733] CHIP: [DMG] { - [1658531449325] [21924:325733] CHIP: [DMG] 0x0 = [ - [1658531449325] [21924:325733] CHIP: [DMG] - [1658531449326] [21924:325733] CHIP: [DMG] ], - [1658531449326] [21924:325733] CHIP: [DMG] }, - [1658531449326] [21924:325733] CHIP: [DMG] 0x1 = true, - [1658531449326] [21924:325733] CHIP: [DMG] }, - [1658531449326] [21924:325733] CHIP: [DMG] }, - [1658531449326] [21924:325733] CHIP: [DMG] - [1658531449326] [21924:325733] CHIP: [DMG] ], - [1658531449326] [21924:325733] CHIP: [DMG] - [1658531449326] [21924:325733] CHIP: [DMG] InteractionModelRevision = 1 - [1658531449326] [21924:325733] CHIP: [DMG] }, + ./chip-tv-casting-app contentlauncher launch-content '{"parameterList": [ { "type": 0, "value": "exampleString", "externalIDList": [ { "name": "exampleName", "value": "exampleValue"} ] } ] }' 0 '{"playbackPosition": 0, "textTrack": {"languageCode": "", "audioOutputIndex": 0}}' 1 1 + + + On TH (tv-app), Verify the launch content command is received successfully. + [1706167504.647497][12245:12245] CHIP:EM: >>> [E:12537r S:1570 M:15519558] (S) Msg RX from 2:000000000001B669 [9F65] --- Type 0001:08 (IM:InvokeCommandRequest) + [1706167504.647555][12245:12245] CHIP:EM: Handling via exchange: 12537r, Delegate: 0xaaaac9aaa7c8 + [1706167504.647660][12245:12245] CHIP:DMG: InvokeRequestMessage = + [1706167504.647694][12245:12245] CHIP:DMG: { + [1706167504.647719][12245:12245] CHIP:DMG: suppressResponse = false, + [1706167504.647748][12245:12245] CHIP:DMG: timedRequest = false, + [1706167504.647774][12245:12245] CHIP:DMG: InvokeRequests = + [1706167504.647822][12245:12245] CHIP:DMG: [ + [1706167504.647853][12245:12245] CHIP:DMG: CommandDataIB = + [1706167504.647887][12245:12245] CHIP:DMG: { + [1706167504.647917][12245:12245] CHIP:DMG: CommandPathIB = + [1706167504.647953][12245:12245] CHIP:DMG: { + [1706167504.647987][12245:12245] CHIP:DMG: EndpointId = 0x1, + [1706167504.648023][12245:12245] CHIP:DMG: ClusterId = 0x50a, + [1706167504.648058][12245:12245] CHIP:DMG: CommandId = 0x0, + [1706167504.648090][12245:12245] CHIP:DMG: }, + [1706167504.648124][12245:12245] CHIP:DMG: + [1706167504.648154][12245:12245] CHIP:DMG: CommandFields = + [1706167504.648186][12245:12245] CHIP:DMG: { + [1706167504.648217][12245:12245] CHIP:DMG: 0x0 = + [1706167504.648251][12245:12245] CHIP:DMG: { + [1706167504.648285][12245:12245] CHIP:DMG: 0x0 = [ + [1706167504.648322][12245:12245] CHIP:DMG: + [1706167504.648362][12245:12245] CHIP:DMG: { + [1706167504.648404][12245:12245] CHIP:DMG: 0x0 = 0, + [1706167504.648449][12245:12245] CHIP:DMG: 0x1 = "exampleString" (13 chars), + [1706167504.648491][12245:12245] CHIP:DMG: 0x2 = [ + [1706167504.648533][12245:12245] CHIP:DMG: + [1706167504.648583][12245:12245] CHIP:DMG: { + [1706167504.648630][12245:12245] CHIP:DMG: 0x0 = "exampleName" (11 chars), + [1706167504.648684][12245:12245] CHIP:DMG: 0x1 = "exampleValue" (12 chars), + [1706167504.648733][12245:12245] CHIP:DMG: }, + [1706167504.648777][12245:12245] CHIP:DMG: ], + [1706167504.648819][12245:12245] CHIP:DMG: }, + [1706167504.648859][12245:12245] CHIP:DMG: ], + [1706167504.648895][12245:12245] CHIP:DMG: }, + [1706167504.648930][12245:12245] CHIP:DMG: 0x1 = false, + [1706167504.648963][12245:12245] CHIP:DMG: 0x3 = + [1706167504.648997][12245:12245] CHIP:DMG: { + [1706167504.649033][12245:12245] CHIP:DMG: 0x0 = 0, + [1706167504.649069][12245:12245] CHIP:DMG: 0x1 = + [1706167504.649107][12245:12245] CHIP:DMG: { + [1706167504.649147][12245:12245] CHIP:DMG: 0x0 = "" (0 chars), + [1706167504.649191][12245:12245] CHIP:DMG: 0x2 = 0, + [1706167504.649233][12245:12245] CHIP:DMG: }, + [1706167504.649271][12245:12245] CHIP:DMG: }, + [1706167504.649307][12245:12245] CHIP:DMG: }, + [1706167504.649339][12245:12245] CHIP:DMG: }, + [1706167504.649385][12245:12245] CHIP:DMG: + [1706167504.649412][12245:12245] CHIP:DMG: ], + [1706167504.649457][12245:12245] CHIP:DMG: + [1706167504.649484][12245:12245] CHIP:DMG: InteractionModelRevision = 11 + [1706167504.649511][12245:12245] CHIP:DMG: }, + [1706167504.649703][12245:12245] CHIP:DMG: AccessControl: checking f=2 a=c s=0x000000000001B669 t= c=0x0000_050A e=1 p=o + [1706167504.649746][12245:12245] CHIP:DMG: AccessControl: allowed disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_CONTENTLAUNCHER_10_6.yaml b/src/app/tests/suites/certification/Test_TC_CONTENTLAUNCHER_10_6.yaml index bc46f1a21393f9..f3334c012af758 100644 --- a/src/app/tests/suites/certification/Test_TC_CONTENTLAUNCHER_10_6.yaml +++ b/src/app/tests/suites/certification/Test_TC_CONTENTLAUNCHER_10_6.yaml @@ -34,8 +34,8 @@ tests: verification: | Product maker needs to provide instructions for how to trigger the command on the DUT. For comparison, the DUT behavior for this test step can be simulated using chip-tool (when DUT is a commissioner) or tv-casting-app (when DUT is a commissionee): - ./chip-tool contentlauncher launch-url 'https://www.foo.com' '{"providerName": "provider"}' 1 1 - ./chip-tv-casting-app contentlauncher launch-url 'https://www.foo.com' '{"providerName": "provider"}' 1 1 + ./chip-tool contentlauncher launch-url 'https://www.foo.com' 1 1 --DisplayString '{"providerName": "provider"}' + ./chip-tv-casting-app contentlauncher launch-url 'https://www.foo.com' 1 1 --DisplayString '{"providerName": "provider"}' On TH (tv-app), Verify the launch url command is received successfully. [1658531502040] [21924:325733] CHIP: [DMG] InvokeRequestMessage = diff --git a/src/app/tests/suites/certification/Test_TC_DD_3_2.yaml b/src/app/tests/suites/certification/Test_TC_DD_3_2.yaml index 4814d35ee82829..514d9375b11251 100644 --- a/src/app/tests/suites/certification/Test_TC_DD_3_2.yaml +++ b/src/app/tests/suites/certification/Test_TC_DD_3_2.yaml @@ -37,9 +37,10 @@ tests: verification: | Verify in DUT(ALL-CLUSTER-APP) start BLE Advertising by specific DUT implementation - Verify in TH (CHIP-TOOL) start commissioning process(need to obtain the Thread dataset first) + Verify in TH (CHIP-TOOL) start commissioning process (either Thread or WiFi) ./chip-tool pairing ble-thread 1 hex:0e080000000000010000000300000f35060004001fffe0020811111111222222220708fd27e57b1b1e22d9051000112233445566778899aabbccddeeff030e4f70656e54687265616444656d6f01021234041061e1206d2c2b46e079eb775f41fc72190c0402a0fff8 20202021 3840 + ./chip-tool pairing ble-wifi 20202021 3840 disabled: true - label: @@ -51,6 +52,38 @@ tests: CHIP:SC: Received PBKDF param response disabled: true + - label: + "Step 2a: Commissioner reads General Commissioning cluster attribute + SupportsConcurrentConnection" + verification: | + Verify in TH(CHIP-TOOL) + CHIP:DMG: AttributeReportIB = + CHIP:DMG: { + CHIP:DMG: AttributeDataIB = + CHIP:DMG: { + CHIP:DMG: DataVersion = 0xb0556660, + CHIP:DMG: AttributePathIB = + CHIP:DMG: { + CHIP:DMG: Endpoint = 0x0, + CHIP:DMG: Cluster = 0x30, + CHIP:DMG: Attribute = 0x0000_0004, + CHIP:DMG: } + CHIP:DMG: + CHIP:DMG: Data = false, + CHIP:DMG: }, + CHIP:DMG: + CHIP:DMG: }, + CHIP:DMG: + CHIP:DMG: ], + CHIP:DMG: + CHIP:DMG: SuppressResponse = true, + CHIP:DMG: InteractionModelRevision = 11 + CHIP:DMG: } + CHIP:CTL: ----- NetworkCommissioning Features: has WiFi. endpointid = 0 + CHIP:SVR: OnReadCommissioningInfo - vendorId=0xFFF1 productId=0x8001 + CHIP:CTL: Successfully finished commissioning step 'ReadCommissioningInfo2' + disabled: true + - label: "Step 3: Commissioner SHALL re-arm Fail-safe timer on Commissionee within 60s (the autonomously Fail-safe timer length set by @@ -76,63 +109,68 @@ tests: OperationalCSRRequest command" verification: | Verify in TH(CHIP-TOOL) - - CHIP:CTL: Sending CSR request to 0xffffa4001730 device + CHIP:CTL: Sending CSR request to 0xffff7fe56480 device CHIP:DMG: ICR moving to [AddingComm] CHIP:DMG: ICR moving to [AddedComma] - CHIP:IN: Prepared secure message 0xffffb9ba6db8 to 0x0000000000000001 (1) of type 0x8 and protocolId (0, 1) on exchange 45042i with MessageCounter:12011388. - CHIP:IN: Sending encrypted msg 0xffffb9ba6db8 with MessageCounter:12011388 to 0x0000000000000001 (1) at monotonic time: 304120 msec - CHIP:DMG: ICR moving to [CommandSen] + CHIP:EM: <<< [E:11057i S:28473 M:98750543] (S) Msg TX to 0:FFFFFFFB00000000 [0000] [BLE] --- Type 0001:08 (IM:InvokeCommandRequest) + CHIP:DMG: ICR moving to [AwaitingRe] CHIP:CTL: Sent CSR request, waiting for the CSR CHIP:DMG: ICR moving to [AwaitingDe] + CHIP:DL: Long dispatch time: 118 ms, for event type 16389 CHIP:DL: HandlePlatformSpecificBLEEvent 16387 - CHIP:DL: Indication received, conn = 0xffffb0044210 + CHIP:DL: Indication received, conn = 0xffff81218b30 CHIP:DL: HandlePlatformSpecificBLEEvent 16389 - CHIP:DL: Indication received, conn = 0xffffb0044210 + CHIP:DL: Indication received, conn = 0xffff81218b30 CHIP:DL: HandlePlatformSpecificBLEEvent 16389 - CHIP:EM: Received message of type 0x9 with protocolId (0, 1) and MessageCounter:8508040 on exchange 45042i - CHIP:EM: Found matching exchange: 45042i, Delegate: 0xffffb0040000 + CHIP:EM: >>> [E:11057i S:28473 M:31913565] (S) Msg RX from 0:FFFFFFFB00000000 [0000] --- Type 0001:09 (IM:InvokeCommandResponse) + CHIP:EM: Found matching exchange: 11057i, Delegate: 0xffff78c217c8 CHIP:DMG: ICR moving to [ResponseRe] CHIP:DMG: InvokeResponseMessage = CHIP:DMG: { - CHIP:DMG: suppressResponse = false, - CHIP:DMG: InvokeResponseIBs = - CHIP:DMG: [ - CHIP:DMG: InvokeResponseIB = - CHIP:DMG: { - CHIP:DMG: CommandDataIB = - CHIP:DMG: { - CHIP:DMG: CommandPathIB = - CHIP:DMG: { - CHIP:DMG: EndpointId = 0x0, - CHIP:DMG: ClusterId = 0x3e, - CHIP:DMG: CommandId = 0x5, - CHIP:DMG: }, + CHIP:DMG: suppressResponse = false, + CHIP:DMG: InvokeResponseIBs = + CHIP:DMG: [ + CHIP:DMG: InvokeResponseIB = + CHIP:DMG: { + CHIP:DMG: CommandDataIB = + CHIP:DMG: { + CHIP:DMG: CommandPathIB = + CHIP:DMG: { + CHIP:DMG: EndpointId = 0x0, + CHIP:DMG: ClusterId = 0x3e, + CHIP:DMG: CommandId = 0x5, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: CommandData = - CHIP:DMG: { - CHIP:DMG: 0x0 = [ - CHIP:DMG: 0x15, 0x30, 0x1, 0xcd, 0x30, 0x81, 0xca, 0x30, 0x70, 0x2, 0x1, 0x0, 0x30, 0xe, 0x31, 0xc, 0x30, 0xa, 0x6, 0x3, 0x55, 0x4, 0xa, 0xc, 0x3, 0x43, 0x53, 0x52, 0x30, 0x59, 0x30, 0x13, 0x6, 0x7, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x2, 0x1, 0x6, 0x8, 0x2a, 0x86 - CHIP:DMG: ] - CHIP:DMG: 0x1 = [ - CHIP:DMG: 0xea, 0xd6, 0x96, 0x53, 0x4d, 0x46, 0x1d, 0xd6, 0xcc, 0x7f, 0x25, 0x50, 0x80, 0x4c, 0x2a, 0xe9, 0xc8, 0xb8, 0x1b, 0x34, 0xca, 0x98, 0x38, 0x42, 0x74, 0xc2, 0x13, 0xf4, 0x10, 0x4d, 0xa2, 0x44, 0x38, 0x98, 0x28, 0xb6, 0xb1, 0x94, 0x6b, 0xd, 0x29, 0x1b - CHIP:DMG: ] - CHIP:DMG: }, - CHIP:DMG: }, + CHIP:DMG: CommandFields = + CHIP:DMG: { + CHIP:DMG: 0x0 = [ + CHIP:DMG: 0x15, 0x30, 0x01, 0xca, 0x30, 0x81, 0xc7, 0x30, 0x70, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x03, 0x43, 0x53, 0x52, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xf1, 0xa2, 0x66, 0x01, 0xf7, 0xec, 0x41, 0x11, 0x82, 0x3f, 0xf6, 0x8f, 0x94, 0xe6, 0xeb, 0xe6, 0x6e, 0x6b, 0xbb, 0x2b, 0xad, 0x19, 0x7e, 0xb8, 0x11, 0xbb, 0xc8, 0xc8, 0xf8, 0x59, 0x73, 0x10, 0xd7, 0xff, 0x61, 0x01, 0x0e, 0x7d, 0x50, 0x6e, 0x9d, 0x66, 0xd3, 0x89, 0x83, 0x84, 0xfe, 0xe0, 0xee, 0x7b, 0xbf, 0xaa, 0xa6, 0x3c, 0x60, 0x0a, 0x8e, 0xda, 0xb1, 0xfc, 0xa4, 0xf5, 0xf2, 0xcb, 0xa0, 0x00, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x23, 0x94, 0xd8, 0xc4, 0x00, 0x9a, 0xec, 0x9c, 0x0e, 0x11, 0x26, 0x7f, 0x9e, 0xea, 0x7b, 0xe3, 0x83, 0xde, 0xf8, 0xd3, 0xd3, 0xe7, 0x31, 0xeb, 0x3c, 0xf5, 0x73, 0x65, 0xcd, 0xd8, 0xc0, 0x48, 0x02, 0x20, 0x63, 0x5a, 0x67, 0x85, 0x71, 0xa9, 0x50, 0x30, 0x8e, 0x4c, 0x00, 0x0e, 0x65, 0x1e, 0x59, 0x53, 0x85, 0xb2, 0x6f, 0x5a, 0x01, 0x46, 0xda, 0xb5, 0x27, 0xea, 0x6b, 0x5c, 0x8a, 0x82, 0x48, 0x5e, 0x30, 0x02, 0x20, 0x08, 0x9b, 0x9c, 0xe3, 0xa4, 0xfd, 0xdb, 0xc5, 0xbd, 0x78, 0x36, 0x7c, 0x47, 0xd9, 0xaf, 0x57, 0x22, 0x5a, 0x70, 0xa8, 0x14, 0x86, 0xdd, 0xea, 0x1b, 0x44, 0x80, 0xbd, 0x39, 0x4f, 0xca, 0x76, 0x18, + CHIP:DMG: ] (242 bytes) + CHIP:DMG: 0x1 = [ + CHIP:DMG: 0xc1, 0xa1, 0xf7, 0xba, 0xe4, 0x5f, 0xd5, 0x62, 0x06, 0xb9, 0xe7, 0xf3, 0x64, 0x47, 0x36, 0x6f, 0xcb, 0xf5, 0x74, 0x97, 0x61, 0xf1, 0x54, 0xbc, 0x9a, 0x6c, 0x1b, 0x60, 0xa7, 0xf0, 0xb6, 0x5e, 0x9b, 0x05, 0x06, 0xd8, 0x9f, 0x0e, 0x47, 0xd9, 0x3a, 0xbf, 0x8d, 0x71, 0x61, 0xd4, 0xcf, 0xee, 0x38, 0x64, 0x0d, 0xc0, 0xf8, 0x44, 0xe7, 0x77, 0x08, 0x7d, 0x6b, 0x20, 0x1e, 0x40, 0x1f, 0x94, + CHIP:DMG: ] (64 bytes) + CHIP:DMG: }, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: }, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: ], + CHIP:DMG: ], CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 1 + CHIP:DMG: InteractionModelRevision = 11 CHIP:DMG: }, CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_003E Command=0x0000_0005 CHIP:CTL: Received certificate signing request from the device + CHIP:CTL: Successfully finished commissioning step 'SendOpCertSigningRequest' + CHIP:CTL: Commissioning stage next step: 'SendOpCertSigningRequest' -> 'ValidateCSR' + CHIP:CTL: Performing next commissioning step 'ValidateCSR' + CHIP:CTL: Successfully finished commissioning step 'ValidateCSR' + CHIP:CTL: Commissioning stage next step: 'ValidateCSR' -> 'GenerateNOCChain' + CHIP:CTL: Performing next commissioning step 'GenerateNOCChain' CHIP:CTL: Getting certificate chain for the device from the issuer CHIP:CTL: Verifying Certificate Signing Request CHIP:CTL: Generating NOC CHIP:CTL: Providing certificate chain to the commissioner - CHIP:CTL: Received callback from the CA for NOC Chain generation. Status ../../src/controller/ExampleOperationalCredentialsIssuer.cpp:225: Success + CHIP:CTL: Received callback from the CA for NOC Chain generation. Status src/controller/ExampleOperationalCredentialsIssuer.cpp:395: Success disabled: true - label: @@ -141,49 +179,48 @@ tests: verification: | Verify in TH(CHIP-TOOL) - [1651218829.220063][3273:3278] CHIP:CTL: Sending root certificate to the device - [1651218829.220201][3273:3278] CHIP:DMG: ICR moving to [AddingComm] - [1651218829.222415][3273:3278] CHIP:DMG: ICR moving to [AddedComma] - [1651218829.222549][3273:3278] CHIP:IN: Prepared secure message 0xffffb9ba6b98 to 0x0000000000000001 (1) of type 0x8 and protocolId (0, 1) on exchange 45043i with MessageCounter:12011389. - [1651218829.222616][3273:3278] CHIP:IN: Sending encrypted msg 0xffffb9ba6b98 with MessageCounter:12011389 to 0x0000000000000001 (1) at monotonic time: 305872 msec - [1651218829.222746][3273:3278] CHIP:DMG: ICR moving to [CommandSen] - [1651218829.222789][3273:3278] CHIP:CTL: Sent root certificate to the device - [1651218829.223121][3273:3278] CHIP:DMG: ICR moving to [AwaitingDe] - [1651218829.306861][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16387 - [1651218829.404144][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16387 - [1651218829.454121][3273:3276] CHIP:DL: Indication received, conn = 0xffffb0044210 - [1651218829.454352][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16389 - CHIP:EM: Received message of type 0x9 with protocolId (0, 1) and MessageCounter:8508041 on exchange 45043i - CHIP:EM: Found matching exchange: 45043i, Delegate: 0xffffa400def0 + CHIP:CTL: Sending root certificate to the device + CHIP:DMG: ICR moving to [AddingComm] + CHIP:DMG: ICR moving to [AddedComma] + CHIP:EM: <<< [E:11058i S:28473 M:98750544] (S) Msg TX to 0:FFFFFFFB00000000 [0000] [BLE] --- Type 0001:08 (IM:InvokeCommandRequest) + CHIP:DMG: ICR moving to [AwaitingRe] + CHIP:CTL: Sent root certificate to the device + CHIP:DMG: ICR moving to [AwaitingDe] + CHIP:DL: HandlePlatformSpecificBLEEvent 16387 + CHIP:DL: HandlePlatformSpecificBLEEvent 16387 + CHIP:DL: Indication received, conn = 0xffff81218b30 + CHIP:DL: HandlePlatformSpecificBLEEvent 16389 + CHIP:EM: >>> [E:11058i S:28473 M:31913566] (S) Msg RX from 0:FFFFFFFB00000000 [0000] --- Type 0001:09 (IM:InvokeCommandResponse) + CHIP:EM: Found matching exchange: 11058i, Delegate: 0xffff78c20b88 CHIP:DMG: ICR moving to [ResponseRe] CHIP:DMG: InvokeResponseMessage = CHIP:DMG: { - CHIP:DMG: suppressResponse = false, - CHIP:DMG: InvokeResponseIBs = - CHIP:DMG: [ - CHIP:DMG: InvokeResponseIB = - CHIP:DMG: { - CHIP:DMG: CommandStatusIB = - CHIP:DMG: { - CHIP:DMG: CommandPathIB = - CHIP:DMG: { - CHIP:DMG: EndpointId = 0x0, - CHIP:DMG: ClusterId = 0x3e, - CHIP:DMG: CommandId = 0xb, - CHIP:DMG: }, + CHIP:DMG: suppressResponse = false, + CHIP:DMG: InvokeResponseIBs = + CHIP:DMG: [ + CHIP:DMG: InvokeResponseIB = + CHIP:DMG: { + CHIP:DMG: CommandStatusIB = + CHIP:DMG: { + CHIP:DMG: CommandPathIB = + CHIP:DMG: { + CHIP:DMG: EndpointId = 0x0, + CHIP:DMG: ClusterId = 0x3e, + CHIP:DMG: CommandId = 0xb, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: StatusIB = - CHIP:DMG: { - CHIP:DMG: status = 0x0, - CHIP:DMG: }, + CHIP:DMG: StatusIB = + CHIP:DMG: { + CHIP:DMG: status = 0x00 (SUCCESS), + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: }, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: }, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: ], + CHIP:DMG: ], CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 1 + CHIP:DMG: InteractionModelRevision = 11 CHIP:DMG: }, CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_003E Command=0x0000_000B Status=0x0 CHIP:CTL: Device confirmed that it has received the root certificate @@ -195,54 +232,53 @@ tests: verification: | Verify in TH(CHIP-TOOL) - [1651218829.457248][3273:3278] CHIP:CTL: Sending operational certificate chain to the device - [1651218829.457372][3273:3278] CHIP:DMG: ICR moving to [AddingComm] - [1651218829.460013][3273:3278] CHIP:DMG: ICR moving to [AddedComma] - [1651218829.460273][3273:3278] CHIP:IN: Prepared secure message 0xffffb9ba7828 to 0x0000000000000001 (1) of type 0x8 and protocolId (0, 1) on exchange 45044i with MessageCounter:12011390. - [1651218829.460374][3273:3278] CHIP:IN: Sending encrypted msg 0xffffb9ba7828 with MessageCounter:12011390 to 0x0000000000000001 (1) at monotonic time: 306110 msec - [1651218829.460602][3273:3278] CHIP:DMG: ICR moving to [CommandSen] - [1651218829.460684][3273:3278] CHIP:CTL: Sent operational certificate to the device - [1651218829.460778][3273:3278] CHIP:DMG: ICR moving to [AwaitingDe] - [1651218829.550574][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16387 - [1651218829.648065][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16387 - [1651218829.745594][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16387 - [1651218833.988087][3273:3276] CHIP:DL: Indication received, conn = 0xffffb0044210 - [1651218833.988336][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16389 - [1651218833.988598][3273:3278] CHIP:EM: Received message of type 0x9 with protocolId (0, 1) and MessageCounter:8508042 on exchange 45044i - CHIP:EM: Found matching exchange: 45044i, Delegate: 0xffffb0040000 + CHIP:CTL: Performing next commissioning step 'SendNOC' + CHIP:DMG: ICR moving to [AddingComm] + CHIP:DMG: ICR moving to [AddedComma] + CHIP:EM: <<< [E:11059i S:28473 M:98750545] (S) Msg TX to 0:FFFFFFFB00000000 [0000] [BLE] --- Type 0001:08 (IM:InvokeCommandRequest) + CHIP:DMG: ICR moving to [AwaitingRe] + CHIP:CTL: Sent operational certificate to the device + CHIP:DMG: ICR moving to [AwaitingDe] + CHIP:DL: HandlePlatformSpecificBLEEvent 16387 + CHIP:DL: HandlePlatformSpecificBLEEvent 16387 + CHIP:DL: HandlePlatformSpecificBLEEvent 16387 + CHIP:DL: Indication received, conn = 0xffff81218b30 + CHIP:DL: HandlePlatformSpecificBLEEvent 16389 + CHIP:EM: >>> [E:11059i S:28473 M:31913567] (S) Msg RX from 0:FFFFFFFB00000000 [0000] --- Type 0001:09 (IM:InvokeCommandResponse) + CHIP:EM: Found matching exchange: 11059i, Delegate: 0xffff78c209c8 CHIP:DMG: ICR moving to [ResponseRe] CHIP:DMG: InvokeResponseMessage = CHIP:DMG: { - CHIP:DMG: suppressResponse = false, - CHIP:DMG: InvokeResponseIBs = - CHIP:DMG: [ - CHIP:DMG: InvokeResponseIB = - CHIP:DMG: { - CHIP:DMG: CommandDataIB = - CHIP:DMG: { - CHIP:DMG: CommandPathIB = - CHIP:DMG: { - CHIP:DMG: EndpointId = 0x0, - CHIP:DMG: ClusterId = 0x3e, - CHIP:DMG: CommandId = 0x8, - CHIP:DMG: }, + CHIP:DMG: suppressResponse = false, + CHIP:DMG: InvokeResponseIBs = + CHIP:DMG: [ + CHIP:DMG: InvokeResponseIB = + CHIP:DMG: { + CHIP:DMG: CommandDataIB = + CHIP:DMG: { + CHIP:DMG: CommandPathIB = + CHIP:DMG: { + CHIP:DMG: EndpointId = 0x0, + CHIP:DMG: ClusterId = 0x3e, + CHIP:DMG: CommandId = 0x8, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: CommandData = - CHIP:DMG: { - CHIP:DMG: 0x0 = 0, - CHIP:DMG: 0x1 = 1, - CHIP:DMG: }, - CHIP:DMG: }, + CHIP:DMG: CommandFields = + CHIP:DMG: { + CHIP:DMG: 0x0 = 0, + CHIP:DMG: 0x1 = 1, + CHIP:DMG: }, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: }, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: ], + CHIP:DMG: ], CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 1 + CHIP:DMG: InteractionModelRevision = 11 CHIP:DMG: }, CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_003E Command=0x0000_0008 CHIP:CTL: Device returned status 0 on receiving the NOC - CHIP:CTL: Operational credentials provisioned on device 0xffffa4001730 + CHIP:CTL: Operational credentials provisioned on device 0xffff7fe56480 disabled: true - label: @@ -251,50 +287,49 @@ tests: verification: | Verify in TH(CHIP-TOOL) - [1651218833.995054][3273:3278] CHIP:CTL: Adding thread network - [1651218833.995176][3273:3278] CHIP:DMG: ICR moving to [AddingComm] - [1651218833.995253][3273:3278] CHIP:DMG: ICR moving to [AddedComma] - [1651218833.995431][3273:3278] CHIP:IN: Prepared secure message 0xffffb9ba7848 to 0x0000000000000001 (1) of type 0x8 and protocolId (0, 1) on exchange 45045i with MessageCounter:12011391. - [1651218833.995523][3273:3278] CHIP:IN: Sending encrypted msg 0xffffb9ba7848 with MessageCounter:12011391 to 0x0000000000000001 (1) at monotonic time: 310645 msec - [1651218833.995723][3273:3278] CHIP:DMG: ICR moving to [CommandSen] - [1651218833.995823][3273:3278] CHIP:DMG: ICR moving to [AwaitingDe] - [1651218834.084548][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16387 - [1651218834.134690][3273:3276] CHIP:DL: Indication received, conn = 0xffffb0044210 - [1651218834.134918][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16389 - CHIP:EM: Received message of type 0x9 with protocolId (0, 1) and MessageCounter:8508043 on exchange 45045i - CHIP:EM: Found matching exchange: 45045i, Delegate: 0xffffa400def0 + CHIP:CTL: Performing next commissioning step 'WiFiNetworkSetup' + CHIP:DMG: ICR moving to [AddingComm] + CHIP:DMG: ICR moving to [AddedComma] + CHIP:EM: <<< [E:11060i S:28473 M:98750546] (S) Msg TX to 0:FFFFFFFB00000000 [0000] [BLE] --- Type 0001:08 (IM:InvokeCommandRequest) + CHIP:DMG: ICR moving to [AwaitingRe] + CHIP:DMG: ICR moving to [AwaitingDe] + CHIP:DL: HandlePlatformSpecificBLEEvent 16387 + CHIP:DL: Indication received, conn = 0xffff81218b30 + CHIP:DL: HandlePlatformSpecificBLEEvent 16389 + CHIP:EM: >>> [E:11060i S:28473 M:31913568] (S) Msg RX from 0:FFFFFFFB00000000 [0000] --- Type 0001:09 (IM:InvokeCommandResponse) + CHIP:EM: Found matching exchange: 11060i, Delegate: 0xffff78c20808 CHIP:DMG: ICR moving to [ResponseRe] CHIP:DMG: InvokeResponseMessage = CHIP:DMG: { - CHIP:DMG: suppressResponse = false, - CHIP:DMG: InvokeResponseIBs = - CHIP:DMG: [ - CHIP:DMG: InvokeResponseIB = - CHIP:DMG: { - CHIP:DMG: CommandDataIB = - CHIP:DMG: { - CHIP:DMG: CommandPathIB = - CHIP:DMG: { - CHIP:DMG: EndpointId = 0x0, - CHIP:DMG: ClusterId = 0x31, - CHIP:DMG: CommandId = 0x5, - CHIP:DMG: }, + CHIP:DMG: suppressResponse = false, + CHIP:DMG: InvokeResponseIBs = + CHIP:DMG: [ + CHIP:DMG: InvokeResponseIB = + CHIP:DMG: { + CHIP:DMG: CommandDataIB = + CHIP:DMG: { + CHIP:DMG: CommandPathIB = + CHIP:DMG: { + CHIP:DMG: EndpointId = 0x0, + CHIP:DMG: ClusterId = 0x31, + CHIP:DMG: CommandId = 0x5, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: CommandData = - CHIP:DMG: { - CHIP:DMG: 0x0 = 0, - CHIP:DMG: 0x1 = "", - CHIP:DMG: }, - CHIP:DMG: }, + CHIP:DMG: CommandFields = + CHIP:DMG: { + CHIP:DMG: 0x0 = 0, + CHIP:DMG: 0x2 = 0, + CHIP:DMG: }, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: }, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: ], + CHIP:DMG: ], CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 1 + CHIP:DMG: InteractionModelRevision = 11 CHIP:DMG: }, CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0031 Command=0x0000_0005 - CHIP:CTL: Received NetworkConfig response + CHIP:CTL: Received NetworkConfig response, networkingStatus=0 disabled: true - label: @@ -303,118 +338,124 @@ tests: verification: | Verify in TH(CHIP-TOOL) - [1651218834.137891][3273:3278] CHIP:CTL: Enabling thread network - [1651218834.138014][3273:3278] CHIP:DMG: ICR moving to [AddingComm] - [1651218834.138086][3273:3278] CHIP:DMG: ICR moving to [AddedComma] - [1651218834.138236][3273:3278] CHIP:IN: Prepared secure message 0xffffb9ba7938 to 0x0000000000000001 (1) of type 0x8 and protocolId (0, 1) on exchange 45046i with MessageCounter:12011392. - [1651218834.138325][3273:3278] CHIP:IN: Sending encrypted msg 0xffffb9ba7938 with MessageCounter:12011392 to 0x0000000000000001 (1) at monotonic time: 310788 msec - [1651218834.138522][3273:3278] CHIP:DMG: ICR moving to [CommandSen] - [1651218834.138628][3273:3278] CHIP:DMG: ICR moving to [AwaitingDe] - [1651218834.231701][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16387 - [1651218834.426948][3273:3276] CHIP:DL: Indication received, conn = 0xffffb0044210 - [1651218834.427186][3273:3278] CHIP:DL: HandlePlatformSpecificBLEEvent 16389 - [1651218834.427443][3273:3278] CHIP:EM: Received message of type 0x9 with protocolId (0, 1) and MessageCounter:8508044 on exchange 45046i - CHIP:EM: Found matching exchange: 45046i, Delegate: 0xffffb0040000 + CHIP:CTL: SendCommand kWiFiNetworkEnable, supportsConcurrentConnection=0 + CHIP:DMG: ICR moving to [AddingComm] + CHIP:DMG: ICR moving to [AddedComma] + CHIP:EM: <<< [E:11062i S:28473 M:98750548] (S) Msg TX to 0:FFFFFFFB00000000 [0000] [BLE] --- Type 0001:08 (IM:InvokeCommandRequest) + CHIP:DMG: ICR moving to [AwaitingRe] + CHIP:DMG: ICR moving to [AwaitingDe] + CHIP:DL: HandlePlatformSpecificBLEEvent 16387 + CHIP:DL: Indication received, conn = 0xffff81218b30 + CHIP:DL: HandlePlatformSpecificBLEEvent 16389 + CHIP:EM: >>> [E:11062i S:28473 M:31913570] (S) Msg RX from 0:FFFFFFFB00000000 [0000] --- Type 0001:09 (IM:InvokeCommandResponse) + CHIP:EM: Found matching exchange: 11062i, Delegate: 0xffff78c20488 CHIP:DMG: ICR moving to [ResponseRe] CHIP:DMG: InvokeResponseMessage = CHIP:DMG: { - CHIP:DMG: suppressResponse = false, - CHIP:DMG: InvokeResponseIBs = - CHIP:DMG: [ - CHIP:DMG: InvokeResponseIB = - CHIP:DMG: { - CHIP:DMG: CommandDataIB = - CHIP:DMG: { - CHIP:DMG: CommandPathIB = - CHIP:DMG: { - CHIP:DMG: EndpointId = 0x0, - CHIP:DMG: ClusterId = 0x31, - CHIP:DMG: CommandId = 0x7, - CHIP:DMG: }, + CHIP:DMG: suppressResponse = false, + CHIP:DMG: InvokeResponseIBs = + CHIP:DMG: [ + CHIP:DMG: InvokeResponseIB = + CHIP:DMG: { + CHIP:DMG: CommandDataIB = + CHIP:DMG: { + CHIP:DMG: CommandPathIB = + CHIP:DMG: { + CHIP:DMG: EndpointId = 0x0, + CHIP:DMG: ClusterId = 0x31, + CHIP:DMG: CommandId = 0x7, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: CommandData = - CHIP:DMG: { - CHIP:DMG: 0x0 = 0, - CHIP:DMG: 0x1 = "", - CHIP:DMG: 0x2 = 0, - CHIP:DMG: }, - CHIP:DMG: }, + CHIP:DMG: CommandFields = + CHIP:DMG: { + CHIP:DMG: 0x0 = 0, + CHIP:DMG: 0x2 = NULL + CHIP:DMG: }, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: }, + CHIP:DMG: }, CHIP:DMG: - CHIP:DMG: ], + CHIP:DMG: ], CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 1 + CHIP:DMG: InteractionModelRevision = 11 CHIP:DMG: }, CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0031 Command=0x0000_0007 - CHIP:CTL: Received ConnectNetwork response + CHIP:CTL: Received ConnectNetwork response, networkingStatus=0 disabled: true - label: "Step 10: Commissioning channel between the Commissioner and - Commissionee is terminated." + Commissionee is closed." + verification: | + Cannot be verified in TH(CHIP-TOOL) + disabled: true + + - label: "Step 11: Commissionee starts the operational channel." verification: | - 1. Terminate the connection between the Commissionee and the Commissioner. (i.e. remove network access or terminate commissioning process) + Verify in TH(CHIP-TOOL) + + Inferred by successful completion of Step 12 disabled: true - label: - "Step 11: Commissioner starts discovery of DUT using Operational + "Step 12: Commissioner starts discovery of DUT using Operational Discovery" verification: | Verify in TH(CHIP-TOOL) - CHIP:DL: Avahi resolve found - CHIP:DIS: Node ID resolved for 0x0000000000000001 - CHIP:DIS: Addr 0: [fd11:22::9d96:8fcf:10cf:799e]:5540 - CHIP:CTL: OperationalDiscoveryComplete for device ID 0x0000000000000001 + CHIP:CTL: Performing next commissioning step 'FindOperational' + CHIP:IN: Expiring all sessions for node <00000000000007CE, 1>!! + CHIP:CSM: FindOrEstablishSession: PeerId = [1:00000000000007CE] + CHIP:CSM: FindOrEstablishSession: No existing OperationalSessionSetup instance found + CHIP:DIS: OperationalSessionSetup[1:00000000000007CE]: State change 1 --> 2 + CHIP:DMG: ICR moving to [AwaitingDe] + CHIP:DIS: Checking node lookup status after 200 ms + CHIP:DL: HandlePlatformSpecificBLEEvent 16387 + CHIP:DIS: UDP:[fe80::e65f:1ff:fec2:47af%eth0]:5540: new best score: 7 + CHIP:DIS: Lookup clearing interface for non LL address + CHIP:DIS: UDP:172.16.62.113%eth0:5540: new best score: 2 + CHIP:DIS: Checking node lookup status after 7151 ms + CHIP:DIS: OperationalSessionSetup[1:00000000000007CE]: Updating device address to UDP:[fe80::e65f:1ff:fec2:47af%eth0]:5540 while in state 2 + CHIP:DIS: OperationalSessionSetup[1:00000000000007CE]: State change 2 --> 3 + CHIP:IN: SecureSession[0xffff7902f2c0]: Allocated Type:2 LSID:28474 disabled: true - label: - "Step 12: Commissioner opens a CASE session with DUT over operational + "Step 13: Commissioner opens a CASE session with DUT over operational network" verification: | Verify in TH(CHIP-TOOL) CHIP:SC: Sent Sigma1 msg - CHIP:CTL: Address resolved for node: 0x0000000000000001 - CHIP:EM: Received message of type 0x31 with protocolId (0, 0) and MessageCounter:1066460336 on exchange 45047i - CHIP:EM: Found matching exchange: 45047i, Delegate: 0xffffa400f7f8 - CHIP:EM: Rxd Ack; Removing MessageCounter:2352378411 from Retrans Table on exchange 45047i - CHIP:EM: Removed CHIP MessageCounter:2352378411 from RetransTable on exchange 45047i + CHIP:DIS: OperationalSessionSetup[1:00000000000007CE]: State change 3 --> 4 + CHIP:EM: Retransmitting MessageCounter:226454874 on exchange 11063i Send Cnt 1 + CHIP:EM: Retransmitting MessageCounter:226454874 on exchange 11063i Send Cnt 2 + CHIP:EM: Retransmitting MessageCounter:226454874 on exchange 11063i Send Cnt 3 + CHIP:EM: >>> [E:11063i S:0 M:192590746 (Ack:226454874)] (U) Msg RX from 0:0000000000000000 [0000] --- Type 0000:31 (SecureChannel:CASE_Sigma2) + CHIP:EM: Found matching exchange: 11063i, Delegate: 0xffff78207b08 + CHIP:EM: Rxd Ack; Removing MessageCounter:226454874 from Retrans Table on exchange 11063i CHIP:SC: Received Sigma2 msg - CHIP:SC: Peer assigned session session ID 2 - CHIP:SC: The device does not support GetClock_RealTimeMS() API. This will eventually result in CASE session setup failures. - CHIP:IN: Generating compressed fabric ID using uncompressed fabric ID 0x0000000000000001 and root pubkey - CHIP:IN: 0x04, 0x6e, 0x3e, 0x58, 0x9d, 0x08, 0xd6, 0xae, - CHIP:IN: 0xe9, 0xff, 0x9b, 0x8f, 0xba, 0x6f, 0x57, 0x73, - CHIP:IN: 0x21, 0xc4, 0xe2, 0x7b, 0x09, 0xe4, 0x24, 0x7f, - CHIP:IN: 0x55, 0x44, 0x3b, 0xf2, 0x7c, 0x13, 0x45, 0x3b, - CHIP:IN: 0x82, 0xa8, 0x42, 0x96, 0xb4, 0x36, 0x78, 0x20, - CHIP:IN: 0xa1, 0x37, 0x69, 0xf0, 0x20, 0xc9, 0x20, 0x7e, - CHIP:IN: 0x66, 0x45, 0x84, 0x53, 0x1b, 0x3e, 0xd2, 0x61, - CHIP:IN: 0xb6, 0x89, 0x27, 0xfd, 0xe8, 0x23, 0x69, 0x6d, - CHIP:IN: 0x93, - CHIP:IN: Generated compressed fabric ID - CHIP:IN: 0xa3, 0x54, 0xab, 0x2a, 0xa2, 0x1f, 0x8e, 0x48, + CHIP:SC: Peer assigned session session ID 24240 CHIP:SC: Found MRP parameters in the message CHIP:SC: Sending Sigma3 - CHIP:EM: Piggybacking Ack for MessageCounter:1066460336 on exchange: 45047i - CHIP:IN: Prepared unauthenticated message 0xaaaad7ce1bf8 to 0x0000000000000000 (0) of type 0x32 and protocolId (0, 0) on exchange 45047i with MessageCounter:2352378412. - CHIP:IN: Sending unauthenticated msg 0xaaaad7ce1bf8 with MessageCounter:2352378412 to 0x0000000000000000 at monotonic time: 315803 msec + CHIP:EM: <<< [E:11063i S:0 M:226454875 (Ack:192590746)] (U) Msg TX to 0:0000000000000000 [0000] [UDP:[fe80::e65f:1ff:fec2:47af%eth0]:5540] --- Type 0000:32 (SecureChannel:CASE_Sigma3) CHIP:SC: Sent Sigma3 msg - CHIP:EM: Received message of type 0x40 with protocolId (0, 0) and MessageCounter:1066460337 on exchange 45047i - CHIP:EM: Found matching exchange: 45047i, Delegate: 0xffffa400f7f8 - CHIP:EM: Rxd Ack; Removing MessageCounter:2352378412 from Retrans Table on exchange 45047i - CHIP:EM: Removed CHIP MessageCounter:2352378412 from RetransTable on exchange 45047i + CHIP:EM: >>> [E:11063i S:0 M:192590747 (Ack:226454875)] (U) Msg RX from 0:0000000000000000 [0000] --- Type 0000:40 (SecureChannel:StatusReport) + CHIP:EM: Found matching exchange: 11063i, Delegate: 0xffff78207b08 + CHIP:EM: Rxd Ack; Removing MessageCounter:226454875 from Retrans Table on exchange 11063i CHIP:SC: Success status report received. Session was established - CHIP:IN: New secure session created for device 0x0000000000000001, LSID:2 PSID:2! + CHIP:SC: SecureSession[0xffff7902f2c0, LSID:28474]: State change 'kEstablishing' --> 'kActive' + CHIP:IN: SecureSession[0xffff7902f2c0]: Activated - Type:2 LSID:28474 + CHIP:IN: New secure session activated for device <00000000000007CE, 1>, LSID:28474 PSID:24240! + CHIP:DIS: OperationalSessionSetup[1:00000000000007CE]: State change 4 --> 5 + CHIP:CTL: Successfully finished commissioning step 'FindOperational' disabled: true - - label: "Step 13: Commissioner sends CommissioningComplete command" + - label: "Step 14: Commissioner sends CommissioningComplete command" verification: | Verify in TH(CHIP-TOOL) - CHIP:CTL: Received CommissioningComplete response - CHIP:CTL: Rendezvous cleanup - CHIP:TOO: Device commissioning completed with success + CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0030 Command=0x0000_0005 + CHIP:CTL: Received CommissioningComplete response, errorCode=0 + CHIP:CTL: Successfully finished commissioning step 'SendComplete' disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_DD_3_6.yaml b/src/app/tests/suites/certification/Test_TC_DD_3_6.yaml index 674808bfabb520..ad24d09cbbb9f8 100644 --- a/src/app/tests/suites/certification/Test_TC_DD_3_6.yaml +++ b/src/app/tests/suites/certification/Test_TC_DD_3_6.yaml @@ -28,6 +28,7 @@ tests: - label: "Note" verification: | Chip-tool command used below are an example to verify the DUT as commissioner test cases. For certification test, we expect DUT should have a capability or way to run the equivalent command. + Test Harness is a Commissionee device that is not connected to an operational network (i.e. Wi-Fi, or Ethernet) and is configured as a Non-concurrent device. disabled: true - label: "Preconditions" @@ -50,9 +51,11 @@ tests: verification: | Verify in TH (ALL-CLUSTER-APP) start BLE Advertising by specific DUT implementation - Verify in DUT(CHIP-TOOL) start commissioning process(need to obtain the Thread dataset first) + Verify in DUT(CHIP-TOOL) start commissioning process (either Thread or WiFi) ./chip-tool pairing ble-thread 1 hex:0e080000000000010000000300000f35060004001fffe0020811111111222222220708fd27e57b1b1e22d9051000112233445566778899aabbccddeeff030e4f70656e54687265616444656d6f01021234041061e1206d2c2b46e079eb775f41fc72190c0402a0fff8 20202021 3840 + ./chip-tool pairing ble-wifi 20202021 3840 + disabled: true - label: @@ -64,6 +67,30 @@ tests: CHIP:SC: Received PBKDF param response disabled: true + - label: + "Step 3a: Commissioner reads commissioning information, including + SupportsConcurrentConnection attribute from General Commissioining + Cluster" + verification: | + Verify in TH that SupportsConcurrentConnection is false + + CHIP:IM: Received Read request + CHIP:DMG: ReadRequestMessage = + CHIP:DMG: { + CHIP:DMG: AttributePathIBs = + CHIP:DMG: [ + CHIP:DMG: AttributePathIB = + CHIP:DMG: { + CHIP:DMG: Endpoint = 0x0, + CHIP:DMG: Cluster = 0x30, + CHIP:DMG: Attribute = 0x0000_0004, + CHIP:DMG: } + CHIP:DMG: + CHIP:DMG: isFabricFiltered = false, + CHIP:DMG: InteractionModelRevision = 11 + CHIP:DMG: }, + disabled: true + - label: "Step 4: Commissioner SHALL re-arm Fail-safe timer on Commissionee within 60s (the autonomously Fail-safe timer length set by @@ -370,15 +397,9 @@ tests: - label: "Step 11: Commissioning channel between the Commissioner and - Commissionee is terminated." + Commissionee is closed, operational channel started." verification: | - Verify the channel was terminated on DUT as commissioner side: - [1651271753284] [23287:743790] CHIP: [CTL] Received CommissioningComplete response - [1651271753284] [23287:743790] CHIP: [CTL] Successfully finished commissioning step 'SendComplete' - [1651271753284] [23287:743790] CHIP: [CTL] Commissioning stage next step: 'SendComplete' -> 'Cleanup' - [1651271753284] [23287:743790] CHIP: [CTL] Performing next commissioning step 'Cleanup' - [1651271753284] [23287:743790] CHIP: [CTL] Successfully finished commissioning step 'Cleanup' - [1651271753284] [23287:743790] CHIP: [TOO] Device commissioning completed with success + Inferred by successful completion of Step 12 disabled: true - label: @@ -387,10 +408,21 @@ tests: verification: | Verify in DUT as commissioner side - CHIP:DL: Avahi resolve found - CHIP:DIS: Node ID resolved for 0x0000000000000001 - CHIP:DIS: Addr 0: [fd11:22::9d96:8fcf:10cf:799e]:5540 - CHIP:CTL: OperationalDiscoveryComplete for device ID 0x0000000000000001 + CHIP:CTL: Performing next commissioning step 'FindOperational' + CHIP:IN: Expiring all sessions for node <00000000000007CE, 1>!! + CHIP:CSM: FindOrEstablishSession: PeerId = [1:00000000000007CE] + CHIP:CSM: FindOrEstablishSession: No existing OperationalSessionSetup instance found + CHIP:DIS: OperationalSessionSetup[1:00000000000007CE]: State change 1 --> 2 + CHIP:DMG: ICR moving to [AwaitingDe] + CHIP:DIS: Checking node lookup status after 200 ms + CHIP:DL: HandlePlatformSpecificBLEEvent 16387 + CHIP:DIS: UDP:[fe80::e65f:1ff:fec2:47af%eth0]:5540: new best score: 7 + CHIP:DIS: Lookup clearing interface for non LL address + CHIP:DIS: UDP:172.16.62.113%eth0:5540: new best score: 2 + CHIP:DIS: Checking node lookup status after 7151 ms + CHIP:DIS: OperationalSessionSetup[1:00000000000007CE]: Updating device address to UDP:[fe80::e65f:1ff:fec2:47af%eth0]:5540 while in state 2 + CHIP:DIS: OperationalSessionSetup[1:00000000000007CE]: State change 2 --> 3 + CHIP:IN: SecureSession[0xffff7902f2c0]: Allocated Type:2 LSID:28474 disabled: true - label: @@ -400,45 +432,35 @@ tests: Verify in DUT as commissioner side CHIP:SC: Sent Sigma1 msg - CHIP:CTL: Address resolved for node: 0x0000000000000001 - CHIP:EM: Received message of type 0x31 with protocolId (0, 0) and MessageCounter:1066460336 on exchange 45047i - CHIP:EM: Found matching exchange: 45047i, Delegate: 0xffffa400f7f8 - CHIP:EM: Rxd Ack; Removing MessageCounter:2352378411 from Retrans Table on exchange 45047i - CHIP:EM: Removed CHIP MessageCounter:2352378411 from RetransTable on exchange 45047i + CHIP:DIS: OperationalSessionSetup[1:00000000000007CE]: State change 3 --> 4 + CHIP:EM: Retransmitting MessageCounter:226454874 on exchange 11063i Send Cnt 1 + CHIP:EM: Retransmitting MessageCounter:226454874 on exchange 11063i Send Cnt 2 + CHIP:EM: Retransmitting MessageCounter:226454874 on exchange 11063i Send Cnt 3 + CHIP:EM: >>> [E:11063i S:0 M:192590746 (Ack:226454874)] (U) Msg RX from 0:0000000000000000 [0000] --- Type 0000:31 (SecureChannel:CASE_Sigma2) + CHIP:EM: Found matching exchange: 11063i, Delegate: 0xffff78207b08 + CHIP:EM: Rxd Ack; Removing MessageCounter:226454874 from Retrans Table on exchange 11063i CHIP:SC: Received Sigma2 msg - CHIP:SC: Peer assigned session session ID 2 - CHIP:SC: The device does not support GetClock_RealTimeMS() API. This will eventually result in CASE session setup failures. - CHIP:IN: Generating compressed fabric ID using uncompressed fabric ID 0x0000000000000001 and root pubkey - CHIP:IN: 0x04, 0x6e, 0x3e, 0x58, 0x9d, 0x08, 0xd6, 0xae, - CHIP:IN: 0xe9, 0xff, 0x9b, 0x8f, 0xba, 0x6f, 0x57, 0x73, - CHIP:IN: 0x21, 0xc4, 0xe2, 0x7b, 0x09, 0xe4, 0x24, 0x7f, - CHIP:IN: 0x55, 0x44, 0x3b, 0xf2, 0x7c, 0x13, 0x45, 0x3b, - CHIP:IN: 0x82, 0xa8, 0x42, 0x96, 0xb4, 0x36, 0x78, 0x20, - CHIP:IN: 0xa1, 0x37, 0x69, 0xf0, 0x20, 0xc9, 0x20, 0x7e, - CHIP:IN: 0x66, 0x45, 0x84, 0x53, 0x1b, 0x3e, 0xd2, 0x61, - CHIP:IN: 0xb6, 0x89, 0x27, 0xfd, 0xe8, 0x23, 0x69, 0x6d, - CHIP:IN: 0x93, - CHIP:IN: Generated compressed fabric ID - CHIP:IN: 0xa3, 0x54, 0xab, 0x2a, 0xa2, 0x1f, 0x8e, 0x48, + CHIP:SC: Peer assigned session session ID 24240 CHIP:SC: Found MRP parameters in the message CHIP:SC: Sending Sigma3 - CHIP:EM: Piggybacking Ack for MessageCounter:1066460336 on exchange: 45047i - CHIP:IN: Prepared unauthenticated message 0xaaaad7ce1bf8 to 0x0000000000000000 (0) of type 0x32 and protocolId (0, 0) on exchange 45047i with MessageCounter:2352378412. - CHIP:IN: Sending unauthenticated msg 0xaaaad7ce1bf8 with MessageCounter:2352378412 to 0x0000000000000000 at monotonic time: 315803 msec + CHIP:EM: <<< [E:11063i S:0 M:226454875 (Ack:192590746)] (U) Msg TX to 0:0000000000000000 [0000] [UDP:[fe80::e65f:1ff:fec2:47af%eth0]:5540] --- Type 0000:32 (SecureChannel:CASE_Sigma3) CHIP:SC: Sent Sigma3 msg - CHIP:EM: Received message of type 0x40 with protocolId (0, 0) and MessageCounter:1066460337 on exchange 45047i - CHIP:EM: Found matching exchange: 45047i, Delegate: 0xffffa400f7f8 - CHIP:EM: Rxd Ack; Removing MessageCounter:2352378412 from Retrans Table on exchange 45047i - CHIP:EM: Removed CHIP MessageCounter:2352378412 from RetransTable on exchange 45047i + CHIP:EM: >>> [E:11063i S:0 M:192590747 (Ack:226454875)] (U) Msg RX from 0:0000000000000000 [0000] --- Type 0000:40 (SecureChannel:StatusReport) + CHIP:EM: Found matching exchange: 11063i, Delegate: 0xffff78207b08 + CHIP:EM: Rxd Ack; Removing MessageCounter:226454875 from Retrans Table on exchange 11063i CHIP:SC: Success status report received. Session was established - CHIP:IN: New secure session created for device 0x0000000000000001, LSID:2 PSID:2! + CHIP:SC: SecureSession[0xffff7902f2c0, LSID:28474]: State change 'kEstablishing' --> 'kActive' + CHIP:IN: SecureSession[0xffff7902f2c0]: Activated - Type:2 LSID:28474 + CHIP:IN: New secure session activated for device <00000000000007CE, 1>, LSID:28474 PSID:24240! + CHIP:DIS: OperationalSessionSetup[1:00000000000007CE]: State change 4 --> 5 + CHIP:CTL: Successfully finished commissioning step 'FindOperational' disabled: true disabled: true - label: "Step 14: Commissioner sends CommissioningComplete command" verification: | Verify in DUT as commissioner side - CHIP:CTL: Received CommissioningComplete response - CHIP:CTL: Rendezvous cleanup - CHIP:TOO: Device commissioning completed with success + CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0030 Command=0x0000_0005 + CHIP:CTL: Received CommissioningComplete response, errorCode=0 + CHIP:CTL: Successfully finished commissioning step 'SendComplete' disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_DD_3_8.yaml b/src/app/tests/suites/certification/Test_TC_DD_3_8.yaml index 8410f4c0aab5eb..e9f48c1652e4a0 100644 --- a/src/app/tests/suites/certification/Test_TC_DD_3_8.yaml +++ b/src/app/tests/suites/certification/Test_TC_DD_3_8.yaml @@ -29,6 +29,7 @@ tests: - label: "Note" verification: | Chip-tool command used below are an example to verify the DUT as commissioner test cases. For certification test, we expect DUT should have a capability or way to run the equivalent command. + Test Harness is a Commissionee device that is not connected to an operational network (i.e. Wi-Fi, or Ethernet) and is configured as a Non-concurrent device. disabled: true - label: "Preconditions" @@ -50,9 +51,10 @@ tests: verification: | Verify in TH as server side: start BLE Advertising by specific DUT implementation - Verify in DUT as client side: start commissioning process(need to obtain the Thread dataset first) + Verify in DUT as client side: start commissioning process (either Thread or WiFi) ./chip-tool pairing ble-thread 1 hex:0e080000000000010000000300000f35060004001fffe0020811111111222222220708fd27e57b1b1e22d9051000112233445566778899aabbccddeeff030e4f70656e54687265616444656d6f01021234041061e1206d2c2b46e079eb775f41fc72190c0402a0fff8 20202021 3840 + ./chip-tool pairing ble-wifi 20202021 3840 disabled: true - label: @@ -64,6 +66,30 @@ tests: CHIP:SC: Received PBKDF param response disabled: true + - label: + "Step 3a: Commissioner reads commissioning information, including + SupportsConcurrentConnection attribute from General Commissioning + Cluster" + verification: | + Verify in TH that SupportsConcurrentConnection is false + + CHIP:IM: Received Read request + CHIP:DMG: ReadRequestMessage = + CHIP:DMG: { + CHIP:DMG: AttributePathIBs = + CHIP:DMG: [ + CHIP:DMG: AttributePathIB = + CHIP:DMG: { + CHIP:DMG: Endpoint = 0x0, + CHIP:DMG: Cluster = 0x30, + CHIP:DMG: Attribute = 0x0000_0004, + CHIP:DMG: } + CHIP:DMG: + CHIP:DMG: isFabricFiltered = false, + CHIP:DMG: InteractionModelRevision = 11 + CHIP:DMG: }, + disabled: true + - label: "Step 4: Commissioner SHALL re-arm Fail-safe timer on Commissionee within 60s (the autonomously Fail-safe timer length set by @@ -372,18 +398,18 @@ tests: "Step 11: Commissioning channel between the Commissioner and Commissionee is terminated." verification: | - 1. Verify the channel was terminated on DUT=chip-tool - [1651271753284] [23287:743790] CHIP: [CTL] Received CommissioningComplete response - [1651271753284] [23287:743790] CHIP: [CTL] Successfully finished commissioning step 'SendComplete' - [1651271753284] [23287:743790] CHIP: [CTL] Commissioning stage next step: 'SendComplete' -> 'Cleanup' - [1651271753284] [23287:743790] CHIP: [CTL] Performing next commissioning step 'Cleanup' - [1651271753284] [23287:743790] CHIP: [CTL] Successfully finished commissioning step 'Cleanup' - [1651271753284] [23287:743790] CHIP: [TOO] Device commissioning completed with success + Verify in TH + + CHIP:SVR: Received kCloseAllBleConnections:32777 + CHIP:IN: Clearing BLE pending packets. + CHIP:BLE: Releasing end point's BLE connection back to application. + CHIP:BLE: Got notification regarding chip connection closure + CHIP:DL: wpa_supplicant: Start WiFi management disabled: true - label: "Step 12: Reboot TH and prepare for commissioning" verification: | - 1. Using TH=all-clusters-app, exit the app, re-launch app + 1. Using TH=all-clusters-app in non-concurrent mode, exit the app, re-launch app disabled: true - label: diff --git a/src/app/tests/suites/certification/Test_TC_DEMM_1_1.yaml b/src/app/tests/suites/certification/Test_TC_DEMM_1_1.yaml new file mode 100644 index 00000000000000..832b21e12ac63b --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_DEMM_1_1.yaml @@ -0,0 +1,116 @@ +# 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. + +name: 241.1.1. [TC-DEMM-1.1] Global attributes with DUT as Server + +PICS: + - DEMM.S + +config: + nodeId: 0x12344321 + cluster: "Device Energy Management Mode" + endpoint: 1 + +tests: + - label: + "Step 1: Commission DUT to TH (can be skipped if done in a preceding + test)." + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 2: TH reads from the DUT the ClusterRevision attribute" + command: "readAttribute" + attribute: "ClusterRevision" + response: + value: 1 + constraints: + type: int16u + + #https://github.com/project-chip/connectedhomeip/issues/31599 + - label: "Step 3: TH reads from the DUT the FeatureMap attribute" + verification: | + ./chip-tool deviceenergymanagementmode read feature-map 1 1 + + On the TH(Chip-tool) Log, Verify featureMap value is 0 and below is the sample log provided for the raspi platform: + + [1705923720.577354][23553:23555] CHIP:DMG: } + [1705923720.577393][23553:23555] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_009F Attribute 0x0000_FFFC DataVersion: 2217281174 + [1705923720.577412][23553:23555] CHIP:TOO: FeatureMap: 1 + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_SKIP_SAMPLE_APP + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: "Step 4: TH reads from the DUT the AttributeList attribute." + PICS: PICS_EVENT_LIST_ENABLED + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [0, 1, 65528, 65529, 65530, 65531, 65532, 65533] + + - label: "Step 4a: TH reads from the DUT the AttributeList attribute." + PICS: "!PICS_EVENT_LIST_ENABLED" + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [0, 1, 65528, 65529, 65531, 65532, 65533] + + - label: + "Step 4b: TH reads optional attribute (StartUpMode) in AttributeList + from DUT" + PICS: DEMM.S.A0002 + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [2] + + - label: "Step 5: TH reads from the DUT the EventList attribute." + PICS: PICS_EVENT_LIST_ENABLED + command: "readAttribute" + attribute: "EventList" + response: + value: [] + constraints: + type: list + + - label: "Step 6: TH reads from the DUT the AcceptedCommandList attribute." + command: "readAttribute" + attribute: "AcceptedCommandList" + response: + value: [0] + constraints: + type: list + + - label: "Step 7: TH reads from the DUT the GeneratedCommandList attribute." + command: "readAttribute" + attribute: "GeneratedCommandList" + response: + value: [1] + constraints: + type: list diff --git a/src/app/tests/suites/certification/Test_TC_DEMM_1_2.yaml b/src/app/tests/suites/certification/Test_TC_DEMM_1_2.yaml new file mode 100644 index 00000000000000..55aa1400ec1ac5 --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_DEMM_1_2.yaml @@ -0,0 +1,112 @@ +# 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. +# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default + +name: 241.1.2. [TC-DEMM-1.2] Cluster attributes with DUT as Server + +PICS: + - DEMM.S + +config: + nodeId: 0x12344321 + cluster: "Basic Information" + endpoint: 1 + +tests: + - label: "Step 1: TH reads from the DUT the SupportedModes attribute" + PICS: DEMM.S.A0000 + verification: | + ./chip-tool deviceenergymanagementmode read supported-modes 1 1 + + - Verify that the DUT response contains a list of ModeOptionsStruct entries + - Verify that the list has at least 2 and at most 255 entries + - Verify that each ModeOptionsStruct entry has a unique Mode field value + - Verify that each ModeOptionsStruct entry has a unique Label field value + - Verify that each ModeOptionsStruct entry’s ModeTags field has: + at least one entry the values of the Value fields that are not larger than 16 bits + - for each Value field: Is the mode tag value a defined common tag value (Auto(0x0000), Quick(0x0001), Quiet(0x0002), LowNoise(0x0003), LowEnergy(0x0004), Vacation(0x0005), Min(0x0006), Max(0x0007), Night(0x0008), Day(0x0009)) or a defined cluster-derived tag value (No Optimization, Device Optimization, Local Optimization, Grid Optimization) or in the MfgTags (0x8000 to 0xBFFF) range + - for at least one Value field: Is the mode tag value a defined common tag value (Auto(0x0000), Quick(0x0001), Quiet(0x0002), LowNoise(0x0003), LowEnergy(0x0004), Vacation(0x0005), Min(0x0006), Max(0x0007), Night(0x0008), Day(0x0009)) or a derived cluster value (RapidCool, RapidFreeze) + - if the Value field is in the MfgTags (0x8000 to 0xBFFF) range, the TagName field is a string with a length between 1 and 64 + - Verify that at least one ModeOptionsStruct entry includes either the RapidCool semantic tag or the RapidFreeze semantic tag in the SemanticTags field + - Save the Mode field values as supported_modes_dut on the TH (Chip-tool) and below is the sample log provided for the raspi platform: + + + [1705923890.093456][23589:23591] CHIP:DMG: } + [1705923890.094137][23589:23591] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_009F Attribute 0x0000_0000 DataVersion: 2217281174 + [1705923890.094312][23589:23591] CHIP:TOO: SupportedModes: 5 entries + [1705923890.094403][23589:23591] CHIP:TOO: [1]: { + [1705923890.094423][23589:23591] CHIP:TOO: Label: No energy management (forecast only) + [1705923890.094458][23589:23591] CHIP:TOO: Mode: 0 + [1705923890.094483][23589:23591] CHIP:TOO: ModeTags: 1 entries + [1705923890.094513][23589:23591] CHIP:TOO: [1]: { + [1705923890.094531][23589:23591] CHIP:TOO: Value: 16384 + [1705923890.094542][23589:23591] CHIP:TOO: } + [1705923890.094552][23589:23591] CHIP:TOO: } + [1705923890.094579][23589:23591] CHIP:TOO: [2]: { + [1705923890.094590][23589:23591] CHIP:TOO: Label: Device optimizes (no local or grid control) + [1705923890.094601][23589:23591] CHIP:TOO: Mode: 1 + [1705923890.094615][23589:23591] CHIP:TOO: ModeTags: 1 entries + [1705923890.094632][23589:23591] CHIP:TOO: [1]: { + [1705923890.094642][23589:23591] CHIP:TOO: Value: 16385 + [1705923890.094653][23589:23591] CHIP:TOO: } + [1705923890.094664][23589:23591] CHIP:TOO: } + [1705923890.094687][23589:23591] CHIP:TOO: [3]: { + [1705923890.094697][23589:23591] CHIP:TOO: Label: Optimized within building + [1705923890.094706][23589:23591] CHIP:TOO: Mode: 2 + [1705923890.094722][23589:23591] CHIP:TOO: ModeTags: 2 entries + [1705923890.094738][23589:23591] CHIP:TOO: [1]: { + [1705923890.094748][23589:23591] CHIP:TOO: Value: 16386 + [1705923890.094759][23589:23591] CHIP:TOO: } + [1705923890.094773][23589:23591] CHIP:TOO: [2]: { + [1705923890.094784][23589:23591] CHIP:TOO: Value: 16385 + [1705923890.094794][23589:23591] CHIP:TOO: } + [1705923890.094804][23589:23591] CHIP:TOO: } + [1705923890.094827][23589:23591] CHIP:TOO: [4]: { + [1705923890.094836][23589:23591] CHIP:TOO: Label: Optimized for grid + [1705923890.094846][23589:23591] CHIP:TOO: Mode: 3 + [1705923890.094861][23589:23591] CHIP:TOO: ModeTags: 2 entries + [1705923890.094876][23589:23591] CHIP:TOO: [1]: { + [1705923890.094886][23589:23591] CHIP:TOO: Value: 16385 + [1705923890.094893][23589:23591] CHIP:TOO: } + [1705923890.094908][23589:23591] CHIP:TOO: [2]: { + [1705923890.094917][23589:23591] CHIP:TOO: Value: 16387 + [1705923890.094927][23589:23591] CHIP:TOO: } + [1705923890.094935][23589:23591] CHIP:TOO: } + [1705923890.094960][23589:23591] CHIP:TOO: [5]: { + [1705923890.094971][23589:23591] CHIP:TOO: Label: Optimized for grid and building + [1705923890.094980][23589:23591] CHIP:TOO: Mode: 4 + [1705923890.094998][23589:23591] CHIP:TOO: ModeTags: 3 entries + [1705923890.095013][23589:23591] CHIP:TOO: [1]: { + [1705923890.095022][23589:23591] CHIP:TOO: Value: 16386 + [1705923890.095032][23589:23591] CHIP:TOO: } + [1705923890.095047][23589:23591] CHIP:TOO: [2]: { + [1705923890.095057][23589:23591] CHIP:TOO: Value: 16385 + [1705923890.095066][23589:23591] CHIP:TOO: } + [1705923890.095080][23589:23591] CHIP:TOO: [3]: { + [1705923890.095090][23589:23591] CHIP:TOO: Value: 16387 + [1705923890.095099][23589:23591] CHIP:TOO: } + [1705923890.095109][23589:23591] CHIP:TOO: } + disabled: true + + - label: "Step 2: TH reads from the DUT the CurrentMode attribute" + PICS: DEMM.S.A0001 + verification: | + ./chip-tool deviceenergymanagementmode read current-mode 1 1 + + Verify on TH(chip-tool) logs, CurrentMode attribute value is an integer value from supported_modes_dut, below is the sample log provided for the raspi platform, Here CurrentMode attribute value is 0 + + [1705923927.418159][23602:23604] CHIP:DMG: } + [1705923927.418327][23602:23604] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_009F Attribute 0x0000_0001 DataVersion: 2217281174 + [1705923927.418389][23602:23604] CHIP:TOO: CurrentMode: 0 + disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_DEMM_2_1.yaml b/src/app/tests/suites/certification/Test_TC_DEMM_2_1.yaml new file mode 100644 index 00000000000000..a6141163a115fe --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_DEMM_2_1.yaml @@ -0,0 +1,219 @@ +# 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. + +name: 241.2.1. [TC-DEMM-2.1] Change to Mode functionality with DUT as Server + +PICS: + - DEMM.S + +config: + nodeId: 0x12344321 + cluster: "Device Energy Management Mode" + endpoint: 1 + + #PIXIT.DEMM.MODE_CHANGE_OK + PIXIT.DEMM.MODE_CHANGE_OK: + type: int8u + defaultValue: 2 + #PIXIT.DEMM.MODE_CHANGE_FAIL + PIXIT.DEMM.MODE_CHANGE_FAIL: + type: int8u + defaultValue: 10 + invalid_mode_th: + type: int8u + defaultValue: 15 + +tests: + - label: "Step 1: Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 2: TH reads from the DUT the SupportedModes attribute." + PICS: DEMM.S.A0000 + command: "readAttribute" + attribute: "SupportedModes" + response: + saveAs: supported_mode_dut + constraints: + type: list + minLength: 2 + + - label: "Step 3: TH reads from the DUT the CurrentMode attribute." + PICS: DEMM.S.A0001 + command: "readAttribute" + attribute: "CurrentMode" + response: + saveAs: old_current_mode_dut + constraints: + type: int8u + minValue: 0 + maxValue: 255 + + - label: + "Step 4: TH sends a ChangeToMode command to the DUT with NewMode set + to old_current_mode_dut" + PICS: DEMM.S.C00.Rsp + command: "ChangeToMode" + arguments: + values: + - name: "NewMode" + value: old_current_mode_dut + response: + values: + - name: "Status" + value: 0x00 + + - label: + "Step 5: Manually put the device in a state from which it will FAIL to + transition to PIXIT.DEMM.MODE_CHANGE_FAIL" + PICS: + DEMM.S.M.CAN_TEST_MODE_FAILURE && DEMM.S.M.CAN_MANUALLY_CONTROLLED && + PICS_SKIP_SAMPLE_APP + verification: | + Manual operation required + cluster: "LogCommands" + command: "UserPrompt" + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: "Step 6: TH reads from the DUT the CurrentMode attribute" + PICS: DEMM.S.A0001 && DEMM.S.M.CAN_MANUALLY_CONTROLLED + command: "readAttribute" + attribute: "CurrentMode" + response: + saveAs: Step6_current_mode_dut + constraints: + type: int8u + minValue: 0 + maxValue: 255 + + #Skipping test-7 because SDK is not enabled with this failure response + - label: + "Step 7: TH sends a ChangeToMode command to the DUT with NewMode set + to PIXIT.DEMM.MODE_CHANGE_FAIL" + PICS: + DEMM.S.M.CAN_TEST_MODE_FAILURE && DEMM.S.C00.Rsp && + PICS_SKIP_SAMPLE_APP + verification: | + Note : Please skip this step as SDK is not enabled with this failure response + + ./chip-tool energyevsemode change-to-mode 2 1 1 + + Verify on TH(chip-tool) log, DUT responds contains a ChangeToModeResponse command with Status field is set to GenericFailure(0x02), InvalidInMode(0x03) , or in the MfgCodes (0x80 to 0xBF) range and StatusText field has a length between 1 and 64, below is the sample log provided for the raspi platform: + + [1705995550.805161][7567:7569] CHIP:DMG: }, + [1705995550.805185][7567:7569] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_009D Command=0x0000_0001 + [1705995550.805197][7567:7569] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_009D Command 0x0000_0001 + [1705995550.805221][7567:7569] CHIP:TOO: ChangeToModeResponse: { + [1705995550.805228][7567:7569] CHIP:TOO: status: 0 + [1705995550.805232][7567:7569] CHIP:TOO: } + cluster: "LogCommands" + command: "UserPrompt" + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: "Step 8: TH reads from the DUT the CurrentMode attribute." + PICS: DEMM.S.A0001 + command: "readAttribute" + attribute: "CurrentMode" + response: + value: old_current_mode_dut + constraints: + type: int8u + + - label: + "Step 9: Manually put the device in a state from which it will + SUCCESSFULLY transition to PIXIT.DEMM.MODE_CHANGE_OK" + PICS: PICS_SKIP_SAMPLE_APP && DEMM.S.M.CAN_MANUALLY_CONTROLLED + verification: | + Manual operation required + cluster: "LogCommands" + command: "UserPrompt" + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: "Step 10: TH reads from the DUT the CurrentMode attribute." + PICS: DEMM.S.A0001 && DEMM.S.M.CAN_MANUALLY_CONTROLLED + command: "readAttribute" + attribute: "CurrentMode" + response: + saveAs: Step10_current_mode_dut + constraints: + type: int8u + minValue: 0 + maxValue: 255 + + - label: + "Step 11: TH sends a ChangeToMode command to the DUT with NewMode set + to PIXIT.DEMM.MODE_CHANGE_OK" + PICS: DEMM.S.C00.Rsp + command: "ChangeToMode" + arguments: + values: + - name: "NewMode" + value: PIXIT.DEMM.MODE_CHANGE_OK + response: + values: + - name: "Status" + value: 0x00 + + - label: + "Step 12: TH reads from the DUT the CurrentMode attribute. Verify that + the DUT response contains an integer value equal to + PIXIT.RVCRUNM.MODE_CHANGE_OK" + PICS: DEMM.S.A0001 + command: "readAttribute" + attribute: "CurrentMode" + response: + value: PIXIT.DEMM.MODE_CHANGE_OK + + - label: + "Step 13: TH sends a ChangeToMode command to the DUT with NewMode set + to invalid_mode_th" + PICS: DEMM.S.C00.Rsp + command: "ChangeToMode" + arguments: + values: + - name: "NewMode" + value: invalid_mode_th + response: + values: + - name: "Status" + value: 0x01 + + - label: + "Step 14: TH reads from the DUT the CurrentMode attribute. Verify that + the DUT response contains an integer value equal to + PIXIT.RVCRUNM.MODE_CHANGE_OK" + PICS: DEMM.S.A0001 + command: "readAttribute" + attribute: "CurrentMode" + response: + value: PIXIT.DEMM.MODE_CHANGE_OK diff --git a/src/app/tests/suites/certification/Test_TC_DESC_2_1.yaml b/src/app/tests/suites/certification/Test_TC_DESC_2_1.yaml index 8778cc209883b5..734282a82e7ca8 100644 --- a/src/app/tests/suites/certification/Test_TC_DESC_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_DESC_2_1.yaml @@ -79,7 +79,7 @@ tests: For all the Endpoint’s listed from the previous step run the following steps. The device type should correspond to the id value in the device_type.json Chip tool outputs all values in integer, convert to hex before comparing. - ./chip-tool descriptor read parts-list 1 1 + ./chip-tool descriptor read parts-list 1 1 Verify parts-list response contains 0 entries on the TH (Chip-tool) and below is the sample log provided for the raspi platform: @@ -88,11 +88,10 @@ tests: ./chip-tool descriptor read device-type-list 1 1 - On TH (Chip-tool) log, Verify that - - If PartsLists count is 0 then, DeviceTypeList count is at least one. - - DeviceTypeList should contains exactly one Application Device Type [In below log 256(In hex 0x100) is a Application Device Type(On/OffLight)] or set of Application Device Types which are a subset of each other. - - DeviceTypeList may contain one or more Utility Device Types, but not Root Node Device Type.[In below log DeviceType: 17(In hex 0x0011) is a Utility DeviceType ] - - Revision value is not less than 1 and it should match the Revision of the DeviceType and below is the sample log provided for the raspi platform + On TH (Chip-tool) log, Verify that the DeviceTypeList count is at least one. + - If the DeviceTypeList contains more than one Application Device Type, verify that all the Application Device Types are part of the same superset. + - Verify the DeviceTypeList does not contain the Root Node Device Type. + - Revision value is not less than 1 and it should match the Revision of the DeviceType and below is the sample log provided for the raspi platform [1674552599.264189][21135:21137] CHIP:DMG: } [1692617790.900384][31584:31586] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_001D Attribute 0x0000_0000 DataVersion: 2832593371 @@ -106,7 +105,7 @@ tests: [1692617790.900428][31584:31586] CHIP:TOO: Revision: 1 [1692617790.900430][31584:31586] CHIP:TOO: } - ./chip-tool descriptor read parts-list 1 2 + ./chip-tool descriptor read parts-list 1 2 Verify parts-list response contains 0 entries on the TH (Chip-tool) and below is the sample log provided for the raspi platform: @@ -115,11 +114,10 @@ tests: ./chip-tool descriptor read device-type-list 1 2 - On TH (Chip-tool) log, Verify that - - If PartsLists count is 0 then, DeviceTypeList count is at least one. - - DeviceTypeList should contains exactly one Application Device Type [In below log 256(In hex 0x100) is a Application Device Type(On/OffLight)] or set of Application Device Types which are a subset of each other. - - DeviceTypeList may contain one or more Utility Device Types, but not Root Node Device Type.[In below log DeviceType: 17(In hex 0x0011) is a Utility DeviceType ] - - Revision value is not less than 1 and it should match the Revision of the DeviceType and below is the sample log provided for the raspi platform + On TH (Chip-tool) log, Verify that the DeviceTypeList count is at least one. + - If the DeviceTypeList contains more than one Application Device Type, verify that all the Application Device Types are part of the same superset. + - Verify the DeviceTypeList does not contain the Root Node Device Type. + - Revision value is not less than 1 and it should match the Revision of the DeviceType and below is the sample log provided for the raspi platform [1692618454.794870][31669:31671] CHIP:TOO: Endpoint: 2 Cluster: 0x0000_001D Attribute 0x0000_0000 DataVersion: 1103199808 [1692618454.794946][31669:31671] CHIP:TOO: DeviceTypeList: 2 entries diff --git a/src/app/tests/suites/certification/Test_TC_DISHM_1_1.yaml b/src/app/tests/suites/certification/Test_TC_DISHM_1_1.yaml index 24ac427a2cb9c8..da8a0924274e9e 100644 --- a/src/app/tests/suites/certification/Test_TC_DISHM_1_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_DISHM_1_1.yaml @@ -46,7 +46,7 @@ tests: verification: | ./chip-tool dishwashermode read feature-map 1 1 - On the TH(Chip-tool) Log, Verify featureMap value is 1 If DISHM.S.F00(DEPONOFF) is true, Otherwise 0, and below is the sample log provided for the raspi platform: + On the TH(Chip-tool) Log, Verify featureMap value is 0 and below is the sample log provided for the raspi platform: [1690365613.351850][27441:27443] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0059 Attribute 0x0000_FFFC DataVersion: 1130015440 [1690365613.351911][27441:27443] CHIP:TOO: FeatureMap: 1 @@ -58,8 +58,7 @@ tests: Verify the "AttributeList " should include the mandatory attributes (values 0, 1), - Global attributes (value 65533, 65532, 65531, 65529 and 65528) and - - List may include optional attribute(value 0x0002), if DISHM.S.A0002(StartUpMode) supports, - - List contains feature dependent attribute (values 0x0003), if DISHM.S.F00(DEPONOFF) is true on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: + - List may include optional attribute(value 0x0002), if DISHM.S.A0002(StartUpMode) supports, on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: [1696402605.599359][7921:7923] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0059 Attribute 0x0000_FFFB DataVersion: 712950283 [1696402605.599377][7921:7923] CHIP:TOO: AttributeList: 9 entries diff --git a/src/app/tests/suites/certification/Test_TC_DISHM_1_2.yaml b/src/app/tests/suites/certification/Test_TC_DISHM_1_2.yaml index 17ee54b3df5fc7..0bb760685297ef 100644 --- a/src/app/tests/suites/certification/Test_TC_DISHM_1_2.yaml +++ b/src/app/tests/suites/certification/Test_TC_DISHM_1_2.yaml @@ -91,25 +91,3 @@ tests: [1689997642.999367][360160:360162] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0059 Attribute 0x0000_0001 DataVersion: 1994417976 [1689997642.999395][360160:360162] CHIP:TOO: CurrentMode: 0 disabled: true - - - label: "Step 4: TH reads from the DUT the OnMode attribute." - PICS: DISHM.S.A0003 - verification: | - ./chip-tool dishwashermode read on-mode 1 1 - - Verify on TH(chip-tool) logs, OnMode attribute value is an integer from supported_modes_dut or null, below is the sample log provided for the raspi platform, Here OnMode attribute value is Null - - [1649676072.465968][10754:10759] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0059 Attribute 0x0000_0003 DataVersion: 4277065072 - [1649676072.466094][10754:10759] CHIP:TOO: OnMode: null - disabled: true - - - label: "Step 5: TH reads from the DUT the StartUpMode attribute." - PICS: DISHM.S.A0002 - verification: | - ./chip-tool dishwashermode read start-up-mode 1 1 - - Verify on TH(chip-tool) logs, StartUpMode attribute value is an integer from supported_modes_dut or null, below is the sample log provided for the raspi platform, Here StartUpMode attribute value is Null - - [1689997956.636092][360258:360260] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0059 Attribute 0x0000_0002 DataVersion: 1994417976 - [1689997956.636125][360258:360260] CHIP:TOO: StartUpMode: null - disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_DISHM_2_1.yaml b/src/app/tests/suites/certification/Test_TC_DISHM_2_1.yaml index 5741789c5dd3f9..2d7ad1388505e5 100644 --- a/src/app/tests/suites/certification/Test_TC_DISHM_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_DISHM_2_1.yaml @@ -13,7 +13,7 @@ # limitations under the License. # Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default -name: 263.3.1. [TC-DISHM-2.1] Change to Mode functionality with DUT as Server +name: 263.3.1. [TC-DISHM-2.1] Change to Mode functionality with DUT as Server PICS: - DISHM.S @@ -135,7 +135,8 @@ tests: ./chip-tool dishwashermode change-to-mode 2 1 1 - Verify on TH(chip-tool) log, DUT responds contains a ChangeToModeResponse command with a GenericFailure(0x02) status response and below is the sample log provided for the raspi platform: + Verify on TH(chip-tool) log, DUT responds contains a ChangeToModeResponse command with + Status field is set to GenericFailure(0x02), InvalidInMode(0x03) , or in the MfgCodes (0x80 to 0xBF) range and StatusText field has a length between 1 and 64, below is the sample log provided for the raspi platform: [1690264785.719168][29854:29856] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0059 Command=0x0000_0001 [1690264785.719200][29854:29856] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0059 Command 0x0000_0001 diff --git a/src/app/tests/suites/certification/Test_TC_DISHM_3_1.yaml b/src/app/tests/suites/certification/Test_TC_DISHM_3_1.yaml index 7d00383866d22b..5b3cbf40b3b5d5 100644 --- a/src/app/tests/suites/certification/Test_TC_DISHM_3_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_DISHM_3_1.yaml @@ -17,7 +17,7 @@ name: 263.4.1. [TC-DISHM-3.1] On Mode functionality with DUT as Server PICS: - DISHM.S.A0003 - - DISHM.S.F00 + - MOD.S.F00 - OO.S.C00.Rsp - OO.S.C01.Rsp @@ -95,7 +95,7 @@ tests: disabled: true - label: "Step 2: TH reads from the DUT the OnMode attribute." - PICS: DISHM.S.A0003 && DISHM.S.F00 + PICS: DISHM.S.A0003 && MOD.S.F00 verification: | ./chip-tool dishwashermode read on-mode 1 1 @@ -107,7 +107,7 @@ tests: disabled: true - label: "Step 3: TH reads from the DUT the CurrentMode attribute." - PICS: DISHM.S.A0001 && DISHM.S.F00 + PICS: DISHM.S.A0001 && MOD.S.F00 verification: | ./chip-tool dishwashermode read current-mode 1 1 @@ -121,7 +121,7 @@ tests: disabled: true - label: "Step 4: TH reads from the DUT the SupportedModes attribute." - PICS: DISHM.S.A0000 && DISHM.S.F00 + PICS: DISHM.S.A0000 && MOD.S.F00 verification: | ./chip-tool dishwashermode read supported-modes 1 1 @@ -171,7 +171,7 @@ tests: - label: "Step 5: TH sends a ChangeToMode command to the DUT with NewMode set to new_mode_th" - PICS: DISHM.S.C00.Rsp && DISHM.S.F00 + PICS: DISHM.S.C00.Rsp && MOD.S.F00 verification: | ./chip-tool dishwashermode change-to-mode 2 1 1 @@ -184,7 +184,7 @@ tests: disabled: true - label: "Step 6: TH sends a Off command to the DUT" - PICS: OO.S.C00.Rsp && DISHM.S.F00 + PICS: OO.S.C00.Rsp && MOD.S.F00 verification: | ./chip-tool onoff off 1 1 @@ -196,7 +196,7 @@ tests: disabled: true - label: "Step 7: TH sends a On command to the DUT" - PICS: OO.S.C01.Rsp && DISHM.S.F00 + PICS: OO.S.C01.Rsp && MOD.S.F00 verification: | ./chip-tool onoff on 1 1 @@ -208,7 +208,7 @@ tests: disabled: true - label: "Step 8: TH reads from the DUT the CurrentMode attribute." - PICS: DISHM.S.A0001 && DISHM.S.F00 + PICS: DISHM.S.A0001 && MOD.S.F00 verification: | ./chip-tool dishwashermode read current-mode 1 1 diff --git a/src/app/tests/suites/certification/Test_TC_DISHM_3_2.yaml b/src/app/tests/suites/certification/Test_TC_DISHM_3_2.yaml index 9043b8f8f31d9c..c53124e903fb7a 100644 --- a/src/app/tests/suites/certification/Test_TC_DISHM_3_2.yaml +++ b/src/app/tests/suites/certification/Test_TC_DISHM_3_2.yaml @@ -26,7 +26,7 @@ config: tests: - label: "Preconditions" verification: | - !DISHM.S.F00(DEPONOFF) | OnOff cluster’s StartUpOnOff attribute is NULL | StartUpOnOff is 0 | OnMode is NULL + !DISHM.S.F00 | OnOff cluster’s StartUpOnOff attribute is NULL | StartUpOnOff is 0 | OnMode is NULL disabled: true - label: "Note" diff --git a/src/app/tests/suites/certification/Test_TC_DISHM_3_3.yaml b/src/app/tests/suites/certification/Test_TC_DISHM_3_3.yaml index 6a34bb32cd7cb2..c9e788d45a6eef 100644 --- a/src/app/tests/suites/certification/Test_TC_DISHM_3_3.yaml +++ b/src/app/tests/suites/certification/Test_TC_DISHM_3_3.yaml @@ -20,7 +20,7 @@ name: PICS: - DISHM.S.A0002 - DISHM.S.A0003 - - DISHM.S.F00 + - MOD.S.F00 - OO.S.A4003 config: @@ -221,7 +221,7 @@ tests: disabled: true - label: "Step 8: TH reads from the DUT the OnMode attribute." - PICS: DISHM.S.A0003 && DISHM.S.F00 + PICS: DISHM.S.A0003 && MOD.S.F00 verification: | ./chip-tool dishwashermode read on-mode 1 1 diff --git a/src/app/tests/suites/certification/Test_TC_DRLK_2_1.yaml b/src/app/tests/suites/certification/Test_TC_DRLK_2_1.yaml index a1a9ac16364702..e84b1ebdbc8459 100755 --- a/src/app/tests/suites/certification/Test_TC_DRLK_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_DRLK_2_1.yaml @@ -607,7 +607,7 @@ tests: - label: "Step 13a: TH reads NumberOfHoliDay SchedulesSupported attribute from DUT" - PICS: DRLK.S.F0b && DRLK.S.A0015 + PICS: DRLK.S.F0b && DRLK.S.A0016 command: "readAttribute" attribute: "NumberOfHolidaySchedulesSupported" response: diff --git a/src/app/tests/suites/certification/Test_TC_DRLK_2_9.yaml b/src/app/tests/suites/certification/Test_TC_DRLK_2_9.yaml index 9f2e34ea6d01ed..0c10f9fa7ba058 100644 --- a/src/app/tests/suites/certification/Test_TC_DRLK_2_9.yaml +++ b/src/app/tests/suites/certification/Test_TC_DRLK_2_9.yaml @@ -167,7 +167,7 @@ tests: - name: "UserIndex" value: null - name: "UserStatus" - value: 5 + value: UserStatusEnum.UnknownEnumValue(5) - name: "UserType" value: 10 response: diff --git a/src/app/tests/suites/certification/Test_TC_DRYERCTRL_2_1.yaml b/src/app/tests/suites/certification/Test_TC_DRYERCTRL_2_1.yaml index e0a490cd60ec1c..865f86283a2830 100644 --- a/src/app/tests/suites/certification/Test_TC_DRYERCTRL_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_DRYERCTRL_2_1.yaml @@ -48,7 +48,7 @@ tests: response: constraints: type: list - maxLength: 16 + maxLength: 4 - label: "Step 3: TH reads from the DUT the mandatory attribute: @@ -60,7 +60,7 @@ tests: constraints: type: enum8 minValue: 0 - maxValue: 15 + maxValue: 3 - label: "Step 4:TH writes a supported SelectedDrynessLevel attribute that is diff --git a/src/app/tests/suites/certification/Test_TC_EEVSEM_1_1.yaml b/src/app/tests/suites/certification/Test_TC_EEVSEM_1_1.yaml new file mode 100644 index 00000000000000..ea416ee91e96b3 --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_EEVSEM_1_1.yaml @@ -0,0 +1,116 @@ +# 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. + +name: 265.1.1. [TC-EEVSEM-1.1] Global Attributes with DUT as Server + +PICS: + - EEVSEM.S + +config: + nodeId: 0x12344321 + cluster: "Energy EVSE Mode" + endpoint: 1 + +tests: + - label: + "Step 1: Commission DUT to TH (can be skipped if done in a preceding + test)." + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 2: TH reads from the DUT the ClusterRevision attribute" + command: "readAttribute" + attribute: "ClusterRevision" + response: + value: 1 + constraints: + type: int16u + + #https://github.com/project-chip/connectedhomeip/issues/31599 + - label: "Step 3: TH reads from the DUT the FeatureMap attribute" + verification: | + ./chip-tool energyevsemode read feature-map 1 1 + + On the TH(Chip-tool) Log, Verify featureMap value is 0 and below is the sample log provided for the raspi platform: + + [1705995388.110138][7525:7527] CHIP:DMG: } + [1705995388.110173][7525:7527] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_009D Attribute 0x0000_FFFC DataVersion: 1324786556 + [1705995388.110192][7525:7527] CHIP:TOO: FeatureMap: 1 + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_SKIP_SAMPLE_APP + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: "Step 4: TH reads from the DUT the AttributeList attribute" + PICS: PICS_EVENT_LIST_ENABLED + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [0, 1, 65528, 65529, 65530, 65531, 65532, 65533] + + - label: "Step 4a: TH reads AttributeList from DUT" + PICS: "!PICS_EVENT_LIST_ENABLED" + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [0, 1, 65528, 65529, 65531, 65532, 65533] + + - label: + "Step 4b: TH reads optional attribute (StartUpMode) in AttributeList + from DUT" + PICS: EEVSEM.S.A0002 + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [2] + + - label: "Step 5: TH reads EventList from DUT" + PICS: PICS_EVENT_LIST_ENABLED + command: "readAttribute" + attribute: "EventList" + response: + value: [] + constraints: + type: list + + - label: "Step 6: TH reads AcceptedCommandList from DUT" + command: "readAttribute" + attribute: "AcceptedCommandList" + response: + value: [0] + constraints: + type: list + + - label: "Step 7: TH reads GeneratedCommandList from DUT" + command: "readAttribute" + attribute: "GeneratedCommandList" + response: + value: [1] + constraints: + type: list diff --git a/src/app/tests/suites/certification/Test_TC_EEVSEM_1_2.yaml b/src/app/tests/suites/certification/Test_TC_EEVSEM_1_2.yaml new file mode 100644 index 00000000000000..642dc5f09912dd --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_EEVSEM_1_2.yaml @@ -0,0 +1,95 @@ +# 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. +# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default + +name: 269.1.2. [TC-EEVSEM-1.2] Cluster attributes with DUT as Server + +PICS: + - EEVSEM.S + +config: + nodeId: 0x12344321 + cluster: "Basic Information" + endpoint: 1 + +tests: + - label: "Step 1: TH reads from the DUT the SupportedModes attribute" + PICS: EEVSEM.S.A0000 + verification: | + ./chip-tool energyevsemode read supported-modes 1 1 + + - Verify that the DUT response contains a list of ModeOptionsStruct entries + - Verify that the list has at least 2 and at most 255 entries + - Verify that each ModeOptionsStruct entry has a unique Mode field value + - Verify that each ModeOptionsStruct entry has a unique Label field value + - Verify that each ModeOptionsStruct entry’s ModeTags field has: + at least one entry the values of the Value fields that are not larger than 16 bits + - for each Value field: Is the mode tag value a defined common tag value (Auto(0x0000), Quick(0x0001), Quiet(0x0002), LowNoise(0x0003), LowEnergy(0x0004), Vacation(0x0005), Min(0x0006), Max(0x0007), Night(0x0008), Day(0x0009)) or a defined cluster-derived tag value (Manual, Time of Use, (T_SOLAR_CHARGING)) or in the MfgTags (0x8000 to 0xBFFF) range + - for at least one Value field: Is the mode tag value a defined common tag value (Auto(0x0000), Quick(0x0001), Quiet(0x0002), LowNoise(0x0003), LowEnergy(0x0004), Vacation(0x0005), Min(0x0006), Max(0x0007), Night(0x0008), Day(0x0009)) or a derived cluster value (Bake(0x4000), Convection(0x4001), Grill(0x4002), Roast(0x4003), Clean(0x4004), Convection Bake(0x4005), Convection Roast(0x4006), Warming(0x4007), Proofing(0x4008)) + - if the Value field is in the MfgTags (0x8000 to 0xBFFF) range, the TagName field is a string with a length between 1 and 64 + - Verify that at least one ModeOptionsStruct entry includes the Manual mode tag + - Save the Mode field values as supported_modes_dut on the TH (Chip-tool) and below is the sample log provided for the raspi platform: + + + [1705995452.973731][7546:7548] CHIP:DMG: } + [1705995452.973843][7546:7548] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_009D Attribute 0x0000_0000 DataVersion: 1324786556 + [1705995452.973865][7546:7548] CHIP:TOO: SupportedModes: 4 entries + [1705995452.973883][7546:7548] CHIP:TOO: [1]: { + [1705995452.973886][7546:7548] CHIP:TOO: Label: Manual + [1705995452.973892][7546:7548] CHIP:TOO: Mode: 0 + [1705995452.973898][7546:7548] CHIP:TOO: ModeTags: 1 entries + [1705995452.973903][7546:7548] CHIP:TOO: [1]: { + [1705995452.973906][7546:7548] CHIP:TOO: Value: 16384 + [1705995452.973909][7546:7548] CHIP:TOO: } + [1705995452.973912][7546:7548] CHIP:TOO: } + [1705995452.973918][7546:7548] CHIP:TOO: [2]: { + [1705995452.973921][7546:7548] CHIP:TOO: Label: Auto-scheduled + [1705995452.973923][7546:7548] CHIP:TOO: Mode: 1 + [1705995452.973926][7546:7548] CHIP:TOO: ModeTags: 1 entries + [1705995452.973930][7546:7548] CHIP:TOO: [1]: { + [1705995452.973933][7546:7548] CHIP:TOO: Value: 16385 + [1705995452.973935][7546:7548] CHIP:TOO: } + [1705995452.973938][7546:7548] CHIP:TOO: } + [1705995452.973943][7546:7548] CHIP:TOO: [3]: { + [1705995452.973946][7546:7548] CHIP:TOO: Label: Solar + [1705995452.973948][7546:7548] CHIP:TOO: Mode: 2 + [1705995452.973951][7546:7548] CHIP:TOO: ModeTags: 1 entries + [1705995452.973955][7546:7548] CHIP:TOO: [1]: { + [1705995452.973957][7546:7548] CHIP:TOO: Value: 16386 + [1705995452.973960][7546:7548] CHIP:TOO: } + [1705995452.973962][7546:7548] CHIP:TOO: } + [1705995452.973968][7546:7548] CHIP:TOO: [4]: { + [1705995452.973971][7546:7548] CHIP:TOO: Label: Auto-scheduled with Solar charging + [1705995452.973973][7546:7548] CHIP:TOO: Mode: 3 + [1705995452.973977][7546:7548] CHIP:TOO: ModeTags: 2 entries + [1705995452.973981][7546:7548] CHIP:TOO: [1]: { + [1705995452.973983][7546:7548] CHIP:TOO: Value: 16385 + [1705995452.973986][7546:7548] CHIP:TOO: } + [1705995452.973989][7546:7548] CHIP:TOO: [2]: { + [1705995452.973992][7546:7548] CHIP:TOO: Value: 16386 + [1705995452.973994][7546:7548] CHIP:TOO: } + [1705995452.973996][7546:7548] CHIP:TOO: } + disabled: true + + - label: "Step 2: TH reads from the DUT the CurrentMode attribute" + PICS: EEVSEM.S.A0001 + verification: | + ./chip-tool energyevsemode read current-mode 1 1 + + Verify on TH(chip-tool) logs, CurrentMode attribute value is an integer value from supported_modes_dut, below is the sample log provided for the raspi platform, Here CurrentMode attribute value is 0 + + [1705995474.391307][7551:7553] CHIP:DMG: } + [1705995474.391347][7551:7553] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_009D Attribute 0x0000_0001 DataVersion: 1324786556 + [1705995474.391367][7551:7553] CHIP:TOO: CurrentMode: 0 + disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_EEVSEM_2_1.yaml b/src/app/tests/suites/certification/Test_TC_EEVSEM_2_1.yaml new file mode 100644 index 00000000000000..b5f483f62fe2d9 --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_EEVSEM_2_1.yaml @@ -0,0 +1,219 @@ +# 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. + +name: 269.2.1. [TC-EEVSEM-2.1] Change to Mode functionality with DUT as Server + +PICS: + - EEVSEM.S + +config: + nodeId: 0x12344321 + cluster: "Energy EVSE Mode" + endpoint: 1 + + #PIXIT.EEVSEM.MODE_CHANGE_OK + PIXIT.EEVSEM.MODE_CHANGE_OK: + type: int8u + defaultValue: 2 + #PIXIT.EEVSEM.MODE_CHANGE_FAIL + PIXIT.EEVSEM.MODE_CHANGE_FAIL: + type: int8u + defaultValue: 10 + invalid_mode_th: + type: int8u + defaultValue: 15 + +tests: + - label: "Step 1: Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 2: TH reads from the DUT the SupportedModes attribute." + PICS: EEVSEM.S.A0000 + command: "readAttribute" + attribute: "SupportedModes" + response: + saveAs: supported_mode_dut + constraints: + type: list + minLength: 2 + + - label: "Step 3: TH reads from the DUT the CurrentMode attribute." + PICS: EEVSEM.S.A0001 + command: "readAttribute" + attribute: "CurrentMode" + response: + saveAs: old_current_mode_dut + constraints: + type: int8u + minValue: 0 + maxValue: 255 + + - label: + "Step 4: TH sends a ChangeToMode command to the DUT with NewMode set + to old_current_mode_dut" + PICS: EEVSEM.S.C00.Rsp + command: "ChangeToMode" + arguments: + values: + - name: "NewMode" + value: old_current_mode_dut + response: + values: + - name: "Status" + value: 0x00 + + - label: + "Step 5: Manually put the device in a state from which it will FAIL to + transition to PIXIT.EEVSEM.MODE_CHANGE_FAIL" + PICS: + " EEVSEM.S.M.CAN_TEST_MODE_FAILURE && + EEVSEM.S.M.CAN_MANUALLY_CONTROLLED && PICS_SKIP_SAMPLE_APP " + verification: | + Manual operation required + cluster: "LogCommands" + command: "UserPrompt" + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: "Step 6: TH reads from the DUT the CurrentMode attribute" + PICS: EEVSEM.S.A0001 && EEVSEM.S.M.CAN_MANUALLY_CONTROLLED + command: "readAttribute" + attribute: "CurrentMode" + response: + saveAs: Step6_current_mode_dut + constraints: + type: int8u + minValue: 0 + maxValue: 255 + + #Skipping test-7 because SDK is not enabled with this failure response + - label: + "Step 7: TH sends a ChangeToMode command to the DUT with NewMode set + to PIXIT.EEVSEM.MODE_CHANGE_FAIL" + PICS: + EEVSEM.S.M.CAN_TEST_MODE_FAILURE && EEVSEM.S.C00.Rsp && + PICS_SKIP_SAMPLE_APP + verification: | + Note : Please skip this step as SDK is not enabled with this failure response + + ./chip-tool energyevsemode change-to-mode 2 1 1 + + Verify on TH(chip-tool) log, DUT responds contains a ChangeToModeResponse command with Status field is set to GenericFailure(0x02), InvalidInMode(0x03) , or in the MfgCodes (0x80 to 0xBF) range and StatusText field has a length between 1 and 64, below is the sample log provided for the raspi platform: + + [1705995550.805161][7567:7569] CHIP:DMG: }, + [1705995550.805185][7567:7569] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_009D Command=0x0000_0001 + [1705995550.805197][7567:7569] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_009D Command 0x0000_0001 + [1705995550.805221][7567:7569] CHIP:TOO: ChangeToModeResponse: { + [1705995550.805228][7567:7569] CHIP:TOO: status: 0 + [1705995550.805232][7567:7569] CHIP:TOO: } + cluster: "LogCommands" + command: "UserPrompt" + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: "Step 8: TH reads from the DUT the CurrentMode attribute." + PICS: EEVSEM.S.A0001 + command: "readAttribute" + attribute: "CurrentMode" + response: + value: old_current_mode_dut + constraints: + type: int8u + + - label: + "Step 9: Manually put the device in a state from which it will + SUCCESSFULLY transition to PIXIT.EEVSEM.MODE_CHANGE_OK" + PICS: PICS_SKIP_SAMPLE_APP + verification: | + Manual operation required + cluster: "LogCommands" + command: "UserPrompt" + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: "Step 10: TH reads from the DUT the CurrentMode attribute." + PICS: EEVSEM.S.A0001 && EEVSEM.S.M.CAN_MANUALLY_CONTROLLED + command: "readAttribute" + attribute: "CurrentMode" + response: + saveAs: Step10_current_mode_dut + constraints: + type: int8u + minValue: 0 + maxValue: 255 + + - label: + "Step 11: TH sends a ChangeToMode command to the DUT with NewMode set + to PIXIT.EEVSEM.MODE_CHANGE_OK" + PICS: EEVSEM.S.C00.Rsp + command: "ChangeToMode" + arguments: + values: + - name: "NewMode" + value: PIXIT.EEVSEM.MODE_CHANGE_OK + response: + values: + - name: "Status" + value: 0x00 + + - label: + "Step 12: TH reads from the DUT the CurrentMode attribute. Verify that + the DUT response contains an integer value equal to + PIXIT.EEVSEM.MODE_CHANGE_OK" + PICS: EEVSEM.S.A0001 + command: "readAttribute" + attribute: "CurrentMode" + response: + value: PIXIT.EEVSEM.MODE_CHANGE_OK + + - label: + "Step 13: TH sends a ChangeToMode command to the DUT with NewMode set + to invalid_mode_th" + PICS: EEVSEM.S.C00.Rsp + command: "ChangeToMode" + arguments: + values: + - name: "NewMode" + value: invalid_mode_th + response: + values: + - name: "Status" + value: 0x01 + + - label: + "Step 14: TH reads from the DUT the CurrentMode attribute. Verify that + the DUT response contains an integer value equal to + PIXIT.EEVSEM.MODE_CHANGE_OK" + PICS: EEVSEM.S.A0001 + command: "readAttribute" + attribute: "CurrentMode" + response: + value: PIXIT.EEVSEM.MODE_CHANGE_OK diff --git a/src/app/tests/suites/certification/Test_TC_EEVSEM_3_1.yaml b/src/app/tests/suites/certification/Test_TC_EEVSEM_3_1.yaml new file mode 100644 index 00000000000000..2d38a6c1465236 --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_EEVSEM_3_1.yaml @@ -0,0 +1,134 @@ +# 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. + +name: 183.3.1. [TC-EEVSEM-3.1] On Mode functionality with DUT as Server + +PICS: + - EEVSEM.S.A0003 + - MOD.S.F00 + - OO.S.C00.Rsp + - OO.S.C01.Rsp + +config: + nodeId: 0x12344321 + cluster: "Energy EVSE Mode" + endpoint: 1 + + ConfigureOnMode: + type: int8u + defaultValue: 0 + new_mode_th: + type: int8u + defaultValue: 2 + +tests: + - label: + "Step 1: Commission DUT to TH (can be skipped if done in a preceding + test)." + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: + "Precondition: TH writes from the DUT the OnMode attribute.NOTE: To + execute this test case set onmode to any integer value because as + default it value has null." + PICS: EEVSEM.S.A0003 && MOD.S.F00 + command: "writeAttribute" + attribute: "OnMode" + arguments: + value: ConfigureOnMode + + - label: "Step 2: TH reads from the DUT the OnMode attribute." + PICS: EEVSEM.S.A0003 && MOD.S.F00 + command: "readAttribute" + attribute: "OnMode" + response: + saveAs: on_mode_dut + constraints: + type: int8u + minValue: 0 + maxValue: 254 + + - label: "Step 3: TH reads from the DUT the CurrentMode attribute." + PICS: EEVSEM.S.A0001 && MOD.S.F00 + command: "readAttribute" + attribute: "CurrentMode" + response: + saveAs: old_current_mode_dut + constraints: + type: int8u + minValue: 0 + maxValue: 254 + + - label: + "If on_mode_dut is equal to old_current_mode_dut proceed to step 4. + Else proceed to step 6." + cluster: "EqualityCommands" + command: "UnsignedNumberEquals" + arguments: + values: + - name: "Value1" + value: on_mode_dut + - name: "Value2" + value: old_current_mode_dut + response: + - values: + - name: "Equals" + saveAs: IsExpectedValue + + - label: "Step 4: TH reads from the DUT the SupportedModes attribute." + runIf: IsExpectedValue + PICS: EEVSEM.S.A0000 && MOD.S.F00 + command: "readAttribute" + attribute: "SupportedModes" + response: + constraints: + type: list + minLength: 2 + + - label: + "Step 5: TH sends a ChangeToMode command to the DUT with NewMode set + to new_mode_th" + runIf: IsExpectedValue + PICS: EEVSEM.S.C00.Rsp && MOD.S.F00 + command: "ChangeToMode" + arguments: + values: + - name: "NewMode" + value: new_mode_th + response: + values: + - name: "Status" + value: 0x00 + + - label: "Step 6:TH sends a Off command to the DUT" + PICS: OO.S.C00.Rsp + cluster: "On/Off" + command: "Off" + + - label: "Step 7:TH sends a On command to the DUT" + PICS: OO.S.C01.Rsp + cluster: "On/Off" + command: "On" + + - label: "Step 8: TH reads from the DUT the CurrentMode attribute." + PICS: EEVSEM.S.A0001 && EEVSEM.S.A0003 && MOD.S.F00 + command: "readAttribute" + attribute: "CurrentMode" + response: + value: on_mode_dut diff --git a/src/app/tests/suites/certification/Test_TC_EEVSEM_3_2.yaml b/src/app/tests/suites/certification/Test_TC_EEVSEM_3_2.yaml new file mode 100644 index 00000000000000..0251528f9ffe94 --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_EEVSEM_3_2.yaml @@ -0,0 +1,172 @@ +# 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. + +name: 269.3.2. [TC-EEVSEM-3.2] Startup Mode functionality with DUT as Server + +PICS: + - EEVSEM.S.A0002 + +config: + nodeId: 0x12344321 + cluster: "Energy EVSE Mode" + endpoint: 1 + + new_start_up_mode_th: + type: int8u + defaultValue: 0 + new_mode_th: + type: int8u + defaultValue: 1 + +tests: + - label: + "Step 1: Commission DUT to TH (can be skipped if done in a preceding + test)." + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 2: TH reads from the DUT the StartUpMode attribute." + PICS: EEVSEM.S.A0002 + command: "readAttribute" + attribute: "StartUpMode" + response: + saveAs: startup_mode_dut + + - label: + "Step 2: If startup_mode_dut is null proceed to step 3. Else save + startup_mode_dut as new_start_up_mode_th and proceed to step 5." + PICS: EEVSEM.S.A0002 + cluster: "EqualityCommands" + command: "UnsignedNumberEquals" + arguments: + values: + - name: "Value1" + value: startup_mode_dut + - name: "Value2" + value: null + response: + - values: + - name: "Equals" + saveAs: IsExpectedValue + + - label: "Step 3: TH reads from the DUT the SupportedModes attribute." + runIf: IsExpectedValue + PICS: EEVSEM.S.A0000 + command: "readAttribute" + attribute: "SupportedModes" + response: + saveAs: supported_modes_dut + constraints: + type: list + minLength: 2 + - label: + "Step 4: TH writes to the DUT the StartUpMode attribute with the + new_start_up_mode_th value" + PICS: EEVSEM.S.A0002 + runIf: IsExpectedValue + command: "writeAttribute" + attribute: "StartUpMode" + arguments: + value: new_start_up_mode_th + + - label: "Step 5: TH reads from the DUT the CurrentMode attribute." + PICS: EEVSEM.S.A0001 + command: "readAttribute" + attribute: "CurrentMode" + response: + saveAs: old_current_mode_dut + + - label: + "Step 5: If startup_mode_dut is equal to old_current_mode_dut proceed + to step 6. Else proceed to step 8." + PICS: EEVSEM.S.A0001 && EEVSEM.S.A0002 + cluster: "EqualityCommands" + command: "UnsignedNumberEquals" + arguments: + values: + - name: "Value1" + value: startup_mode_dut + - name: "Value2" + value: old_current_mode_dut + response: + - values: + - name: "Equals" + saveAs: Step5_IsExpectedValue + + - label: "Step 6: TH reads from the DUT the SupportedModes attribute." + PICS: EEVSEM.S.A0000 + runIf: Step5_IsExpectedValue + command: "readAttribute" + attribute: "SupportedModes" + response: + saveAs: Step6_supported_modes_dut + constraints: + type: list + minLength: 2 + + - label: + "Step 7: TH sends a ChangeToMode command to the DUT with NewMode set + to new_mode_th" + PICS: EEVSEM.S.C00.Rsp + runIf: Step5_IsExpectedValue + command: "ChangeToMode" + arguments: + values: + - name: "NewMode" + value: new_mode_th + response: + values: + - name: "Status" + value: 0x00 + + - label: "Step 8: Physically power cycle the device" + verification: | + Physically power cycle the device. + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_USER_PROMPT + arguments: + values: + - name: "message" + value: "Please enter 'y' for success" + - name: "expectedValue" + value: "y" + + - label: "Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 9: TH reads from the DUT the StartUpMode attribute." + PICS: EEVSEM.S.A0002 && PICS_USER_PROMPT + command: "readAttribute" + attribute: "StartUpMode" + response: + saveAs: new_start_up_mode_dut + constraints: + anyOf: [startup_mode_dut, new_start_up_mode_th] + + - label: "Step 10: TH reads from the DUT the CurrentMode attribute." + PICS: EEVSEM.S.A0001 && PICS_USER_PROMPT + command: "readAttribute" + attribute: "CurrentMode" + response: + value: new_start_up_mode_dut diff --git a/src/app/tests/suites/certification/Test_TC_EEVSEM_3_3.yaml b/src/app/tests/suites/certification/Test_TC_EEVSEM_3_3.yaml new file mode 100644 index 00000000000000..e60aa1ca60c740 --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_EEVSEM_3_3.yaml @@ -0,0 +1,189 @@ +# 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. + +name: + 269.3.3. [TC-EEVSEM-3.3] On Mode and Startup Mode functionality with DUT as + Server + +PICS: + - EEVSEM.S.A0002 + - EEVSEM.S.A0003 + - MOD.S.F00 + - OO.S.A4003 + +config: + nodeId: 0x12344321 + cluster: "Energy EVSE Mode" + endpoint: 1 + + new_start_up_mode_th: + type: int8u + defaultValue: 0 + new_mode_th: + type: int8u + defaultValue: 1 + +tests: + - label: + "Step 1: Commission DUT to TH (can be skipped if done in a preceding + test)." + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 2: TH reads from the DUT the StartUpMode attribute." + PICS: EEVSEM.S.A0002 + command: "readAttribute" + attribute: "StartUpMode" + response: + saveAs: startup_mode_dut + + - label: + "Step 2: If startup_mode_dut is null proceed to step 3. Else save + startup_mode_dut as new_start_up_mode_th and proceed to step 5." + PICS: EEVSEM.S.A0002 + cluster: "EqualityCommands" + command: "UnsignedNumberEquals" + arguments: + values: + - name: "Value1" + value: startup_mode_dut + - name: "Value2" + value: null + response: + - values: + - name: "Equals" + saveAs: IsExpectedValue + + - label: "Step 3: TH reads from the DUT the SupportedModes attribute." + runIf: IsExpectedValue + PICS: EEVSEM.S.A0000 + command: "readAttribute" + attribute: "SupportedModes" + response: + saveAs: supported_modes_dut + constraints: + type: list + minLength: 2 + + - label: + "Step 4: TH writes to the DUT the StartUpMode attribute with the + new_start_up_mode_th value" + PICS: EEVSEM.S.A0002 + runIf: IsExpectedValue + command: "writeAttribute" + attribute: "StartUpMode" + arguments: + value: new_start_up_mode_th + + - label: "Step 5: TH reads from the DUT the OnMode attribute." + PICS: EEVSEM.S.A0003 && EEVSEM.S.A0002 + command: "readAttribute" + attribute: "OnMode" + response: + saveAs: old_on_mode_dut + + - label: + "Step 5: If startup_mode_dut is equal to old_on_mode_dut proceed to + step 6. Else proceed to step 8." + PICS: EEVSEM.S.A0002 + cluster: "EqualityCommands" + command: "UnsignedNumberEquals" + arguments: + values: + - name: "Value1" + value: old_on_mode_dut + - name: "Value2" + value: startup_mode_dut + response: + - values: + - name: "Equals" + saveAs: Step5_IsExpectedValue + + - label: "Step 6: TH reads from the DUT the SupportedModes attribute." + PICS: EEVSEM.S.A0000 && EEVSEM.S.A0002 + runIf: Step5_IsExpectedValue + command: "readAttribute" + attribute: "SupportedModes" + response: + saveAs: Step6_supported_modes_dut + constraints: + type: list + minLength: 2 + + - label: + "Step 7: TH writes to the DUT the OnMode attribute with the + new_mode_th value" + PICS: EEVSEM.S.A0003 + runIf: Step5_IsExpectedValue + command: "writeAttribute" + attribute: "OnMode" + arguments: + value: new_mode_th + + - label: "Step 8: TH reads from the DUT the OnMode attribute." + PICS: EEVSEM.S.A0003 && MOD.S.F00 + command: "readAttribute" + attribute: "OnMode" + response: + saveAs: new_on_mode_dut + + - label: + "Step 9: TH writes to the DUT the StartUpOnOff attribute with the + value 1." + PICS: OO.S.A4003 + cluster: "On/Off" + command: "writeAttribute" + attribute: "StartUpOnOff" + arguments: + value: 1 + + - label: "Step 10: Physically power cycle the device" + verification: | + Physically power cycle the device. + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_USER_PROMPT + arguments: + values: + - name: "message" + value: "Please enter 'y' for success" + - name: "expectedValue" + value: "y" + + - label: "Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 11: TH reads from the DUT the StartUpMode attribute." + PICS: EEVSEM.S.A0002 && PICS_USER_PROMPT + command: "readAttribute" + attribute: "StartUpMode" + response: + constraints: + anyOf: [new_start_up_mode_th, startup_mode_dut] + + - label: "Step 12: TH reads from the DUT the CurrentMode attribute." + PICS: EEVSEM.S.A0001 && PICS_USER_PROMPT + command: "readAttribute" + attribute: "CurrentMode" + response: + value: new_on_mode_dut diff --git a/src/app/tests/suites/certification/Test_TC_EEVSE_1_1.yaml b/src/app/tests/suites/certification/Test_TC_EEVSE_1_1.yaml index 44932851b0343c..0be6a9015ed5e9 100644 --- a/src/app/tests/suites/certification/Test_TC_EEVSE_1_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_EEVSE_1_1.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Project CHIP Authors +# 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. @@ -11,129 +11,291 @@ # 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default -name: 272.1.1. [TC-EEVSE-1.1] Global Attributes with DUT as Server +name: 265.1.1. [TC-EEVSE-1.1] Global Attributes with DUT as Server PICS: - EEVSE.S config: nodeId: 0x12344321 - cluster: "Basic Information" - endpoint: 0 + cluster: "Energy EVSE" + endpoint: 1 tests: + - label: "Step 1: Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 2: TH reads from the DUT the ClusterRevision attribute" + command: "readAttribute" + attribute: "ClusterRevision" + response: + value: 2 + constraints: + type: int16u + + - label: "Step 3a: TH reads from the DUT the FeatureMap attribute" + PICS: + "!EEVSE.S.F00 && !EEVSE.S.F01 && !EEVSE.S.F02 && !EEVSE.S.F03 && + !EEVSE.S.F04" + command: "readAttribute" + attribute: "FeatureMap" + response: + value: 0 + constraints: + type: bitmap32 + + - label: + "Step 3b: Given EEVSE.S.F00(ChargingPreferences) ensure featuremap has + the correct bit set" + PICS: EEVSE.S.F00 + command: "readAttribute" + attribute: "FeatureMap" + response: + constraints: + type: bitmap32 + hasMasksSet: [0x1] + + - label: + "Step 3b: Given EEVSE.S.F01(SoCReporting) ensure featuremap has the + correct bit set" + PICS: EEVSE.S.F01 + command: "readAttribute" + attribute: "FeatureMap" + response: + constraints: + type: bitmap32 + hasMasksSet: [0x2] + + - label: + "Step 3b: Given EEVSE.S.F02(PlugAndCharge) ensure featuremap has the + correct bit set" + PICS: EEVSE.S.F02 + command: "readAttribute" + attribute: "FeatureMap" + response: + constraints: + type: bitmap32 + hasMasksSet: [0x4] + + - label: + "Step 3b: Given EEVSE.S.F03(RFID) ensure featuremap has the correct + bit set" + PICS: EEVSE.S.F03 + command: "readAttribute" + attribute: "FeatureMap" + response: + constraints: + type: bitmap32 + hasMasksSet: [0x8] + + - label: + "Step 3b: Given EEVSE.S.F04(V2X) ensure featuremap has the correct bit + set" + PICS: EEVSE.S.F04 + command: "readAttribute" + attribute: "FeatureMap" + response: + constraints: + type: bitmap32 + hasMasksSet: [0x10] + + - label: "Step 4a: TH reads from the DUT the AttributeList attribute" + PICS: PICS_EVENT_LIST_ENABLED + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: + [ + 0, + 1, + 2, + 3, + 5, + 6, + 7, + 64, + 65, + 66, + 65528, + 65529, + 65530, + 65531, + 65532, + 65533, + ] + + - label: "Step 4a: TH reads AttributeList from DUT" + PICS: "!PICS_EVENT_LIST_ENABLED" + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: + [ + 0, + 1, + 2, + 3, + 5, + 6, + 7, + 64, + 65, + 66, + 65528, + 65529, + 65531, + 65532, + 65533, + ] + + - label: + "Step 4b: TH reads optional attribute (UserMaximumChargeCurrent) in + AttributeList from DUT" + PICS: EEVSE.S.A0009 + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [9] + + - label: + "Step 4c: TH reads optional attribute (RandomizationDelayWindow) in + AttributeList from DUT" + PICS: EEVSE.S.A000A + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [10] + + - label: + "Step 4d: TH reads optional attribute (V2X) in AttributeList from DUT" + PICS: EEVSE.S.F04 + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [4, 8, 67] + + - label: + "Step 4e: TH reads optional attribute (ChargingPreferences) in + AttributeList from DUT" + PICS: EEVSE.S.F00 + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [35, 36, 37, 38, 39] + + - label: + "Step 4e: TH reads optional attribute (SoCReporting) in AttributeList + from DUT" + PICS: EEVSE.S.F01 + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [48, 49] + + - label: + "Step 4f: TH reads optional attribute (PlugAndCharge) in AttributeList + from DUT" + PICS: EEVSE.S.F02 + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [50] + + - label: "Step 5a: TH reads EventList from DUT" + PICS: PICS_EVENT_LIST_ENABLED + command: "readAttribute" + attribute: "EventList" + response: + constraints: + type: list + contains: [0, 1, 2, 3, 4] + + - label: "Step 5b: TH reads optional attribute (RFID) in EventList from DUT" + PICS: EEVSE.S.F03 && PICS_EVENT_LIST_ENABLED + command: "readAttribute" + attribute: "EventList" + response: + constraints: + type: list + contains: [5] + + - label: "Step 6a: TH reads AcceptedCommandList from DUT" + command: "readAttribute" + attribute: "AcceptedCommandList" + response: + constraints: + type: list + contains: [1, 2] + + - label: + "Step 6b: TH reads the optional (StartDiagnostics) command in + AcceptedCommandList" + PICS: EEVSE.S.C04.Rsp + command: "readAttribute" + attribute: "AcceptedCommandList" + response: + constraints: + type: list + contains: [4] + - label: - "Step 1: Commission DUT to TH (can be skipped if done in a preceding - test)." - verification: | - - disabled: true - - - label: "Step 2: TH reads from the DUT the ClusterRevision attribute." - verification: | - ./chip-tool energyevse read cluster-revision 1 1 - - On TH(chip-tool), Verify the ClusterRevision attribute value as 2: - Below mentioned log is based on the RPI implementation, Value may vary on real DUT - - [1703744384.239486][1259:1261] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_FFFD DataVersion: 1471857723 - [1703744384.239529][1259:1261] CHIP:TOO: ClusterRevision: 2 - disabled: true - - - label: "Step 3: TH reads from the DUT the FeatureMap attribute." - verification: | - ./chip-tool energyevse read feature-map 1 1 - - Via the TH (chip-tool), verify that theFeatureMap attribute contains the value. Below mentioned log is based on the RPI implementation, Value may vary on real DUT - - - [1703744496.721907][1265:1267] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_FFFC DataVersion: 1471857723 - [1703744496.721955][1265:1267] CHIP:TOO: FeatureMap: 31 - disabled: true - - - label: "Step 4: TH reads from the DUT the AttributeList attribute." - verification: | - ./chip-tool energyevse read attribute-list 1 1 - - Via the TH (chip-tool), verify that theAttributeListattribute contains - - Mandatory entries:0x0000, 0x0001, 0x0002, 0x0003, 0x0005, 0x0006, 0x0007, 0x0040, 0x0041, 0x0042 0xfff8, 0xfff9, 0xfffb, 0xfffc and 0xfffd - - Optional entries: 0x0009, 0x000A - - Based on feature support:- 0x0004, 0x0008, 0x0043, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0030, 0x0031, 0x0032 - Below mentioned log is based on the RPI implementation, Value may vary on real DUT - - [1705654173.130338][6375:6377] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_FFFB DataVersion: 1462274739 - [1705654173.130427][6375:6377] CHIP:TOO: AttributeList: 28 entries - [1705654173.130469][6375:6377] CHIP:TOO: [1]: 0 - [1705654173.130506][6375:6377] CHIP:TOO: [2]: 1 - [1705654173.130529][6375:6377] CHIP:TOO: [3]: 2 - [1705654173.130551][6375:6377] CHIP:TOO: [4]: 3 - [1705654173.130574][6375:6377] CHIP:TOO: [5]: 4 - [1705654173.130608][6375:6377] CHIP:TOO: [6]: 5 - [1705654173.130631][6375:6377] CHIP:TOO: [7]: 6 - [1705654173.130664][6375:6377] CHIP:TOO: [8]: 7 - [1705654173.130687][6375:6377] CHIP:TOO: [9]: 8 - [1705654173.130710][6375:6377] CHIP:TOO: [10]: 9 - [1705654173.130744][6375:6377] CHIP:TOO: [11]: 10 - [1705654173.130769][6375:6377] CHIP:TOO: [12]: 35 - [1705654173.130801][6375:6377] CHIP:TOO: [13]: 36 - [1705654173.130826][6375:6377] CHIP:TOO: [14]: 37 - [1705654173.130849][6375:6377] CHIP:TOO: [15]: 38 - [1705654173.130883][6375:6377] CHIP:TOO: [16]: 39 - [1705654173.130907][6375:6377] CHIP:TOO: [17]: 48 - [1705654173.130930][6375:6377] CHIP:TOO: [18]: 49 - [1705654173.130964][6375:6377] CHIP:TOO: [19]: 50 - [1705654173.130988][6375:6377] CHIP:TOO: [20]: 64 - [1705654173.131021][6375:6377] CHIP:TOO: [21]: 65 - [1705654173.131045][6375:6377] CHIP:TOO: [22]: 66 - [1705654173.131068][6375:6377] CHIP:TOO: [23]: 67 - [1705654173.131101][6375:6377] CHIP:TOO: [24]: 65528 - [1705654173.131126][6375:6377] CHIP:TOO: [25]: 65529 - [1705654173.131149][6375:6377] CHIP:TOO: [26]: 65531 - [1705654173.131182][6375:6377] CHIP:TOO: [27]: 65532 - [1705654173.131205][6375:6377] CHIP:TOO: [28]: 65533 - disabled: true - - - label: "Step 5*: TH reads from the DUT the EventList attribute." - verification: | - EventList is currently not supported and SHALL be skipped. - - ./chip-tool energyevse read event-list 1 1 - - Via the TH (chip-tool), verify that the EventList attribute. Below mentioned log is based on the RPI implementation, Value may vary on real DUT - - [1703745599.166331][1300:1302] CHIP:DMG: StatusIB = - [1703745599.166364][1300:1302] CHIP:DMG: { - [1703745599.166419][1300:1302] CHIP:DMG: status = 0x86 (UNSUPPORTED_ATTRIBUTE), - [1703745599.166450][1300:1302] CHIP:DMG: }, - disabled: true - - - label: "Step 6: TH reads from the DUT the AcceptedCommandList attribute." - verification: | - ./chip-tool energyevse read accepted-command-list 1 1 - - On TH(chip-tool), Verify the AcceptedCommandList attribute that contains 7 entries: - Below mentioned log is based on the RPI implementation, Value may vary on real DUT - - [1703745620.007744][1304:1306] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_FFF9 DataVersion: 1471857723 - [1703745620.007809][1304:1306] CHIP:TOO: AcceptedCommandList: 7 entries - [1703745620.007838][1304:1306] CHIP:TOO: [1]: 1 - [1703745620.007862][1304:1306] CHIP:TOO: [2]: 2 - [1703745620.007886][1304:1306] CHIP:TOO: [3]: 3 - [1703745620.007909][1304:1306] CHIP:TOO: [4]: 5 - [1703745620.007931][1304:1306] CHIP:TOO: [5]: 6 - [1703745620.007954][1304:1306] CHIP:TOO: [6]: 7 - [1703745620.007977][1304:1306] CHIP:TOO: [7]: 4 - disabled: true - - - label: "Step 7: TH reads from the DUT the GeneratedCommandList attribute." - verification: | - ./chip-tool energyevse read generated-command-list 1 1 - - On TH(chip-tool), Verify the GeneratedCommandList attribute that contains 1 entries: - - [1703745647.799108][1307:1309] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_FFF8 DataVersion: 1471857723 - [1703745647.799167][1307:1309] CHIP:TOO: GeneratedCommandList: 1 entries - [1703745647.799197][1307:1309] CHIP:TOO: [1]: 0 - disabled: true + "Step 6c: TH reads Feature dependent commands(EEVSE.S.F04) in + AcceptedCommandList" + PICS: EEVSE.S.F04 + command: "readAttribute" + attribute: "AcceptedCommandList" + response: + constraints: + type: list + contains: [3] + + - label: + "Step 6d: TH reads Feature dependent commands(ChargingPreferences) in + AcceptedCommandList" + PICS: EEVSE.S.F00 + command: "readAttribute" + attribute: "AcceptedCommandList" + response: + constraints: + type: list + contains: [5, 6, 7] + + - label: "Step 7a: TH reads GeneratedCommandList from DUT" + PICS: " !EEVSE.S.F00 " + command: "readAttribute" + attribute: "GeneratedCommandList" + response: + value: [] + constraints: + type: list + + - label: "Step 7b: TH reads GeneratedCommandList from DUT" + PICS: EEVSE.S.F00 + command: "readAttribute" + attribute: "GeneratedCommandList" + response: + constraints: + type: list + contains: [0] diff --git a/src/app/tests/suites/certification/Test_TC_EEVSE_2_1.yaml b/src/app/tests/suites/certification/Test_TC_EEVSE_2_1.yaml index f1ea0b28385634..a448a969c7e44e 100644 --- a/src/app/tests/suites/certification/Test_TC_EEVSE_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_EEVSE_2_1.yaml @@ -11,333 +11,278 @@ # 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default -name: 266.1.2. [TC-EEVSE-2.1] Attributes with DUT as Server +name: 265.1.2. [TC-EEVSE-2.1] Attributes with DUT as Server PICS: - EEVSE.S config: - nodeId: "0x12344321" - cluster: "Basic Information" - endpoint: 0 + nodeId: 0x12344321 + cluster: "Energy EVSE" + endpoint: 1 tests: - - label: - "Step 1: Commission DUT to TH (can be skipped if done in a preceding - test)." - verification: | - - disabled: true - - - label: "Step 2: TH reads from the DUT the State attribute." - verification: | - ./chip-tool energyevse read state 1 1 - - On TH(chip-tool), Verify the State value between 0 and 6 inclusive. - - [1703746501.478667][1324:1326] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0000 DataVersion: 1471857723 - [1703746501.482885][1324:1326] CHIP:TOO: State: 0 - disabled: true - - - label: "Step 3: TH reads from the DUT the SupplyState attribute." + - label: "Step 1: Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 2: TH reads from the DUT the State attribute" + command: "readAttribute" + attribute: "State" + response: + constraints: + type: enum8 + minValue: 0 + maxValue: 6 + + - label: "Step 3: TH reads from the DUT the SupplyState attribute" PICS: EEVSE.S.A0001 - verification: | - ./chip-tool energyevse read supply-state 1 1 - - On TH(chip-tool), Verify the SupplyState value between 0 and 4 inclusive. - - [1703746567.014836][1331:1333] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0001 DataVersion: 1471857723 - [1703746567.014912][1331:1333] CHIP:TOO: SupplyState: 0 - disabled: true - - - label: "Step 4: TH reads from the DUT the FaultState attribute." + command: "readAttribute" + attribute: "SupplyState" + response: + constraints: + type: enum8 + minValue: 0 + maxValue: 4 + + - label: "Step 4: TH reads from the DUT the FaultState attribute" PICS: EEVSE.S.A0002 - verification: | - ./chip-tool energyevse read fault-state 1 1 - - On TH(chip-tool), Verify the FaultState value between 0 to 15 and 255 inclusive. - - [1703746609.539647][1339:1341] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0002 DataVersion: 1471857723 - [1703746609.539748][1339:1341] CHIP:TOO: FaultState: 0 - disabled: true - - - label: "Step 5: TH reads from the DUT the ChargingEnabledUntil attribute." + command: "readAttribute" + attribute: "FaultState" + response: + constraints: + type: enum8 + anyOf: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 255] + + - label: "Step 5: TH reads from the DUT the ChargingEnabledUntil attribut" PICS: EEVSE.S.A0003 - verification: | - ./chip-tool energyevse read charging-enabled-until 1 1 - - On TH(chip-tool), Verify the ChargingEnabledUntil attribute contains epoch-s value or null. - - [1703746659.995945][1410:1412] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0003 DataVersion: 1471857723 - [1703746659.996071][1410:1412] CHIP:TOO: ChargingEnabledUntil: null - disabled: true + command: "readAttribute" + attribute: "ChargingEnabledUntil" + response: + constraints: + type: epoch-s + minValue: 0 + maxValue: 4294967295 - label: - "Step 6: TH reads from the DUT the DischargingEnabledUntil attribute." + "Step 6: TH reads from the DUT the DischargingEnabledUntil attribute" PICS: EEVSE.S.A0004 - verification: | - ./chip-tool energyevse read discharging-enabled-until 1 1 - - On TH(chip-tool), Verify the DischargingEnabledUntil attribute contains epoch-s value or null. - - [1703746787.751096][1849:1851] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0004 DataVersion: 1471857723 - [1703746787.751173][1849:1851] CHIP:TOO: DischargingEnabledUntil: null - disabled: true - - - label: "Step 7: TH reads from the DUT the CircuitCapacity attribute." + command: "readAttribute" + attribute: "DischargingEnabledUntil" + response: + constraints: + type: epoch-s + minValue: 0 + maxValue: 4294967295 + + - label: "Step 7: TH reads from the DUT the CircuitCapacity attribute" PICS: EEVSE.S.A0005 - verification: | - ./chip-tool energyevse read circuit-capacity 1 1 - - On TH(chip-tool), Verify the CircuitCapacity contains an amperage-mA value is in the range of 0 to 80000. - - [1703746836.529283][1855:1857] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0005 DataVersion: 1471857723 - [1703746836.529406][1855:1857] CHIP:TOO: CircuitCapacity: 0 - disabled: true - - - label: "Step 8: TH reads from the DUT the MinimumChargeCurrent attribute." + command: "readAttribute" + attribute: "CircuitCapacity" + response: + constraints: + type: amperage_ma + minValue: 0 + maxValue: 80000 + + - label: "Step 8: TH reads from the DUT the MinimumChargeCurrent attribute" PICS: EEVSE.S.A0006 - verification: | - ./chip-tool energyevse read minimum-charge-current 1 1 - - On TH(chip-tool), Verify the MinimumChargeCurrent contains an amperage-mA value is in the range of 0 to 80000. - - [1703746900.151431][1861:1863] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0006 DataVersion: 1471857723 - [1703746900.151511][1861:1863] CHIP:TOO: MinimumChargeCurrent: 6000 - disabled: true - - - label: "Step 9: TH reads from the DUT the MaximumChargeCurrent attribute." + command: "readAttribute" + attribute: "MinimumChargeCurrent" + response: + constraints: + type: amperage_ma + minValue: 0 + maxValue: 80000 + + - label: "Step 9: TH reads from the DUT the MaximumChargeCurrent attribute" PICS: EEVSE.S.A0007 - verification: | - ./chip-tool energyevse read maximum-charge-current 1 1 - - On TH(chip-tool), Verify the MaximumChargeCurrent contains an amperage-mA value is in the range of 0 80000. - - [1703746980.955341][1866:1868] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0007 DataVersion: 1471857723 - [1703746980.955401][1866:1868] CHIP:TOO: MaximumChargeCurrent: 0 - disabled: true + command: "readAttribute" + attribute: "MaximumChargeCurrent" + response: + constraints: + type: amperage_ma + minValue: 0 + maxValue: 80000 - label: - "Step 10: TH reads from the DUT the MaximumDischargeCurrent attribute." + "Step 10: TH reads from the DUT the MaximumDischargeCurrent attribute" PICS: EEVSE.S.A0008 - verification: | - ./chip-tool energyevse read maximum-discharge-current 1 1 - - On TH(chip-tool), Verify the MaximumDischargeCurrent contains an amperage-mA value is in the range of 0 80000. - - [1703747035.548962][1870:1872] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0008 DataVersion: 1471857723 - [1703747035.549016][1870:1872] CHIP:TOO: MaximumDischargeCurrent: 0 - disabled: true + command: "readAttribute" + attribute: "MaximumDischargeCurrent" + response: + constraints: + type: amperage_ma + minValue: 0 + maxValue: 80000 - label: "Step 11: TH writes to the DUT the UserMaximumChargeCurrent attribute - value 30000." + value 3000" PICS: EEVSE.S.A0009 - verification: | - ./chip-tool energyevse write user-maximum-charge-current 30000 1 1 - - On TH(chip-tool), Verify the SUCCESS response for UserMaximumChargeCurrent attribute successful write. - - [1703747211.562507][1880:1882] CHIP:DMG: StatusIB = - [1703747211.562536][1880:1882] CHIP:DMG: { - [1703747211.562599][1880:1882] CHIP:DMG: status = 0x00 (SUCCESS), - [1703747211.562629][1880:1882] CHIP:DMG: }, - [1703747211.562677][1880:1882] CHIP:DMG: - [1703747211.562703][1880:1882] CHIP:DMG: }, - disabled: true + command: "writeAttribute" + attribute: "UserMaximumChargeCurrent" + arguments: + value: 30000 - label: "Step 11a: TH reads from the DUT the UserMaximumChargeCurrent - attribute." + attribute" PICS: EEVSE.S.A0009 - verification: | - ./chip-tool energyevse read user-maximum-charge-current 1 1 - - On TH(chip-tool), Verify the UserMaximumChargeCurrent attribute contains the amperage-mA value 30000. - - [1703747252.643892][1886:1888] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0009 DataVersion: 1471857725 - [1703747252.643979][1886:1888] CHIP:TOO: UserMaximumChargeCurrent: 30000 - disabled: true + command: "readAttribute" + attribute: "UserMaximumChargeCurrent" + response: + value: 30000 + constraints: + type: amperage_ma - label: "Step 12: TH writes to the DUT the RandomizationDelayWindow attribute - value 600." + value 600" PICS: EEVSE.S.A000A - verification: | - ./chip-tool energyevse write randomization-delay-window 600 1 1 - - On TH(chip-tool), Verify the SUCCESS response for RandomizationDelayWindow attribute successful write. - - [1703747329.583214][1890:1892] CHIP:DMG: StatusIB = - [1703747329.583244][1890:1892] CHIP:DMG: { - [1703747329.583273][1890:1892] CHIP:DMG: status = 0x00 (SUCCESS), - [1703747329.583301][1890:1892] CHIP:DMG: }, - disabled: true + command: "writeAttribute" + attribute: "RandomizationDelayWindow" + arguments: + value: 600 - label: "Step 12a: TH reads from the DUT the RandomizationDelayWindow - attribute." + attribute" PICS: EEVSE.S.A000A - verification: | - ./chip-tool energyevse read randomization-delay-window 1 1 - - On TH(chip-tool), Verify the RandomizationDelayWindow attribute contains elapsed-s value 600. - - [1703747373.495538][1893:1895] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_000A DataVersion: 1471857726 - [1703747373.495591][1893:1895] CHIP:TOO: RandomizationDelayWindow: 600 - disabled: true - - - label: "Step 13: TH reads from the DUT the NextChargeStartTime attribute." + command: "readAttribute" + attribute: "RandomizationDelayWindow" + response: + value: 600 + constraints: + type: elapsed_s + + - label: "Step 13: TH reads from the DUT the NextChargeStartTime attribute" PICS: EEVSE.S.A0023 - verification: | - ./chip-tool energyevse read next-charge-start-time 1 1 - - On TH(chip-tool), Verify the NextChargeStartTime attribute contains epoch-s value or null. - - [1703747468.300635][1902:1904] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0023 DataVersion: 1471857726 - [1703747468.300690][1902:1904] CHIP:TOO: NextChargeStartTime: null - disabled: true - - - label: - "Step 14: TH reads from the DUT the NextChargeTargetTime attribute." + command: "readAttribute" + attribute: "NextChargeStartTime" + response: + constraints: + type: epoch-s + minValue: 0 + maxValue: 4294967295 + + - label: "Step 14: TH reads from the DUT the NextChargeTargetTime attribute" PICS: EEVSE.S.A0024 - verification: | - ./chip-tool energyevse read next-charge-target-time 1 1 - - On TH(chip-tool), Verify the NextChargeTargetTime attribute contains epoch-s value or null. - - [1703747509.059648][1906:1908] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0024 DataVersion: 1471857726 - [1703747509.059700][1906:1908] CHIP:TOO: NextChargeTargetTime: null - disabled: true + command: "readAttribute" + attribute: "NextChargeTargetTime" + response: + constraints: + type: epoch-s + minValue: 0 + maxValue: 4294967295 - label: - "Step 15: TH reads from the DUT the NextChargeRequiredEnergy - attribute." + "Step 15: TH reads from the DUT the NextChargeRequiredEnergy attribute" PICS: EEVSE.S.A0025 - verification: | - ./chip-tool energyevse read next-charge-required-energy 1 1 - - On TH(chip-tool), Verify the NextChargeRequiredEnergy attribute energy-mWh value is in the valid range(min 0) or null. - - [1703747579.793082][1917:1919] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0025 DataVersion: 1471857726 - [1703747579.793170][1917:1919] CHIP:TOO: NextChargeRequiredEnergy: null - disabled: true - - - label: "Step 16: TH reads from the DUT the NextChargeTargetSoC attribute." + command: "readAttribute" + attribute: "NextChargeRequiredEnergy" + response: + constraints: + type: energy-mWh + minValue: 0 + + - label: "Step 16: TH reads from the DUT the NextChargeTargetSoC attribute" PICS: EEVSE.S.A0026 - verification: | - ./chip-tool energyevse read next-charge-target-so-c 1 1 - - On TH(chip-tool), Verify the NextChargeTargetSoC attribute contains a percent value, or null. - - [1703747625.575922][1922:1924] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0026 DataVersion: 1471857726 - [1703747625.576013][1922:1924] CHIP:TOO: NextChargeTargetSoC: null - disabled: true + command: "readAttribute" + attribute: "NextChargeTargetSoC" + response: + constraints: + type: percent + minValue: 0 + maxValue: 100 - label: "Step 17: TH writes to the DUT the ApproximateEVEfficiency attribute - value 3500." + value 3500" PICS: EEVSE.S.A0027 - verification: | - ./chip-tool energyevse write approximate-evefficiency 3500 1 1 - - On TH(chip-tool), Verify the SUCCESS response for ApproximateEVEfficiency attribute successful write. - - [1703747688.527575][1927:1929] CHIP:DMG: StatusIB = - [1703747688.527603][1927:1929] CHIP:DMG: { - [1703747688.527631][1927:1929] CHIP:DMG: status = 0x00 (SUCCESS), - [1703747688.527678][1927:1929] CHIP:DMG: }, - disabled: true + command: "writeAttribute" + attribute: "ApproximateEVEfficiency" + arguments: + value: 3500 - label: - "Step 17a: TH reads from the DUT the ApproximateEVEfficiency - attribute." + "Step 17a: TH reads from the DUT the ApproximateEVEfficiency attribute" PICS: EEVSE.S.A0027 - verification: | - ./chip-tool energyevse read approximate-evefficiency 1 1 - - On TH(chip-tool), Verify the ApproximateEVEfficiency attribute contains the uint16 value 3500. - - [1703747727.592819][1930:1932] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0027 DataVersion: 1471857728 - [1703747727.592870][1930:1932] CHIP:TOO: ApproximateEVEfficiency: 3500 - disabled: true - - - label: "Step 18: TH reads from the DUT the StateOfCharge attribute." + command: "readAttribute" + attribute: "ApproximateEVEfficiency" + response: + value: 3500 + constraints: + type: int16u + + - label: "Step 18: TH reads from the DUT the StateOfCharge attribute" PICS: EEVSE.S.A0030 - verification: | - ./chip-tool energyevse read state-of-charge 1 1 - - On TH(chip-tool), Verify the StateOfCharge attribute contains a percent value, or null. - - [1703747792.711492][1934:1936] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0030 DataVersion: 1471857728 - [1703747792.711546][1934:1936] CHIP:TOO: StateOfCharge: null - disabled: true - - - label: "Step 19: TH reads from the DUT the BatteryCapacity attribute." + command: "readAttribute" + attribute: "StateOfCharge" + response: + constraints: + type: percent + minValue: 0 + maxValue: 100 + + - label: "Step 19: TH reads from the DUT the BatteryCapacity attribute" PICS: EEVSE.S.A0031 - verification: | - ./chip-tool energyevse read battery-capacity 1 1 - - On TH(chip-tool), Verify the BatteryCapacity attribute contains an energy-mWh value or null. - - [1703747831.580988][1942:1944] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0031 DataVersion: 1471857728 - [1703747831.581068][1942:1944] CHIP:TOO: BatteryCapacity: null - disabled: true - - - label: "Step 20: TH reads from the DUT the VehicleID attribute." + command: "readAttribute" + attribute: "BatteryCapacity" + response: + constraints: + type: energy-mWh + minValue: 0 + + - label: "Step 20: TH reads from the DUT the VehicleID attribute" PICS: EEVSE.S.A0032 - verification: | - ./chip-tool energyevse read vehicle-id 1 1 - - On TH(chip-tool), Verify the VehicleID attribute contains a string value, or null. - - [1703747885.083733][1948:1950] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0032 DataVersion: 1471857728 - [1703747885.083795][1948:1950] CHIP:TOO: VehicleID: null - disabled: true - - - label: "Step 21: TH reads from the DUT the SessionID attribute." + command: "readAttribute" + attribute: "VehicleID" + response: + constraints: + type: char_string + maxLength: 32 + + - label: "Step 21: TH reads from the DUT the SessionID attribute" PICS: EEVSE.S.A0040 - verification: | - ./chip-tool energyevse read session-id 1 1 - - On TH(chip-tool), Verify the SessionID attribute contains a uint32 value, or null. - [1703747940.652133][1953:1955] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0040 DataVersion: 1471857728 - [1703747940.652210][1953:1955] CHIP:TOO: SessionID: null - disabled: true - - - label: "Step 22: TH reads from the DUT the SessionDuration attribute." + command: "readAttribute" + attribute: "SessionID" + response: + constraints: + type: int32u + minValue: 0 + maxValue: 2147483647 + + - label: "Step 22: TH reads from the DUT the SessionDuration attribute" PICS: EEVSE.S.A0041 - verification: | - ./chip-tool energyevse read session-duration 1 1 - - On TH(chip-tool), Verify the SessionDuration attribute contains an elapsed-s value or null. - - [1703747993.886193][1957:1959] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0041 DataVersion: 1471857728 - [1703747993.886248][1957:1959] CHIP:TOO: SessionDuration: null - disabled: true - - - label: - "Step 23: TH reads from the DUT the SessionEnergyCharged attribute." + command: "readAttribute" + attribute: "SessionDuration" + response: + constraints: + type: elapsed_s + minValue: 0 + maxValue: 2147483647 + + - label: "Step 23: TH reads from the DUT the SessionEnergyCharged attribute" PICS: EEVSE.S.A0042 - verification: | - ./chip-tool energyevse read session-energy-charged 1 1 - - On TH(chip-tool), Verify the SessionEnergyCharged attribute energy-mWh value is in the valid range(min 0) or null. - - [1703748035.855732][1962:1964] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0042 DataVersion: 1471857728 - [1703748035.855811][1962:1964] CHIP:TOO: SessionEnergyCharged: null - disabled: true + command: "readAttribute" + attribute: "SessionEnergyCharged" + response: + constraints: + type: energy-mWh + minValue: 0 - label: - "Step 24: TH reads from the DUT the SessionEnergyDischarged attribute." + "Step 24: TH reads from the DUT the SessionEnergyDischarged attribute" PICS: EEVSE.S.A0043 - verification: | - ./chip-tool energyevse read session-energy-discharged 1 1 - - On TH(chip-tool), Verify the SessionEnergyDischarged attribute energy-mWh value is in the valid range(min 0) or null. - - [1703748130.507623][1967:1970] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0099 Attribute 0x0000_0043 DataVersion: 1471857728 - [1703748130.507701][1967:1970] CHIP:TOO: SessionEnergyDischarged: null - disabled: true + command: "readAttribute" + attribute: "SessionEnergyDischarged" + response: + constraints: + type: energy-mWh + minValue: 0 diff --git a/src/app/tests/suites/certification/Test_TC_ICDM_3_4.yaml b/src/app/tests/suites/certification/Test_TC_ICDM_3_4.yaml index 2237dc6dae247c..7bbcb729489eef 100644 --- a/src/app/tests/suites/certification/Test_TC_ICDM_3_4.yaml +++ b/src/app/tests/suites/certification/Test_TC_ICDM_3_4.yaml @@ -11,96 +11,188 @@ # 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default -name: "[TC-ICDM-3.4] ICDCounter persistence with DUT as Server" +name: 217.1.6. [TC-ICDM-3.4] ICDCounter persistence with DUT as Server PICS: - ICDM.S config: nodeId: 0x12344321 - cluster: "Basic Information" + cluster: "ICD Management" endpoint: 0 + CheckInNodeID1: + type: node_id + defaultValue: 1 + MonitorSubID1: + type: subject-id + defaultValue: 2 + Key1: + type: octstr + defaultValue: "hex:1234567890abcdef1234567890abcdef" + IdleModedurationValue: + type: int16u + defaultValue: 5 + tests: - - label: "Preconditions" + - label: + "Precondition: Commission DUT to TH (can be skipped if done in a + preceding test)" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: + "Precondition: TH reads the RegisteredClients attribute from the DUT" + PICS: ICDM.S.A0003 + command: "readAttribute" + attribute: "RegisteredClients" + response: + saveAs: RegisteredClientsIDs + constraints: + type: list + + - label: + "Precondition: If list of registered clients is not empty, unregister + existing client(s)" verification: | - 1.Commission DUT to TH (can be skipped if done in a preceding test). - disabled: true + Please send the 'unregister client' command using the check-in nodeID received from the previous read + ./chip-tool icdmanagement unregister-client 112233 1 0 + + [1704888949.629057][71657:71659] CHIP:DMG: + [1704888949.629066][71657:71659] CHIP:DMG: InteractionModelRevision = 11 + [1704888949.629074][71657:71659] CHIP:DMG: }, + [1704888949.629125][71657:71659] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0002 Status=0x0 + [1704888949.629153][71657:71659] CHIP:DMG: ICR moving to [AwaitingDe] + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_USER_PROMPT && ICDM.S.C02.Rsp + arguments: + values: + - name: "message" + value: "Please enter 'y' for success" + - name: "expectedValue" + value: "y" + + - label: + "Precondition: TH reads from the DUT the RegisteredClients attribute. + Verify that the DUT response contains empty list of registered + clients." + PICS: ICDM.S.A0003 && PICS_USER_PROMPT + command: "readAttribute" + attribute: "RegisteredClients" + response: + value: [] + constraints: + type: list - label: "Step 1: TH reads from the DUT the IdleModeDuration attribute" PICS: ICDM.S.A0000 - verification: | - ./chip-tool icdmanagement read idle-mode-duration 1 0 - - [1702414709.798241][3855:3857] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0000 DataVersion: 2130984683 - [1702414709.798379][3855:3857] CHIP:TOO: IdleModeDuration: 3600 - disabled: true + command: "readAttribute" + attribute: "IdleModeDuration" + response: + saveAs: IdleModeDuration1 + constraints: + type: int32u + minValue: 1 + maxValue: 64800 - label: "Step 2: TH reads from the DUT the ICDCounter attribute." PICS: ICDM.S.A0004 - verification: | - ./chip-tool icdmanagement read icdcounter 1 0 - - [1702420930.466437][1422:1425] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0004 DataVersion: 2255930497 - [1702420930.469162][1422:1425] CHIP:TOO: ICDCounter: 1706188495 - disabled: true + command: "readAttribute" + attribute: "ICDCounter" + response: + saveAs: ICDCounter1 + constraints: + type: int32u + minValue: 0 + maxValue: 4294967295 - label: - "Step 3a: TH sends RegisterClient command. - CheckInNodeID: + "Step 3a & 3b: TH sends RegisterClient command. - CheckInNodeID: registering clients node ID (CheckInNodeID1) - MonitoredSubject: monitored subject ID (MonitorSubID1) - Key: shared secret between the - client and the ICD (Key1)" - PICS: ICDM.S.C00.Rsp - verification: | - ./chip-tool icdmanagement register-client 1 1 1234567890abcdef 1 0 - - [1702420936.087934][1426:1428] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0001 - [1702420936.088020][1426:1428] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Command 0x0000_0001 - [1702420936.088218][1426:1428] CHIP:TOO: RegisterClientResponse: { - [1702420936.088275][1426:1428] CHIP:TOO: ICDCounter: 1706188495 - [1702420936.088320][1426:1428] CHIP:TOO: } - disabled: true - - - label: - "Step 3b: Verify DUT responds w/ status SUCCESS(0x00); Verify that the - DUT response contains IcdCounter1" - PICS: ICDM.S.C01.Tx - verification: | - ./chip-tool icdmanagement register-client 1 1 1234567890abcdef 1 0 - - [1702420936.087934][1426:1428] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0001 - [1702420936.088020][1426:1428] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Command 0x0000_0001 - [1702420936.088218][1426:1428] CHIP:TOO: RegisterClientResponse: { - [1702420936.088275][1426:1428] CHIP:TOO: ICDCounter: 1706188495 - [1702420936.088320][1426:1428] CHIP:TOO: } - disabled: true + client and the ICD (Key1). Verify DUT responds w/ status + SUCCESS(0x00); Verify that the DUT response contains IcdCounter1" + PICS: ICDM.S.C00.Rsp && ICDM.S.C01.Tx + command: "RegisterClient" + arguments: + values: + - name: "CheckInNodeID" + value: CheckInNodeID1 + - name: "MonitoredSubject" + value: MonitorSubID1 + - name: "Key" + value: Key1 + response: + values: + - name: "ICDCounter" + value: ICDCounter1 + constraints: + type: int32u - label: "Step 4: Wait for 1 or more Idle Mode duration." - verification: | - Wait for 1 or more Idle Mode duration. - disabled: true - + cluster: "DelayCommands" + command: "WaitForMs" + arguments: + values: + - name: "ms" + value: ( IdleModedurationValue * 1000 ) + + #Issue https://github.com/project-chip/connectedhomeip/issues/31297 - label: "Step 5: TH reads from the DUT the ICDCounter attribute." - PICS: ICDM.S.A0004 verification: | ./chip-tool icdmanagement read icdcounter 1 0 [1702421000.635860][1431:1433] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0004 DataVersion: 2255930497 [1702421000.635970][1431:1433] CHIP:TOO: ICDCounter: 1706188496 - disabled: true + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_USER_PROMPT && ICDM.S.A0004 + arguments: + values: + - name: "message" + value: "Please enter 'y' for success" + - name: "expectedValue" + value: "y" - label: "Step 6: Reboot DUT" - verification: | - Reboot DUT - disabled: true + PICS: PICS_SDK_CI_ONLY + cluster: "SystemCommands" + endpoint: 0 + command: "Reboot" - - label: "Step 7: TH reads from the DUT the ICDCounter attribute." - PICS: ICDM.S.A0004 + - label: "Step Reboot target device(DUT)" verification: | - ./chip-tool icdmanagement read icdcounter 1 0 + Did the DUT successfully reboot? + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_SKIP_SAMPLE_APP + arguments: + values: + - name: "message" + value: "Please reboot the DUT and enter 'y' after DUT starts" + - name: "expectedValue" + value: "y" + + - label: "Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId - [1702421019.370137][1435:1437] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0004 DataVersion: 3029212499 - [1702421019.370232][1435:1437] CHIP:TOO: ICDCounter: 1706188596 - disabled: true + - label: "Step 7: TH reads from the DUT the ICDCounter attribute." + PICS: ICDM.S.A0004 && PICS_USER_PROMPT + command: "readAttribute" + attribute: "ICDCounter" + response: + constraints: + type: int32u + minValue: ICDCounter2 + maxValue: 4294967295 diff --git a/src/app/tests/suites/certification/Test_TC_IDM_1_3.yaml b/src/app/tests/suites/certification/Test_TC_IDM_1_3.yaml index de5625a8d11ad4..7e25cef6c174e1 100644 --- a/src/app/tests/suites/certification/Test_TC_IDM_1_3.yaml +++ b/src/app/tests/suites/certification/Test_TC_IDM_1_3.yaml @@ -31,6 +31,189 @@ tests: Chip-repl commands used below are an example to verify the DUT as client test cases. For certification test, we expect DUT should have a capability or way to run the equivalent command. disabled: true + - label: + "Step 0 (Pre-Condition 1): Commission TH Client to TH device (Server), + if not done so already." + verification: | + Ensure DUT is commissioned to TH device (Server). + disabled: true + + - label: + "Step 0 (Pre-Condition 2): Commission DUT to TH device (Server), if + not done so already." + verification: | + Ensure DUT is commissioned to TH device (Server). + This likely requires opening the commissioning window with TH Client." + disabled: true + + - label: + "Step 0 (Pre-Condition 3): TH Client send `FailAtFault` command to + `FaultInjection` cluster to TH device (Server)." + cluster: "FaultInjection" + command: "FailAtFault" + arguments: + values: + - name: "Type" + value: 3 + - name: "Id" + value: 12 + - name: "NumCallsToSkip" + value: 3 + - name: "NumCallsToFail" + value: 1 + - name: "TakeMutex" + value: false + verification: | + Equivalent TH Client command to run `chip-tool faultinjection fail-at-fault 3 12 3 1 false 1 0` + On TH(all-clusters-app), Verify command is successfully: + + CHIP:DMG: InvokeRequestMessage = + CHIP:DMG: { + CHIP:DMG: suppressResponse = false, + CHIP:DMG: timedRequest = false, + CHIP:DMG: InvokeRequests = + CHIP:DMG: [ + CHIP:DMG: CommandDataIB = + CHIP:DMG: { + CHIP:DMG: CommandPathIB = + CHIP:DMG: { + CHIP:DMG: EndpointId = 0x0, + CHIP:DMG: ClusterId = 0xfff1fc06, + CHIP:DMG: CommandId = 0x0, + CHIP:DMG: }, + CHIP:DMG: + CHIP:DMG: CommandFields = + CHIP:DMG: { + CHIP:DMG: 0x0 = 3, + CHIP:DMG: 0x1 = 12, + CHIP:DMG: 0x2 = 3, + CHIP:DMG: 0x3 = 1, + CHIP:DMG: 0x4 = false, + CHIP:DMG: }, + CHIP:DMG: }, + CHIP:DMG: + CHIP:DMG: ], + CHIP:DMG: + CHIP:DMG: InteractionModelRevision = 11 + CHIP:DMG: }, + CHIP:DMG: AccessControl: checking f=1 a=c s=0x000000000001B669 t= c=0xFFF1_FC06 e=0 p=m + CHIP:DMG: AccessControl: allowed + CHIP:DMG: Received command for Endpoint=0 Cluster=0xFFF1_FC06 Command=0x0000_0000 + CHIP:ZCL: FaultInjection: Configure a fault of type: 3 and Id: 12 to be triggered deterministically <--------- Verify success with this message. + disabled: true + + - label: + "Step 0 (Pre-Condition 4): TH Client send `FailAtFault` command to + `FaultInjection` cluster to TH device (Server)." + cluster: "FaultInjection" + command: "FailAtFault" + arguments: + values: + - name: "Type" + value: 3 + - name: "Id" + value: 13 + - name: "NumCallsToSkip" + value: 2 + - name: "NumCallsToFail" + value: 1 + - name: "TakeMutex" + value: false + verification: | + Equivalent TH Client command to run `chip-tool faultinjection fail-at-fault 3 13 2 1 false 1 0` + On TH(all-clusters-app), Verify command is successfully: + + CHIP:DMG: InvokeRequestMessage = + CHIP:DMG: { + CHIP:DMG: suppressResponse = false, + CHIP:DMG: timedRequest = false, + CHIP:DMG: InvokeRequests = + CHIP:DMG: [ + CHIP:DMG: CommandDataIB = + CHIP:DMG: { + CHIP:DMG: CommandPathIB = + CHIP:DMG: { + CHIP:DMG: EndpointId = 0x0, + CHIP:DMG: ClusterId = 0xfff1fc06, + CHIP:DMG: CommandId = 0x0, + CHIP:DMG: }, + CHIP:DMG: + CHIP:DMG: CommandFields = + CHIP:DMG: { + CHIP:DMG: 0x0 = 3, + CHIP:DMG: 0x1 = 13, + CHIP:DMG: 0x2 = 2, + CHIP:DMG: 0x3 = 1, + CHIP:DMG: 0x4 = false, + CHIP:DMG: }, + CHIP:DMG: }, + CHIP:DMG: + CHIP:DMG: ], + CHIP:DMG: + CHIP:DMG: InteractionModelRevision = 11 + CHIP:DMG: }, + CHIP:DMG: AccessControl: checking f=1 a=c s=0x000000000001B669 t= c=0xFFF1_FC06 e=0 p=m + CHIP:DMG: AccessControl: allowed + CHIP:DMG: Received command for Endpoint=0 Cluster=0xFFF1_FC06 Command=0x0000_0000 + CHIP:ZCL: FaultInjection: Configure a fault of type: 3 and Id: 13 to be triggered deterministically <--------- Verify success with this message. + disabled: true + + - label: + "Step 0 (Pre-Condition 5): TH Client send `FailAtFault` command to + `FaultInjection` cluster to TH device (Server)." + cluster: "FaultInjection" + command: "FailAtFault" + arguments: + values: + - name: "Type" + value: 3 + - name: "Id" + value: 14 + - name: "NumCallsToSkip" + value: 1 + - name: "NumCallsToFail" + value: 1 + - name: "TakeMutex" + value: false + verification: | + Equivalent TH Client command to run `chip-tool faultinjection fail-at-fault 3 14 1 1 false 1 0` + On TH(all-clusters-app), Verify command is successfully: + + CHIP:DMG: InvokeRequestMessage = + CHIP:DMG: { + CHIP:DMG: suppressResponse = false, + CHIP:DMG: timedRequest = false, + CHIP:DMG: InvokeRequests = + CHIP:DMG: [ + CHIP:DMG: CommandDataIB = + CHIP:DMG: { + CHIP:DMG: CommandPathIB = + CHIP:DMG: { + CHIP:DMG: EndpointId = 0x0, + CHIP:DMG: ClusterId = 0xfff1fc06, + CHIP:DMG: CommandId = 0x0, + CHIP:DMG: }, + CHIP:DMG: + CHIP:DMG: CommandFields = + CHIP:DMG: { + CHIP:DMG: 0x0 = 3, + CHIP:DMG: 0x1 = 14, + CHIP:DMG: 0x2 = 1, + CHIP:DMG: 0x3 = 1, + CHIP:DMG: 0x4 = false, + CHIP:DMG: }, + CHIP:DMG: }, + CHIP:DMG: + CHIP:DMG: ], + CHIP:DMG: + CHIP:DMG: InteractionModelRevision = 11 + CHIP:DMG: }, + CHIP:DMG: AccessControl: checking f=1 a=c s=0x000000000001B669 t= c=0xFFF1_FC06 e=0 p=m + CHIP:DMG: AccessControl: allowed + CHIP:DMG: Received command for Endpoint=0 Cluster=0xFFF1_FC06 Command=0x0000_0000 + CHIP:ZCL: FaultInjection: Configure a fault of type: 3 and Id: 14 to be triggered deterministically <--------- Verify success with this message. + disabled: true + - label: "Step 1: DUT sends the Invoke Request Message to the TH. The Message should contain two valid and unique paths in the CommandDataIBs, which has the specific Endpoints, specific Clusters @@ -40,7 +223,6 @@ tests: in a single InvokeResponseMessage, the ordering of CommandDataIBs in the InvokeResponseMessage SHALL be in the same order as provided in the request." - verification: | Product maker needs to provide instructions for how to trigger the command on the DUT that is capable of fitting into a single InvokeResponseMessage. For comparison, the DUT behavior for this test step can be simulated using chip-repl (when DUT is a commissioner/Client). @@ -104,7 +286,6 @@ tests: contain a response to the first CommandDataIB in the InvokeRequestMessage. The second InvokeReponseMessage SHALL contains a response to the second CommandDataIB in the InvokeRequestMessage." - verification: | Product maker needs to provide instructions for how to trigger the command this on the DUT that is capable of fitting into a single InvokeResponseMessage. For comparison, the DUT behavior for this test step can be simulated using chip-repl (when DUT is a commissioner/Client). @@ -112,7 +293,10 @@ tests: `await devCtrl.SendBatchCommands(0x12344321, [chip.clusters.Command.InvokeRequestInfo(1, chip.clusters.OnOff.Commands.Toggle()), chip.clusters.Command.InvokeRequestInfo(2, chip.clusters.OnOff.Commands.Toggle())])` - Verify DUT doesn't crash by seeing next step execute. + * Verify DUT doesn't crash by seeing next step execute. + * On TH(all-clusters-app), Verify following logs are seen: + CHIP:DMG: Response to InvokeRequestMessage overridden by fault injection + CHIP:DMG: Injecting the following response:Each response will be sent in a separate InvokeResponseMessage. The order of responses will be the same as the original request. disabled: true - label: "Step 3: DUT sends the Invoke Request Message to the TH. The @@ -125,7 +309,6 @@ tests: contain a response to the second CommandDataIB in the InvokeRequestMessage. The second InvokeReponseMessage SHALL contains a response to the first CommandDataIB in the InvokeRequestMessage." - verification: | Product maker needs to provide instructions for how to trigger the command this on the DUT that is capable of fitting into a single InvokeResponseMessage. For comparison, the DUT behavior for this test step can be simulated using chip-repl (when DUT is a commissioner/Client). @@ -133,7 +316,10 @@ tests: `await devCtrl.SendBatchCommands(0x12344321, [chip.clusters.Command.InvokeRequestInfo(1, chip.clusters.OnOff.Commands.Toggle()), chip.clusters.Command.InvokeRequestInfo(2, chip.clusters.OnOff.Commands.Toggle())])` - Verify DUT doesn't crash by seeing next step execute. + * Verify DUT doesn't crash by seeing next step execute. + * On TH(all-clusters-app), Verify following logs are seen: + CHIP:DMG: Response to InvokeRequestMessage overridden by fault injection + CHIP:DMG: Injecting the following response:Each response will be sent in a separate InvokeResponseMessage. The order of responses will be reversed from the original request. disabled: true - label: "Step 4: DUT sends the Invoke Request Message to the TH. The @@ -146,7 +332,6 @@ tests: InvokeResponseMessage SHALL contain a response to the first CommandDataIB in the InvokeRequestMessage. The second response to second CommandDataIB will intentionally be left out." - verification: | Product maker needs to provide instructions for how to trigger the command this on the DUT that is capable of fitting into a single InvokeResponseMessage. For comparison, the DUT behavior for this test step can be simulated using chip-repl (when DUT is a commissioner/Client). @@ -154,7 +339,10 @@ tests: `await devCtrl.SendBatchCommands(0x12344321, [chip.clusters.Command.InvokeRequestInfo(1, chip.clusters.OnOff.Commands.Toggle()), chip.clusters.Command.InvokeRequestInfo(2, chip.clusters.OnOff.Commands.Toggle())])` - Verify DUT doesn't crash by seeing next step execute. + * Verify DUT doesn't crash by seeing next step execute. + * On TH(all-clusters-app), Verify following logs are seen: + CHIP:DMG: Response to InvokeRequestMessage overridden by fault injection + CHIP:DMG: Injecting the following response:Single InvokeResponseMessages. Dropping response to second request disabled: true - label: "Step 5: DUT sends the Invoke Request Message to the TH. The @@ -163,7 +351,6 @@ tests: TH should be configured such that it responds regularly to single invoke request." - verification: | Product maker needs to provide instructions for how to trigger the command this on the DUT that is capable of fitting into a single InvokeResponseMessage. For comparison, the DUT behavior for this test step can be simulated using chip-repl (when DUT is a commissioner/Client). diff --git a/src/app/tests/suites/certification/Test_TC_ILL_2_1.yaml b/src/app/tests/suites/certification/Test_TC_ILL_2_1.yaml index 6afdb920658f94..741fc878e8880f 100644 --- a/src/app/tests/suites/certification/Test_TC_ILL_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_ILL_2_1.yaml @@ -86,4 +86,4 @@ tests: constraints: type: enum8 minValue: 0 - maxValue: 254 + maxValue: LightSensorTypeEnum.UnknownEnumValue(254) diff --git a/src/app/tests/suites/certification/Test_TC_I_2_3.yaml b/src/app/tests/suites/certification/Test_TC_I_2_3.yaml index 379ed424638c9b..343539ce69e624 100644 --- a/src/app/tests/suites/certification/Test_TC_I_2_3.yaml +++ b/src/app/tests/suites/certification/Test_TC_I_2_3.yaml @@ -237,7 +237,7 @@ tests: - name: "EffectIdentifier" value: 0 - name: "EffectVariant" - value: 66 + value: EffectVariantEnum.UnknownEnumValue(66) - label: "Check DUT executes a blink effect." cluster: "LogCommands" diff --git a/src/app/tests/suites/certification/Test_TC_LCFG_2_1.yaml b/src/app/tests/suites/certification/Test_TC_LCFG_2_1.yaml index 2dae158d9874dc..48af6aaebb275c 100644 --- a/src/app/tests/suites/certification/Test_TC_LCFG_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_LCFG_2_1.yaml @@ -48,7 +48,7 @@ tests: value: nodeId - label: "Step 1a: TH reads SupportedLocales attribute from DUT" - PICS: LCFG.S.A0000 + PICS: LCFG.S.A0001 command: "readAttribute" attribute: "SupportedLocales" response: @@ -81,7 +81,7 @@ tests: error: UNSUPPORTED_WRITE - label: "Step 3: TH reads SupportedLocales attribute from DUT" - PICS: LCFG.S.A0000 + PICS: LCFG.S.A0001 command: "readAttribute" attribute: "SupportedLocales" response: diff --git a/src/app/tests/suites/certification/Test_TC_LTIME_3_1.yaml b/src/app/tests/suites/certification/Test_TC_LTIME_3_1.yaml index 7e365a9fae6ed5..b011a94ce9cef7 100644 --- a/src/app/tests/suites/certification/Test_TC_LTIME_3_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_LTIME_3_1.yaml @@ -146,6 +146,22 @@ tests: verification: | Repeat the test step 8 for below mentioned values 1, 2,3, 4, 5, 6,7, 8, 9,10 and 11 and verify that TH receives the write command and updates the respective value. Verify that TH reads ActiveCalendarType attribute value and it is the same as the value that was set before + ./chip-tool timeformatlocalization write active-calendar-type 1 1 0 + + Verify that write request is successful on the TH(chip-tool) Log and and below is the sample log provided for raspi platform: + + [1685530839.323951][17790:17790] CHIP:DMG: StatusIB = + [1685530839.323956][17790:17790] CHIP:DMG: { + [1685530839.323961][17790:17790] CHIP:DMG: status = 0x00 (SUCCESS), + [1685530839.323965][17790:17790] CHIP:DMG: }, + + ./chip-tool timeformatlocalization read active-calendar-type 1 0 + + Verify ActiveCalendarType attribute value is 1 on the TH(chip-tool) Log and and below is the sample log provided for raspi platform: + + [1685530893.728748][17790:17790] CHIP:DMG: + [1685530893.728752][17790:17790] CHIP:DMG: Data = 1, + [1685530893.728755][17790:17790] CHIP:DMG: }, ./chip-tool timeformatlocalization write active-calendar-type 2 1 0 @@ -336,7 +352,7 @@ tests: command: "writeAttribute" attribute: "ActiveCalendarType" arguments: - value: 50 + value: CalendarTypeEnum.UnknownEnumValue(50) response: error: CONSTRAINT_ERROR @@ -345,6 +361,6 @@ tests: command: "writeAttribute" attribute: "HourFormat" arguments: - value: 5 + value: HourFormatEnum.UnknownEnumValue(5) response: error: CONSTRAINT_ERROR diff --git a/src/app/tests/suites/certification/Test_TC_LUNIT_3_1.yaml b/src/app/tests/suites/certification/Test_TC_LUNIT_3_1.yaml index a572f7e143dc43..b67c22a871ced9 100644 --- a/src/app/tests/suites/certification/Test_TC_LUNIT_3_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_LUNIT_3_1.yaml @@ -94,6 +94,6 @@ tests: arguments: # Per spec, if [TEMP] feature is enabled, then this attribute can be # one of 0 (Farenheit), 1 (Celsius) or 2 (Kelvin) - value: 5 # INVALID + value: TempUnitEnum.UnknownEnumValue(5) response: error: CONSTRAINT_ERROR diff --git a/src/app/tests/suites/certification/Test_TC_LWM_1_1.yaml b/src/app/tests/suites/certification/Test_TC_LWM_1_1.yaml index 7c7caff3a7ce71..0b8b51fcbe3f10 100644 --- a/src/app/tests/suites/certification/Test_TC_LWM_1_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_LWM_1_1.yaml @@ -41,9 +41,10 @@ tests: constraints: type: int16u + #Issue https://github.com/project-chip/connectedhomeip/issues/31551 - label: "Step 3:TH reads from the DUT the FeatureMap attribute., bit 0: SHALL - be 1 if and only if LWM.S.F00(DEPONOFF)" + be 1 if and only if LWM.S.F00" command: "readAttribute" attribute: "FeatureMap" PICS: LWM.S.F00 @@ -90,9 +91,9 @@ tests: type: list contains: [2] + #Issue https://github.com/project-chip/connectedhomeip/issues/31551 - label: - "Step 4c: TH reads the Feature dependent attribute(DEPONOFF) in - AttributeList" + "Step 4c: TH reads the Feature dependent attribute in AttributeList" PICS: LWM.S.F00 command: "readAttribute" attribute: "AttributeList" diff --git a/src/app/tests/suites/certification/Test_TC_LWM_1_2.yaml b/src/app/tests/suites/certification/Test_TC_LWM_1_2.yaml index 39c4a04ceb7163..fc9a0211fb7caf 100644 --- a/src/app/tests/suites/certification/Test_TC_LWM_1_2.yaml +++ b/src/app/tests/suites/certification/Test_TC_LWM_1_2.yaml @@ -99,25 +99,3 @@ tests: [1690184642.211028][15428:15430] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0051 Attribute 0x0000_0001 DataVersion: 3075628268 [1690184642.211042][15428:15430] CHIP:TOO: CurrentMode: 0 disabled: true - - - label: "Step 4: TH reads from the DUT the OnMode attribute." - PICS: LWM.S.A0003 - verification: | - ./chip-tool laundrywashermode read on-mode 1 1 - - Verify on TH(chip-tool) logs, OnMode attribute value is an integer value from supported_modes_dut or null, below is the sample log provided for the raspi platform, Here OnMode attribute value is Null - - [1690184668.519026][15432:15434] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0051 Attribute 0x0000_0003 DataVersion: 3075628268 - [1690184668.519041][15432:15434] CHIP:TOO: OnMode: null - disabled: true - - - label: "Step 5: TH reads from the DUT the StartUpMode attribute." - PICS: LWM.S.A0002 - verification: | - ./chip-tool laundrywashermode read start-up-mode 1 1 - - Verify on TH(chip-tool) logs, StartUpMode attribute value is an integer value from supported_modes_dut or null, below is the sample log provided for the raspi platform, Here StartUpMode attribute value is Null - - [1690184690.235037][15436:15438] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0051 Attribute 0x0000_0002 DataVersion: 3075628268 - [1690184690.235048][15436:15438] CHIP:TOO: StartUpMode: null - disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_LWM_2_1.yaml b/src/app/tests/suites/certification/Test_TC_LWM_2_1.yaml index a6a916f1b2e2d8..b3535b13ceec51 100644 --- a/src/app/tests/suites/certification/Test_TC_LWM_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_LWM_2_1.yaml @@ -177,7 +177,7 @@ tests: command: "readAttribute" attribute: "CurrentMode" response: - value: Step6_current_mode_dut + value: old_current_mode_dut constraints: type: int8u minValue: 0 diff --git a/src/app/tests/suites/certification/Test_TC_LWM_3_1.yaml b/src/app/tests/suites/certification/Test_TC_LWM_3_1.yaml index 0b9a36eba56e80..2bafddfa303f64 100644 --- a/src/app/tests/suites/certification/Test_TC_LWM_3_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_LWM_3_1.yaml @@ -16,7 +16,7 @@ name: 183.3.1. [TC-LWM-3.1] On Mode functionality with DUT as Server PICS: - LWM.S.A0003 - - LWM.S.F00 + - MOD.S.F00 - OO.S.C00.Rsp - OO.S.C01.Rsp @@ -47,14 +47,14 @@ tests: "Precondition: TH writes from the DUT the OnMode attribute.NOTE: To execute this test case set onmode to any integer value because as default it value has null." - PICS: LWM.S.A0003 && LWM.S.F00 + PICS: LWM.S.A0003 && MOD.S.F00 command: "writeAttribute" attribute: "OnMode" arguments: value: ConfigureOnMode - label: "Step 2: TH reads from the DUT the OnMode attribute." - PICS: LWM.S.A0003 && LWM.S.F00 + PICS: LWM.S.A0003 && MOD.S.F00 command: "readAttribute" attribute: "OnMode" response: @@ -65,7 +65,7 @@ tests: maxValue: 254 - label: "Step 3: TH reads from the DUT the CurrentMode attribute." - PICS: LWM.S.A0001 && LWM.S.F00 + PICS: LWM.S.A0001 && MOD.S.F00 command: "readAttribute" attribute: "CurrentMode" response: @@ -93,7 +93,7 @@ tests: - label: "Step 4: TH reads from the DUT the SupportedModes attribute." runIf: IsExpectedValue - PICS: LWM.S.A0000 && LWM.S.F00 + PICS: LWM.S.A0000 && MOD.S.F00 command: "readAttribute" attribute: "SupportedModes" response: @@ -105,7 +105,7 @@ tests: "Step 5: TH sends a ChangeToMode command to the DUT with NewMode set to new_mode_th" runIf: IsExpectedValue - PICS: LWM.S.C00.Rsp && LWM.S.F00 + PICS: LWM.S.C00.Rsp && MOD.S.F00 command: "ChangeToMode" arguments: values: @@ -117,17 +117,17 @@ tests: value: 0x00 - label: "Step 6:TH sends a Off command to the DUT" - PICS: OO.S.C00.Rsp && LWM.S.F00 + PICS: OO.S.C00.Rsp && MOD.S.F00 cluster: "On/Off" command: "Off" - label: "Step 7:TH sends a On command to the DUT" - PICS: OO.S.C01.Rsp && LWM.S.F00 + PICS: OO.S.C01.Rsp && MOD.S.F00 cluster: "On/Off" command: "On" - label: "Step 8: TH reads from the DUT the CurrentMode attribute." - PICS: LWM.S.A0001 && LWM.S.F00 + PICS: LWM.S.A0001 && MOD.S.F00 command: "readAttribute" attribute: "CurrentMode" response: diff --git a/src/app/tests/suites/certification/Test_TC_LWM_3_3.yaml b/src/app/tests/suites/certification/Test_TC_LWM_3_3.yaml index 8250418368643d..bf97f17f286154 100644 --- a/src/app/tests/suites/certification/Test_TC_LWM_3_3.yaml +++ b/src/app/tests/suites/certification/Test_TC_LWM_3_3.yaml @@ -19,7 +19,7 @@ name: PICS: - LWM.S.A0002 - LWM.S.A0003 - - LWM.S.F00 + - MOD.S.F00 - OO.S.A4003 config: @@ -136,7 +136,7 @@ tests: value: new_mode_th - label: "Step 8: TH reads from the DUT the OnMode attribute." - PICS: LWM.S.A0003 && LWM.S.F00 + PICS: LWM.S.A0003 && MOD.S.F00 command: "readAttribute" attribute: "OnMode" response: diff --git a/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_10.yaml b/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_10.yaml index fce8304cea1c83..6e2fbf37ac8cad 100644 --- a/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_10.yaml +++ b/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_10.yaml @@ -30,39 +30,40 @@ tests: verification: | Product maker needs to provide instructions for how to trigger the command on the DUT. For comparison, the DUT behavior for this test step can be simulated using chip-tool (when DUT is a commissioner) or tv-casting-app (when DUT is a commissionee): - ./chip-tool mediaplayback activate-audio-track 1 2 1 1 + ./chip-tool mediaplayback activate-audio-track activeAudioTrackId_1 0 1 3 On TH (tv-app), Verify the ActivateAudioTrack command is received successfully. - - [1705561368.453512][4597:4597] CHIP:EM: Handling via exchange: 56290r, Delegate: 0xaaaad1391778 - [1705561368.453660][4597:4597] CHIP:DMG: InvokeRequestMessage = - [1705561368.453721][4597:4597] CHIP:DMG: { - [1705561368.453772][4597:4597] CHIP:DMG: suppressResponse = false, - [1705561368.453833][4597:4597] CHIP:DMG: timedRequest = false, - [1705561368.453890][4597:4597] CHIP:DMG: InvokeRequests = - [1705561368.453995][4597:4597] CHIP:DMG: [ - [1705561368.454052][4597:4597] CHIP:DMG: CommandDataIB = - [1705561368.454139][4597:4597] CHIP:DMG: { - [1705561368.454200][4597:4597] CHIP:DMG: CommandPathIB = - [1705561368.454273][4597:4597] CHIP:DMG: { - [1705561368.454367][4597:4597] CHIP:DMG: EndpointId = 0x1, - [1705561368.454442][4597:4597] CHIP:DMG: ClusterId = 0x506, - [1705561368.454536][4597:4597] CHIP:DMG: CommandId = 0xc, - [1705561368.454610][4597:4597] CHIP:DMG: }, - [1705561368.454721][4597:4597] CHIP:DMG: - [1705561368.454807][4597:4597] CHIP:DMG: CommandFields = - [1705561368.454879][4597:4597] CHIP:DMG: { - [1705561368.454976][4597:4597] CHIP:DMG: 0x0 = "1" (1 chars), - [1705561368.455055][4597:4597] CHIP:DMG: 0x1 = 2, - [1705561368.455130][4597:4597] CHIP:DMG: }, - [1705561368.455195][4597:4597] CHIP:DMG: }, - [1705561368.455297][4597:4597] CHIP:DMG: - [1705561368.455354][4597:4597] CHIP:DMG: ], - [1705561368.455447][4597:4597] CHIP:DMG: - [1705561368.455504][4597:4597] CHIP:DMG: InteractionModelRevision = 11 - [1705561368.455559][4597:4597] CHIP:DMG: }, - [1705561368.455805][4597:4597] CHIP:DMG: AccessControl: checking f=2 a=c s=0x000000000001B669 t= c=0x0000_0506 e=1 p=o - [1705561368.455903][4597:4597] CHIP:DMG: AccessControl: allowed + [1706092346.813652][4555:4555] CHIP:EM: Handling via exchange: 39139r, Delegate: 0xaaaaabf7a7c8 + [1706092346.813745][4555:4555] CHIP:DMG: InvokeRequestMessage = + [1706092346.813775][4555:4555] CHIP:DMG: { + [1706092346.813800][4555:4555] CHIP:DMG: suppressResponse = false, + [1706092346.813829][4555:4555] CHIP:DMG: timedRequest = false, + [1706092346.813857][4555:4555] CHIP:DMG: InvokeRequests = + [1706092346.813892][4555:4555] CHIP:DMG: [ + [1706092346.813919][4555:4555] CHIP:DMG: CommandDataIB = + [1706092346.813949][4555:4555] CHIP:DMG: { + [1706092346.813975][4555:4555] CHIP:DMG: CommandPathIB = + [1706092346.814004][4555:4555] CHIP:DMG: { + [1706092346.814041][4555:4555] CHIP:DMG: EndpointId = 0x3, + [1706092346.814077][4555:4555] CHIP:DMG: ClusterId = 0x506, + [1706092346.814111][4555:4555] CHIP:DMG: CommandId = 0xc, + [1706092346.814145][4555:4555] CHIP:DMG: }, + [1706092346.814179][4555:4555] CHIP:DMG: + [1706092346.814209][4555:4555] CHIP:DMG: CommandFields = + [1706092346.814242][4555:4555] CHIP:DMG: { + [1706092346.814278][4555:4555] CHIP:DMG: 0x0 = "activeAudioTrackId_1" (20 chars), + [1706092346.814316][4555:4555] CHIP:DMG: 0x1 = 0, + [1706092346.814351][4555:4555] CHIP:DMG: }, + [1706092346.814382][4555:4555] CHIP:DMG: }, + [1706092346.814417][4555:4555] CHIP:DMG: + [1706092346.814443][4555:4555] CHIP:DMG: ], + [1706092346.814476][4555:4555] CHIP:DMG: + [1706092346.814502][4555:4555] CHIP:DMG: InteractionModelRevision = 11 + [1706092346.814527][4555:4555] CHIP:DMG: }, + [1706092346.814651][4555:4555] CHIP:DMG: AccessControl: checking f=2 a=c s=0x000000000001B669 t= c=0x0000_0506 e=3 p=o + [1706092346.814692][4555:4555] CHIP:DMG: AccessControl: allowed + [1706092346.814776][4555:4555] CHIP:DMG: Received command for Endpoint=3 Cluster=0x0000_0506 Command=0x0000_000C + [1706092346.814824][4555:4555] CHIP:DL: GetContentAppByEndpointId() - endpoint 3 not found disabled: true - label: "Step 2: DUT sends ActivateTextTrack command to TH" @@ -70,38 +71,42 @@ tests: verification: | Product maker needs to provide instructions for how to trigger the command on the DUT. For comparison, the DUT behavior for this test step can be simulated using chip-tool (when DUT is a commissioner) or tv-casting-app (when DUT is a commissionee): - ./chip-tool mediaplayback activate-text-track 1 1 1 + ./chip-tool mediaplayback activate-text-track activeTextTrackId_1 1 3 On TH (tv-app), Verify the ActivateTextTrack command is received successfully. - [1705561407.549846][4597:4597] CHIP:EM: Handling via exchange: 12272r, Delegate: 0xaaaad1391778 - [1705561407.549918][4597:4597] CHIP:DMG: InvokeRequestMessage = - [1705561407.549942][4597:4597] CHIP:DMG: { - [1705561407.549961][4597:4597] CHIP:DMG: suppressResponse = false, - [1705561407.549999][4597:4597] CHIP:DMG: timedRequest = false, - [1705561407.550020][4597:4597] CHIP:DMG: InvokeRequests = - [1705561407.550048][4597:4597] CHIP:DMG: [ - [1705561407.550069][4597:4597] CHIP:DMG: CommandDataIB = - [1705561407.550103][4597:4597] CHIP:DMG: { - [1705561407.550125][4597:4597] CHIP:DMG: CommandPathIB = - [1705561407.550162][4597:4597] CHIP:DMG: { - [1705561407.550190][4597:4597] CHIP:DMG: EndpointId = 0x1, - [1705561407.550227][4597:4597] CHIP:DMG: ClusterId = 0x506, - [1705561407.550255][4597:4597] CHIP:DMG: CommandId = 0xd, - [1705561407.550290][4597:4597] CHIP:DMG: }, - [1705561407.550319][4597:4597] CHIP:DMG: - [1705561407.550342][4597:4597] CHIP:DMG: CommandFields = - [1705561407.550379][4597:4597] CHIP:DMG: { - [1705561407.550409][4597:4597] CHIP:DMG: 0x0 = "1" (1 chars), - [1705561407.550446][4597:4597] CHIP:DMG: }, - [1705561407.550470][4597:4597] CHIP:DMG: }, - [1705561407.550504][4597:4597] CHIP:DMG: - [1705561407.550526][4597:4597] CHIP:DMG: ], - [1705561407.550553][4597:4597] CHIP:DMG: - [1705561407.550584][4597:4597] CHIP:DMG: InteractionModelRevision = 11 - [1705561407.550605][4597:4597] CHIP:DMG: }, - [1705561407.550765][4597:4597] CHIP:DMG: AccessControl: checking f=2 a=c s=0x000000000001B669 t= c=0x0000_0506 e=1 p=o - [1705561407.550811][4597:4597] CHIP:DMG: AccessControl: allowed + [1706092322.174823][4555:4555] CHIP:EM: Handling via exchange: 27897r, Delegate: 0xaaaaabf7a7c8 + [1706092322.174908][4555:4555] CHIP:DMG: InvokeRequestMessage = + [1706092322.174936][4555:4555] CHIP:DMG: { + [1706092322.174956][4555:4555] CHIP:DMG: suppressResponse = false, + [1706092322.174981][4555:4555] CHIP:DMG: timedRequest = false, + [1706092322.175002][4555:4555] CHIP:DMG: InvokeRequests = + [1706092322.175030][4555:4555] CHIP:DMG: [ + [1706092322.175051][4555:4555] CHIP:DMG: CommandDataIB = + [1706092322.175077][4555:4555] CHIP:DMG: { + [1706092322.175101][4555:4555] CHIP:DMG: CommandPathIB = + [1706092322.175128][4555:4555] CHIP:DMG: { + [1706092322.175156][4555:4555] CHIP:DMG: EndpointId = 0x3, + [1706092322.175184][4555:4555] CHIP:DMG: ClusterId = 0x506, + [1706092322.175212][4555:4555] CHIP:DMG: CommandId = 0xd, + [1706092322.175239][4555:4555] CHIP:DMG: }, + [1706092322.175267][4555:4555] CHIP:DMG: + [1706092322.175291][4555:4555] CHIP:DMG: CommandFields = + [1706092322.175317][4555:4555] CHIP:DMG: { + [1706092322.175347][4555:4555] CHIP:DMG: 0x0 = "activeTextTrackId_1" (19 chars), + [1706092322.175376][4555:4555] CHIP:DMG: }, + [1706092322.175401][4555:4555] CHIP:DMG: }, + [1706092322.175428][4555:4555] CHIP:DMG: + [1706092322.175448][4555:4555] CHIP:DMG: ], + [1706092322.175475][4555:4555] CHIP:DMG: + [1706092322.175496][4555:4555] CHIP:DMG: InteractionModelRevision = 11 + [1706092322.175517][4555:4555] CHIP:DMG: }, + [1706092322.175618][4555:4555] CHIP:DMG: AccessControl: checking f=2 a=c s=0x000000000001B669 t= c=0x0000_0506 e=3 p=o + [1706092322.175653][4555:4555] CHIP:DMG: AccessControl: allowed + [1706092322.175678][4555:4555] CHIP:DMG: Received command for Endpoint=3 Cluster=0x0000_0506 Command=0x0000_000D + [1706092322.175713][4555:4555] CHIP:DL: GetContentAppByEndpointId() - endpoint 3 not found + [1706092322.175733][4555:4555] CHIP:ZCL: MediaPlayback NOT returning ContentApp delegate for endpoint:3 + [1706092322.175784][4555:4555] CHIP:DMG: Command handler moving to [NewRespons] disabled: true - label: "Step 1: DUT sends DeactivateTextTrack command to TH" @@ -109,35 +114,34 @@ tests: verification: | Product maker needs to provide instructions for how to trigger the command on the DUT. For comparison, the DUT behavior for this test step can be simulated using chip-tool (when DUT is a commissioner) or tv-casting-app (when DUT is a commissionee): - ./chip-tool mediaplayback deactivate-text-track 1 1 + ./chip-tool mediaplayback deactivate-text-track 1 3 On TH (tv-app), Verify the DeactivateTextTrack command is received successfully. - - [1705561431.594454][4597:4597] CHIP:EM: Handling via exchange: 47051r, Delegate: 0xaaaad1391778 - [1705561431.594534][4597:4597] CHIP:DMG: InvokeRequestMessage = - [1705561431.594564][4597:4597] CHIP:DMG: { - [1705561431.594588][4597:4597] CHIP:DMG: suppressResponse = false, - [1705561431.594689][4597:4597] CHIP:DMG: timedRequest = false, - [1705561431.594718][4597:4597] CHIP:DMG: InvokeRequests = - [1705561431.594764][4597:4597] CHIP:DMG: [ - [1705561431.594791][4597:4597] CHIP:DMG: CommandDataIB = - [1705561431.594821][4597:4597] CHIP:DMG: { - [1705561431.594848][4597:4597] CHIP:DMG: CommandPathIB = - [1705561431.594891][4597:4597] CHIP:DMG: { - [1705561431.594931][4597:4597] CHIP:DMG: EndpointId = 0x1, - [1705561431.594978][4597:4597] CHIP:DMG: ClusterId = 0x506, - [1705561431.595013][4597:4597] CHIP:DMG: CommandId = 0xe, - [1705561431.595056][4597:4597] CHIP:DMG: }, - [1705561431.595092][4597:4597] CHIP:DMG: - [1705561431.595130][4597:4597] CHIP:DMG: CommandFields = - [1705561431.595164][4597:4597] CHIP:DMG: { - [1705561431.595196][4597:4597] CHIP:DMG: }, - [1705561431.595235][4597:4597] CHIP:DMG: }, - [1705561431.595271][4597:4597] CHIP:DMG: - [1705561431.595297][4597:4597] CHIP:DMG: ], - [1705561431.595341][4597:4597] CHIP:DMG: - [1705561431.595367][4597:4597] CHIP:DMG: InteractionModelRevision = 11 - [1705561431.595403][4597:4597] CHIP:DMG: }, - [1705561431.595522][4597:4597] CHIP:DMG: AccessControl: checking f=2 a=c s=0x000000000001B669 t= c=0x0000_0506 e=1 p=o - [1705561431.595573][4597:4597] CHIP:DMG: AccessControl: allowed + [1706092292.772177][4555:4555] CHIP:DMG: InvokeRequestMessage = + [1706092292.772202][4555:4555] CHIP:DMG: { + [1706092292.772221][4555:4555] CHIP:DMG: suppressResponse = false, + [1706092292.772242][4555:4555] CHIP:DMG: timedRequest = false, + [1706092292.772262][4555:4555] CHIP:DMG: InvokeRequests = + [1706092292.772287][4555:4555] CHIP:DMG: [ + [1706092292.772306][4555:4555] CHIP:DMG: CommandDataIB = + [1706092292.772330][4555:4555] CHIP:DMG: { + [1706092292.772351][4555:4555] CHIP:DMG: CommandPathIB = + [1706092292.772376][4555:4555] CHIP:DMG: { + [1706092292.772401][4555:4555] CHIP:DMG: EndpointId = 0x3, + [1706092292.772428][4555:4555] CHIP:DMG: ClusterId = 0x506, + [1706092292.772453][4555:4555] CHIP:DMG: CommandId = 0xe, + [1706092292.772477][4555:4555] CHIP:DMG: }, + [1706092292.772503][4555:4555] CHIP:DMG: + [1706092292.772524][4555:4555] CHIP:DMG: CommandFields = + [1706092292.772547][4555:4555] CHIP:DMG: { + [1706092292.772571][4555:4555] CHIP:DMG: }, + [1706092292.772592][4555:4555] CHIP:DMG: }, + [1706092292.772615][4555:4555] CHIP:DMG: + [1706092292.772634][4555:4555] CHIP:DMG: ], + [1706092292.772657][4555:4555] CHIP:DMG: + [1706092292.772675][4555:4555] CHIP:DMG: InteractionModelRevision = 11 + [1706092292.772694][4555:4555] CHIP:DMG: }, + [1706092292.772782][4555:4555] CHIP:DMG: AccessControl: checking f=2 a=c s=0x000000000001B669 t= c=0x0000_0506 e=3 p=o + [1706092292.772814][4555:4555] CHIP:DMG: AccessControl: allowed + [1706092292.772837][4555:4555] CHIP:DMG: Received command for Endpoint=3 Cluster=0x0000_0506 Command=0x0000_000E disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_8.yaml b/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_8.yaml index 7514964cabce09..a4fed0de0f90a3 100644 --- a/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_8.yaml +++ b/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_8.yaml @@ -11,7 +11,6 @@ # 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default name: 19.8.7. [TC-MEDIAPLAYBACK-6.8] Text Track Verification @@ -20,77 +19,53 @@ PICS: config: nodeId: 0x12344321 - cluster: "Basic Information" - endpoint: 0 + cluster: "Media Playback" + endpoint: 3 + + ID_Value: + type: CHAR_STRING + defaultValue: activeTextTrackId_0 tests: - - label: "Preconditions" - verification: | - 1.DUT is powered on and not in a low power state - 2.DUT has media playing with no corresponding text appearing on screen (text tracks are disabled) - disabled: true + - label: + "Commission DUT to TH (can be skipped if done in a preceding test)." + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId - label: "Step 1: TH reads the ActiveTextTrack attribute from the DUT" PICS: MEDIAPLAYBACK.S.A0009 - verification: | - ./chip-tool mediaplayback read active-text-track 1 3 - - [1705510042.296465][16330:16332] CHIP:DMG: InteractionModelRevision = 11 - [1705510042.296473][16330:16332] CHIP:DMG: } - [1705510042.296562][16330:16332] CHIP:TOO: Endpoint: 3 Cluster: 0x0000_0506 Attribute 0x0000_0009 DataVersion: 900375739 - [1705510042.296659][16330:16332] CHIP:TOO: ActiveTextTrack: { - [1705510042.296668][16330:16332] CHIP:TOO: Id: activeTextTrackId_0 - [1705510042.296701][16330:16332] CHIP:TOO: TrackAttributes: { - [1705510042.296710][16330:16332] CHIP:TOO: LanguageCode: languageCode1 - [1705510042.296722][16330:16332] CHIP:TOO: DisplayName: displayName1 - [1705510042.296731][16330:16332] CHIP:TOO: } - [1705510042.296741][16330:16332] CHIP:TOO: } - [1705510042.296826][16330:16332] CHIP:EM: <<< [E:46686i S:46889 M:218476891 (Ack:232741748)] (S) Msg TX to 1:0000000000000001 [DC0D] [UDP:[fe80::a151:a1e6:e7:e224%wlp0s20f3]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1705510042.296863][16330:16332] CHIP:EM: Flushed pending ack for MessageCounter:232741748 on exchange 46686i - disabled: true + command: "readAttribute" + attribute: "ActiveTextTrack" + response: + value: { ID: "", TrackAttributes: null } - label: "Step 2: TH reads the AvailableTextTracks attribute from the DUT" PICS: MEDIAPLAYBACK.S.A000a - verification: | - ./chip-tool mediaplayback read available-text-tracks 1 3 - - [1705510341.175871][16392:16394] CHIP:DMG: InteractionModelRevision = 11 - [1705510341.175877][16392:16394] CHIP:DMG: } - [1705510341.176016][16392:16394] CHIP:TOO: Endpoint: 3 Cluster: 0x0000_0506 Attribute 0x0000_000A DataVersion: 900375739 - [1705510341.176056][16392:16394] CHIP:TOO: AvailableTextTracks: 2 entries - [1705510341.176114][16392:16394] CHIP:TOO: [1]: { - [1705510341.176121][16392:16394] CHIP:TOO: Id: activeTextTrackId_0 - [1705510341.176142][16392:16394] CHIP:TOO: TrackAttributes: { - [1705510341.176148][16392:16394] CHIP:TOO: LanguageCode: languageCode1 - [1705510341.176156][16392:16394] CHIP:TOO: DisplayName: displayName1 - [1705510341.176163][16392:16394] CHIP:TOO: } - [1705510341.176169][16392:16394] CHIP:TOO: } - [1705510341.176184][16392:16394] CHIP:TOO: [2]: { - [1705510341.176189][16392:16394] CHIP:TOO: Id: activeTextTrackId_1 - [1705510341.176195][16392:16394] CHIP:TOO: TrackAttributes: { - [1705510341.176200][16392:16394] CHIP:TOO: LanguageCode: languageCode2 - [1705510341.176206][16392:16394] CHIP:TOO: DisplayName: displayName2 - [1705510341.176212][16392:16394] CHIP:TOO: } - [1705510341.176218][16392:16394] CHIP:TOO: } - [1705510341.176307][16392:16394] CHIP:EM: <<< [E:6048i S:22581 M:56736636 (Ack:198505019)] (S) Msg TX to 1:0000000000000001 [DC0D] [UDP:[fe80::a151:a1e6:e7:e224%wlp0s20f3]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1705510341.176351][16392:16394] CHIP:EM: Flushed pending ack for MessageCounter:198505019 o - disabled: true + command: "readAttribute" + attribute: "AvailableTextTracks" + response: + constraints: + type: list + minLength: 1 - label: "Step 3: TH sends a ActivateTextTrack command to DUT specifying the ID value from step 2" PICS: MEDIAPLAYBACK.S.C0d.Rsp verification: | - ./chip-tool mediaplayback activate-text-track activeAudioTrackId_0 1 3 - - [1705510090.516480][16340:16342] CHIP:DMG: ], - [1705510090.516490][16340:16342] CHIP:DMG: - [1705510090.516496][16340:16342] CHIP:DMG: InteractionModelRevision = 11 - [1705510090.516502][16340:16342] CHIP:DMG: }, - [1705510090.516532][16340:16342] CHIP:DMG: Received Command Response Status for Endpoint=3 Cluster=0x0000_0506 Command=0x0000_000D Status=0x0 - [1705510090.516551][16340:16342] CHIP:DMG: ICR moving to [AwaitingDe] - [1705510090.516603][16340:16342] CHIP:EM: <<< [E:38439i S:17770 M:29388041 (Ack:36384138)] (S) Msg TX to 1:0000000000000001 [DC0D] [UDP:[fe80::a151:a1e6:e7:e224%wlp0s20f3]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1705510090.516635][16340:16342] CHIP:EM: Flushed pending ack for MessageCounter:36384138 on exchange 38439i + ./chip-tool mediaplayback activate-text-track activeTextTrackId_1 1 3 + + On TH(chip-tool), Verify response is a successful (value 0) status response + + [1705920343.780331][14340:14342] CHIP:DMG: InteractionModelRevision = 11 + [1705920343.780356][14340:14342] CHIP:DMG: }, + [1705920343.780439][14340:14342] CHIP:DMG: Received Command Response Status for Endpoint=3 Cluster=0x0000_0506 Command=0x0000_000D Status=0x0 + [1705920343.780508][14340:14342] CHIP:DMG: ICR moving to [AwaitingDe] + [1705920343.780756][14340:14342] CHIP:EM: <<< [E:28106i S:13054 M:170208295 (Ack:222967153)] (S) Msg TX to 1:0000000000000001 [D27C] [UDP:[fe80::e65f:1ff:fe0f:19ff%wlan0]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) disabled: true - label: "Step 4: TH reads the ActiveTextTrack attribute from the DUT" @@ -98,22 +73,19 @@ tests: verification: | ./chip-tool mediaplayback read active-text-track 1 3 - [1705510111.140989][16347:16349] CHIP:DMG: SuppressResponse = true, - [1705510111.140995][16347:16349] CHIP:DMG: InteractionModelRevision = 11 - [1705510111.141001][16347:16349] CHIP:DMG: } - [1705510111.141083][16347:16349] CHIP:TOO: Endpoint: 3 Cluster: 0x0000_0506 Attribute 0x0000_0009 DataVersion: 900375739 - [1705510111.141165][16347:16349] CHIP:TOO: ActiveTextTrack: { - [1705510111.141173][16347:16349] CHIP:TOO: Id: activeTextTrackId_0 - [1705510111.141193][16347:16349] CHIP:TOO: TrackAttributes: { - [1705510111.141200][16347:16349] CHIP:TOO: LanguageCode: languageCode1 - [1705510111.141207][16347:16349] CHIP:TOO: DisplayName: displayName1 - [1705510111.141214][16347:16349] CHIP:TOO: } - [1705510111.141220][16347:16349] CHIP:TOO: } - [1705510111.141301][16347:16349] CHIP:EM: <<< [E:17921i S:33385 M:33192485 (Ack:130923512)] (S) Msg TX to 1:0000000000000001 [DC0D] [UDP:[fe80::a151:a1e6:e7:e224%wlp0s20f3]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1705510111.141335][16347:16349] CHIP:EM: Flushed pending ack for MessageCounter:130923512 on exchange 17921i - [1705510111.141507][16347:16347] CHIP:CTL: Shutting down the commissioner - [1705510111.141549][16347:16347] CHIP:CTL: Shutting down the controller - [1705510111.141558][16347:16347] CHIP:IN: Expiring all sessions for fabric 0x1!! + On TH(chip-tool), Verify that the attribute returned has a value equal to the ID value from step 2. + + [1705920389.490076][14344:14346] CHIP:DMG: InteractionModelRevision = 11 + [1705920389.490106][14344:14346] CHIP:DMG: } + [1705920389.490347][14344:14346] CHIP:TOO: Endpoint: 3 Cluster: 0x0000_0506 Attribute 0x0000_0009 DataVersion: 402582000 + [1705920389.490552][14344:14346] CHIP:TOO: ActiveTextTrack: { + [1705920389.490588][14344:14346] CHIP:TOO: Id: activeTextTrackId_1 + [1705920389.490634][14344:14346] CHIP:TOO: TrackAttributes: { + [1705920389.490697][14344:14346] CHIP:TOO: LanguageCode: languageCode2 + [1705920389.490731][14344:14346] CHIP:TOO: DisplayName: displayName2 + [1705920389.490761][14344:14346] CHIP:TOO: } + [1705920389.490790][14344:14346] CHIP:TOO: } + [1705920389.491114][14344:14346] CHIP:EM: <<< [E:21221i S:59617 M:230711552 (Ack:159745975)] (S) Msg TX to 1:0000000000000001 [D27C] [UDP:[fe80::e65f:1ff:fe0f:19ff%wlan0]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) disabled: true - label: "Step 5: TH sends a DeactivateTextTrack command to DUT" @@ -121,14 +93,12 @@ tests: verification: | ./chip-tool mediaplayback deactivate-text-track 1 3 - [1705510243.371080][16362:16364] CHIP:DMG: InteractionModelRevision = 11 - [1705510243.371088][16362:16364] CHIP:DMG: }, - [1705510243.371125][16362:16364] CHIP:DMG: Received Command Response Status for Endpoint=3 Cluster=0x0000_0506 Command=0x0000_000E Status=0x0 - [1705510243.371148][16362:16364] CHIP:DMG: ICR moving to [AwaitingDe] - [1705510243.371203][16362:16364] CHIP:EM: <<< [E:35676i S:44821 M:224478765 (Ack:259090512)] (S) Msg TX to 1:0000000000000001 [DC0D] [UDP:[fe80::a151:a1e6:e7:e224%wlp0s20f3]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1705510243.371238][16362:16364] CHIP:EM: Flushed pending ack for MessageCounter:259090512 on exchange 35676i - [1705510243.371429][16362:16362] CHIP:CTL: Shutting down the commissioner - [1705510243.371483][16362:16362] CHIP:CTL: Shutting down the controller + On TH(chip-tool), Verify response is a successful (value 0) status response + [1705920432.359994][14349:14351] CHIP:DMG: }, + [1705920432.360088][14349:14351] CHIP:DMG: Received Command Response Status for Endpoint=3 Cluster=0x0000_0506 Command=0x0000_000E Status=0x0 + [1705920432.360161][14349:14351] CHIP:DMG: ICR moving to [AwaitingDe] + [1705920432.360460][14349:14351] CHIP:EM: <<< [E:34606i S:60686 M:245440743 (Ack:79584870)] (S) Msg TX to 1:0000000000000001 [D27C] [UDP:[fe80::e65f:1ff:fe0f:19ff%wlan0]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) + [1705920432.360651][14349:14351] CHIP:EM: Flushed pending ack for MessageCounter:79584870 on exchange 34606i disabled: true - label: "Step 6: TH reads the ActiveTextTrack attribute from the DUT" @@ -136,14 +106,36 @@ tests: verification: | ./chip-tool mediaplayback read active-text-track 1 3 - - [1705510269.182464][16374:16376] CHIP:DMG: InteractionModelRevision = 11 - [1705510269.182472][16374:16376] CHIP:DMG: } - [1705510269.182556][16374:16376] CHIP:TOO: Endpoint: 3 Cluster: 0x0000_0506 Attribute 0x0000_0009 DataVersion: 900375739 - [1705510269.182642][16374:16376] CHIP:TOO: ActiveTextTrack: { - [1705510269.182651][16374:16376] CHIP:TOO: Id: - [1705510269.182670][16374:16376] CHIP:TOO: TrackAttributes: null - [1705510269.182679][16374:16376] CHIP:TOO: } - [1705510269.182763][16374:16376] CHIP:EM: <<< [E:17583i S:2252 M:176774078 (Ack:187039870)] (S) Msg TX to 1:0000000000000001 [DC0D] [UDP:[fe80::a151:a1e6:e7:e224%wlp0s20f3]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1705510269.182802][16374:16376] CHIP:EM: Flushed pending ack for MessageCounter:187039870 on exchange 17583i + On TH(chip-tool), Verify that the attribute returned has a null value. + [1705920471.994181][14352:14354] CHIP:DMG: } + [1705920471.994472][14352:14354] CHIP:TOO: Endpoint: 3 Cluster: 0x0000_0506 Attribute 0x0000_0009 DataVersion: 402582000 + [1705920471.994741][14352:14354] CHIP:TOO: ActiveTextTrack: { + [1705920471.994789][14352:14354] CHIP:TOO: Id: + [1705920471.994845][14352:14354] CHIP:TOO: TrackAttributes: null + [1705920471.994886][14352:14354] CHIP:TOO: } + [1705920471.995254][14352:14354] CHIP:EM: <<< [E:930i S:17726 M:66812520 (Ack:87654763)] (S) Msg TX to 1:0000000000000001 [D27C] [UDP:[fe80::e65f:1ff:fe0f:19ff%wlan0]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) + [1705920471.995502][14352:14354] CHIP:EM: Flushed pending ack for MessageCounter:87654763 on exchange 930i disabled: true + command: "ActivateTextTrack" + arguments: + values: + - name: "TrackID" + value: ID_Value + + - label: "Step 4: TH reads the ActiveTextTrack attribute from the DUT" + PICS: MEDIAPLAYBACK.S.A0009 + command: "readAttribute" + attribute: "ActiveTextTrack" + response: + value: { ID: ID_Value } + + - label: "Step 5: TH sends a DeactivateTextTrack command to DUT" + PICS: MEDIAPLAYBACK.S.C0e.Rsp + command: "DeactivateTextTrack" + + - label: "Step 6: TH reads the ActiveTextTrack attribute from the DUT" + PICS: MEDIAPLAYBACK.S.A0009 + command: "readAttribute" + attribute: "ActiveTextTrack" + response: + value: { ID: "", TrackAttributes: null } diff --git a/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_9.yaml b/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_9.yaml index 1e5333c65ad226..57d790d965a651 100644 --- a/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_9.yaml +++ b/src/app/tests/suites/certification/Test_TC_MEDIAPLAYBACK_6_9.yaml @@ -11,7 +11,6 @@ # 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default name: 19.8.8. [TC-MEDIAPLAYBACK-6.9] Audio Track Verification @@ -20,95 +19,58 @@ PICS: config: nodeId: 0x12344321 - cluster: "Basic Information" - endpoint: 0 + cluster: "Media Playback" + endpoint: 3 + + AudioTrack_ID_Value: + type: CHAR_STRING + defaultValue: activeAudioTrackId_1 + AudioOutputIndex_Value: + type: int16u + defaultValue: 1 tests: - - label: "Preconditions" - verification: | - 1.DUT is powered on and not in a low power state - 2.DUT has media playing content with multiple audio tracks available - disabled: true + - label: + "Commission DUT to TH (can be skipped if done in a preceding test)." + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId - label: "Step 1: TH reads the ActiveAudioTrack attribute from the DUT" PICS: MEDIAPLAYBACK.S.A0007 - verification: | - ./chip-tool mediaplayback read active-audio-track 1 3 - - - [1705510425.048787][16407:16409] CHIP:DMG: SuppressResponse = true, - [1705510425.048793][16407:16409] CHIP:DMG: InteractionModelRevision = 11 - [1705510425.048799][16407:16409] CHIP:DMG: } - [1705510425.048880][16407:16409] CHIP:TOO: Endpoint: 3 Cluster: 0x0000_0506 Attribute 0x0000_0007 DataVersion: 900375739 - [1705510425.048963][16407:16409] CHIP:TOO: ActiveAudioTrack: { - [1705510425.048971][16407:16409] CHIP:TOO: Id: activeAudioTrackId_0 - [1705510425.048979][16407:16409] CHIP:TOO: TrackAttributes: { - [1705510425.048985][16407:16409] CHIP:TOO: LanguageCode: languageCode1 - [1705510425.048999][16407:16409] CHIP:TOO: DisplayName: displayName1 - [1705510425.049006][16407:16409] CHIP:TOO: } - [1705510425.049012][16407:16409] CHIP:TOO: } - [1705510425.049085][16407:16409] CHIP:EM: <<< [E:36805i S:17177 M:13072081 (Ack:131987814)] (S) Msg TX to 1:0000000000000001 [DC0D] [UDP:[fe80::a151:a1e6:e7:e224%wlp0s20f3]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - disabled: true + command: "readAttribute" + attribute: "ActiveAudioTrack" + response: + saveAs: ActiveAudioTrackValue - label: "Step 2: TH reads the AvailableAudioTracks attribute from the DUT" PICS: MEDIAPLAYBACK.S.A0008 - verification: | - ./chip-tool mediaplayback read available-audio-tracks 1 3 - - - [1705510455.278768][16412:16414] CHIP:DMG: - [1705510455.278774][16412:16414] CHIP:DMG: SuppressResponse = true, - [1705510455.278781][16412:16414] CHIP:DMG: InteractionModelRevision = 11 - [1705510455.278786][16412:16414] CHIP:DMG: } - [1705510455.278928][16412:16414] CHIP:TOO: Endpoint: 3 Cluster: 0x0000_0506 Attribute 0x0000_0008 DataVersion: 900375739 - [1705510455.278981][16412:16414] CHIP:TOO: AvailableAudioTracks: 2 entries - [1705510455.279038][16412:16414] CHIP:TOO: [1]: { - [1705510455.279045][16412:16414] CHIP:TOO: Id: activeAudioTrackId_0 - [1705510455.279053][16412:16414] CHIP:TOO: TrackAttributes: { - [1705510455.279059][16412:16414] CHIP:TOO: LanguageCode: languageCode1 - [1705510455.279074][16412:16414] CHIP:TOO: DisplayName: displayName1 - [1705510455.279081][16412:16414] CHIP:TOO: } - [1705510455.279087][16412:16414] CHIP:TOO: } - [1705510455.279101][16412:16414] CHIP:TOO: [2]: { - [1705510455.279107][16412:16414] CHIP:TOO: Id: activeAudioTrackId_1 - [1705510455.279113][16412:16414] CHIP:TOO: TrackAttributes: { - [1705510455.279119][16412:16414] CHIP:TOO: LanguageCode: languageCode2 - [1705510455.279125][16412:16414] CHIP:TOO: DisplayName: displayName2 - [1705510455.279131][16412:16414] CHIP:TOO: } - [1705510455.279136][16412:16414] CHIP:TOO: } - [1705510455.279220][16412:16414] CHIP:EM: <<< [E:35757i S:13973 M:92594399 (Ack:246741638)] (S) Msg TX to 1:0000000000000001 [DC0D] [UDP:[fe80::a151:a1e6:e7:e224%wlp0s20f3]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1705510455.279240][16412:16414] CHIP:EM: Flushed pending ack for MessageC - disabled: true + command: "readAttribute" + attribute: "AvailableAudioTracks" + response: + saveAs: AvailableAudioTracksValue + constraints: + type: list + minLength: 2 - label: "Step 3: TH sends a ActivateAudioTrack command to DUT specifying the ID value from step 2" PICS: MEDIAPLAYBACK.S.C09.Rsp - verification: | - ./chip-tool mediaplayback activate-text-track activeAudioTrackId_1 1 3 - - [1705510513.251669][16417:16419] CHIP:DMG: - [1705510513.251677][16417:16419] CHIP:DMG: InteractionModelRevision = 11 - [1705510513.251685][16417:16419] CHIP:DMG: }, - [1705510513.251722][16417:16419] CHIP:DMG: Received Command Response Status for Endpoint=3 Cluster=0x0000_0506 Command=0x0000_000D Status=0x0 - [1705510513.251744][16417:16419] CHIP:DMG: ICR moving to [AwaitingDe] - [1705510513.251824][16417:16419] CHIP:EM: <<< [E:31201i S:10659 M:469610 (Ack:79656282)] (S) Msg TX to 1:0000000000000001 [DC0D] [UDP:[fe80::a151:a1e6:e7:e224%wlp0s20f3]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - disabled: true + command: "ActivateAudioTrack" + arguments: + values: + - name: "AudioOutputIndex" + value: AudioOutputIndex_Value + - name: "TrackID" + value: AudioTrack_ID_Value - label: "Step 4: TH reads the ActiveAudioTrack attribute from the DUT" PICS: MEDIAPLAYBACK.S.A0007 - verification: | - ./chip-tool mediaplayback read active-audio-track 1 3 - - [1705510563.022455][16427:16429] CHIP:DMG: } - [1705510563.022535][16427:16429] CHIP:TOO: Endpoint: 3 Cluster: 0x0000_0506 Attribute 0x0000_0007 DataVersion: 900375739 - [1705510563.022607][16427:16429] CHIP:TOO: ActiveAudioTrack: { - [1705510563.022614][16427:16429] CHIP:TOO: Id: activeAudioTrackId_0 - [1705510563.022622][16427:16429] CHIP:TOO: TrackAttributes: { - [1705510563.022628][16427:16429] CHIP:TOO: LanguageCode: languageCode1 - [1705510563.022642][16427:16429] CHIP:TOO: DisplayName: displayName1 - [1705510563.022649][16427:16429] CHIP:TOO: } - [1705510563.022655][16427:16429] CHIP:TOO: } - [1705510563.022725][16427:16429] CHIP:EM: <<< [E:32787i S:18357 M:255165335 (Ack:47655138)] (S) Msg TX to 1:0000000000000001 [DC0D] [UDP:[fe80::a151:a1e6:e7:e224%wlp0s20f3]:5640] --- Type 0000:10 (SecureChannel:StandaloneAck) - [1705510563.022757][16427:16429] CHIP:EM: Flushed pending ack for MessageCounter:47655138 on exchange 32787i - disabled: true + command: "readAttribute" + attribute: "ActiveAudioTrack" + response: + value: { ID: AudioTrack_ID_Value } diff --git a/src/app/tests/suites/certification/Test_TC_OTCCM_1_1.yaml b/src/app/tests/suites/certification/Test_TC_OTCCM_1_1.yaml index 180490a567c742..008c608c9736ba 100644 --- a/src/app/tests/suites/certification/Test_TC_OTCCM_1_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_OTCCM_1_1.yaml @@ -11,7 +11,6 @@ # 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default name: 260.1.1. [TC-OTCCM-1.1] Global attributes with DUT as Server @@ -40,21 +39,9 @@ tests: constraints: type: int16u - - label: - "Step 3: TH reads from the DUT the FeatureMap attribute, bit 0: SHALL - be 1 if and only if OTCCM.S.F00(DEPONOFF)" - command: "readAttribute" - attribute: "FeatureMap" - PICS: OTCCM.S.F00 - response: - constraints: - type: bitmap32 - hasMasksSet: [0x1] - - label: "Step 3: TH reads from the DUT the FeatureMap attribute." command: "readAttribute" attribute: "FeatureMap" - PICS: "!OTCCM.S.F00" response: value: 0 constraints: @@ -88,17 +75,6 @@ tests: type: list contains: [2] - - label: - "Step 4c: Read the Feature dependent attribute(DEPONOFF) in - AttributeList" - PICS: OTCCM.S.F00 - command: "readAttribute" - attribute: "AttributeList" - response: - constraints: - type: list - contains: [3] - - label: "Step 5: TH reads from the DUT the EventList attribute." PICS: PICS_EVENT_LIST_ENABLED command: "readAttribute" diff --git a/src/app/tests/suites/certification/Test_TC_OTCCM_1_2.yaml b/src/app/tests/suites/certification/Test_TC_OTCCM_1_2.yaml index 7b793c9694fe10..ce90c982b8bcf9 100644 --- a/src/app/tests/suites/certification/Test_TC_OTCCM_1_2.yaml +++ b/src/app/tests/suites/certification/Test_TC_OTCCM_1_2.yaml @@ -34,38 +34,105 @@ tests: - label: "Step 2: TH reads from the DUT the SupportedModes attribute." PICS: OTCCM.S.A0000 verification: | - ./chip-tool Ovenmode read supported-modes 1 1 + ./chip-tool ovenmode read supported-modes 1 1 - Verify that the DUT response contains list of ModeOptionsStruct entries. - - Verify that the list has at least 2 and at most 255 entries - - Verify that each ModeOptionsStruct entry has a unique Mode field value and Label field value - - If ModeOptionsStruct entry’s ModeTags field is not empty, then Verify the values of the Value fields that are not larger than 16 bits, for each Value field: Is the mode tag value a defined common tag value ( Auto(0x0000), Quick(0x0001), Quiet(0x0002), LowNoise(0x0003), LowEnergy(0x0004), Vacation(0x0005), Min(0x0006), Max(0x0007), Night(0x0008), Day(0x0009)) or a defined cluster derived tag value ( Normal, Delicate, Heavy, Whites) or in the MfgTags (0x8000 to 0xBFFF) range - - If the Value field is in the MfgTags (0x8000 to 0xBFFF) range, the TagName field is a string with a length between 1 and 64 - - Verify that at least one ModeOptionsStruct entry includes the Normal mode tag - - Save the Mode field values as supported_modes_dut on the TH (Chip-tool) - disabled: true - - - label: "Step 3: TH reads from the DUT the CurrentMode attribute." - PICS: OTCCM.S.A0001 - verification: | - ./chip-tool Ovenmode read current-mode 1 1 + - Verify that the DUT response contains a list of ModeOptionsStruct entries + -Verify that the list has at least 2 and at most 255 entries + - Verify that each ModeOptionsStruct entry has a unique Mode field value + - Verify that each ModeOptionsStruct entry has a unique Label field value + - Verify that each ModeOptionsStruct entry’s ModeTags field has: + at least one entry the values of the Value fields that are not larger than 16 bits + - for each Value field: Is the mode tag value a defined common tag value (Auto(0x0000), Quick(0x0001), Quiet(0x0002), LowNoise(0x0003), LowEnergy(0x0004), Vacation(0x0005), Min(0x0006), Max(0x0007), Night(0x0008), Day(0x0009)) or a defined derived cluster tag value (Bake(0x4000), Convection(0x4001), Grill(0x4002), Roast(0x4003), Clean(0x4004), Convection Bake(0x4005), Convection Roast(0x4006), Warming(0x4007), Proofing(0x4008)) or in the MfgTags (0x8000 to 0xBFFF) range + - for at least one Value field: Is the mode tag value a defined common tag value (Auto(0x0000), Quick(0x0001), Quiet(0x0002), LowNoise(0x0003), LowEnergy(0x0004), Vacation(0x0005), Min(0x0006), Max(0x0007), Night(0x0008), Day(0x0009)) or a derived cluster value (Normal, Defrost) + - if the Value field is in the MfgTags (0x8000 to 0xBFFF) range, the TagName field is a string with a length between 1 and 64 + - Verify that at least one ModeOptionsStruct entry includes the Bake(0x4000) mode tag in the ModeTags field + - Save the Mode field values as supported_modes_dut, On the TH (Chip-tool) and below is the sample log provided for the raspi platform: - Verify on TH(chip-tool) logs, CurrentMode attribute value is an integer value from supported_modes_dut + [1705647707.587205][79487:79492] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0049 Attribute 0x0000_0000 DataVersion: 3240184500 + [1705647707.587250][79487:79492] CHIP:TOO: SupportedModes: 9 entries + [1705647707.587265][79487:79492] CHIP:TOO: [1]: { + [1705647707.587268][79487:79492] CHIP:TOO: Label: Bake + [1705647707.587275][79487:79492] CHIP:TOO: Mode: 0 + [1705647707.587282][79487:79492] CHIP:TOO: ModeTags: 1 entries + [1705647707.587287][79487:79492] CHIP:TOO: [1]: { + [1705647707.587290][79487:79492] CHIP:TOO: Value: 16384 + [1705647707.587294][79487:79492] CHIP:TOO: } + [1705647707.587297][79487:79492] CHIP:TOO: } + [1705647707.587303][79487:79492] CHIP:TOO: [2]: { + [1705647707.587305][79487:79492] CHIP:TOO: Label: Convection + [1705647707.587308][79487:79492] CHIP:TOO: Mode: 1 + [1705647707.587311][79487:79492] CHIP:TOO: ModeTags: 1 entries + [1705647707.587316][79487:79492] CHIP:TOO: [1]: { + [1705647707.587318][79487:79492] CHIP:TOO: Value: 16385 + [1705647707.587321][79487:79492] CHIP:TOO: } + [1705647707.587324][79487:79492] CHIP:TOO: } + [1705647707.587330][79487:79492] CHIP:TOO: [3]: { + [1705647707.587333][79487:79492] CHIP:TOO: Label: Grill + [1705647707.587335][79487:79492] CHIP:TOO: Mode: 2 + [1705647707.587338][79487:79492] CHIP:TOO: ModeTags: 1 entries + [1705647707.587342][79487:79492] CHIP:TOO: [1]: { + [1705647707.587345][79487:79492] CHIP:TOO: Value: 16386 + [1705647707.587348][79487:79492] CHIP:TOO: } + [1705647707.587351][79487:79492] CHIP:TOO: } + [1705647707.587356][79487:79492] CHIP:TOO: [4]: { + [1705647707.587359][79487:79492] CHIP:TOO: Label: Roast + [1705647707.587361][79487:79492] CHIP:TOO: Mode: 3 + [1705647707.587364][79487:79492] CHIP:TOO: ModeTags: 1 entries + [1705647707.587369][79487:79492] CHIP:TOO: [1]: { + [1705647707.587371][79487:79492] CHIP:TOO: Value: 16387 + [1705647707.587374][79487:79492] CHIP:TOO: } + [1705647707.587376][79487:79492] CHIP:TOO: } + [1705647707.587382][79487:79492] CHIP:TOO: [5]: { + [1705647707.587384][79487:79492] CHIP:TOO: Label: Clean + [1705647707.587387][79487:79492] CHIP:TOO: Mode: 4 + [1705647707.587390][79487:79492] CHIP:TOO: ModeTags: 1 entries + [1705647707.587394][79487:79492] CHIP:TOO: [1]: { + [1705647707.587397][79487:79492] CHIP:TOO: Value: 16388 + [1705647707.587400][79487:79492] CHIP:TOO: } + [1705647707.587402][79487:79492] CHIP:TOO: } + [1705647707.587408][79487:79492] CHIP:TOO: [6]: { + [1705647707.587410][79487:79492] CHIP:TOO: Label: Convection Bake + [1705647707.587413][79487:79492] CHIP:TOO: Mode: 5 + [1705647707.587416][79487:79492] CHIP:TOO: ModeTags: 1 entries + [1705647707.587420][79487:79492] CHIP:TOO: [1]: { + [1705647707.587423][79487:79492] CHIP:TOO: Value: 16389 + [1705647707.587425][79487:79492] CHIP:TOO: } + [1705647707.587428][79487:79492] CHIP:TOO: } + [1705647707.587434][79487:79492] CHIP:TOO: [7]: { + [1705647707.587436][79487:79492] CHIP:TOO: Label: Convection Roast + [1705647707.587439][79487:79492] CHIP:TOO: Mode: 6 + [1705647707.587442][79487:79492] CHIP:TOO: ModeTags: 1 entries + [1705647707.587446][79487:79492] CHIP:TOO: [1]: { + [1705647707.587449][79487:79492] CHIP:TOO: Value: 16390 + [1705647707.587451][79487:79492] CHIP:TOO: } + [1705647707.587454][79487:79492] CHIP:TOO: } + [1705647707.587460][79487:79492] CHIP:TOO: [8]: { + [1705647707.587462][79487:79492] CHIP:TOO: Label: Warming + [1705647707.587465][79487:79492] CHIP:TOO: Mode: 7 + [1705647707.587468][79487:79492] CHIP:TOO: ModeTags: 1 entries + [1705647707.587472][79487:79492] CHIP:TOO: [1]: { + [1705647707.587475][79487:79492] CHIP:TOO: Value: 16391 + [1705647707.587477][79487:79492] CHIP:TOO: } + [1705647707.587480][79487:79492] CHIP:TOO: } + [1705647707.587485][79487:79492] CHIP:TOO: [9]: { + [1705647707.587488][79487:79492] CHIP:TOO: Label: Proofing + [1705647707.587490][79487:79492] CHIP:TOO: Mode: 8 + [1705647707.587493][79487:79492] CHIP:TOO: ModeTags: 1 entries + [1705647707.587497][79487:79492] CHIP:TOO: [1]: { + [1705647707.587500][79487:79492] CHIP:TOO: Value: 16392 + [1705647707.587502][79487:79492] CHIP:TOO: } + [1705647707.587505][79487:79492] CHIP:TOO: } disabled: true - - label: "Step 4: TH reads from the DUT the OnMode attribute." - PICS: OTCCM.S.A0003 + - label: "Step 3: TH reads from the DUT the CurrentMode attribute." + PICS: OTCCM.S.A0001 verification: | - ./chip-tool Ovenmode read on-mode 1 1 + ./chip-tool ovenmode read current-mode 1 1 - Verify on TH(chip-tool) logs, OnMode attribute value is an integer value from supported_modes_dut or null - disabled: true - - - label: "Step 5: TH reads from the DUT the StartUpMode attribute." - PICS: OTCCM.S.A0002 - verification: | - ./chip-tool Ovenmode read start-up-mode 1 1 + Verify on TH(chip-tool) logs, CurrentMode attribute value is an integer value from supported_modes_dut, below is the sample log provided for the raspi platform, Here CurrentMode attribute value is 0 - Verify on TH(chip-tool) logs, StartUpMode attribute value is an integer value from supported_modes_dut or null + [1705647748.316225][81944:81949] CHIP:DMG: } + [1705647748.316354][81944:81949] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0049 Attribute 0x0000_0001 DataVersion: 3240184500 + [1705647748.316395][81944:81949] CHIP:TOO: CurrentMode: 0 disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_OTCCM_2_1.yaml b/src/app/tests/suites/certification/Test_TC_OTCCM_2_1.yaml index 1e6d17ff71679f..6f0ef16b5a2726 100644 --- a/src/app/tests/suites/certification/Test_TC_OTCCM_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_OTCCM_2_1.yaml @@ -83,7 +83,9 @@ tests: - label: "Step 5: Manually put the device in a state from which it will FAIL to transition to PIXIT.OTCCM.MODE_CHANGE_FAIL" - PICS: OTCCM.S.M.CAN_TEST_MODE_FAILURE && PICS_SKIP_SAMPLE_APP + PICS: + OTCCM.S.M.CAN_TEST_MODE_FAILURE && PICS_SKIP_SAMPLE_APP && + OTCCM.S.M.CAN_MANUALLY_CONTROLLED verification: | Manual operation required cluster: "LogCommands" @@ -96,7 +98,7 @@ tests: value: "y" - label: "Step 6: TH reads from the DUT the CurrentMode attribute." - PICS: OTCCM.S.A0001 + PICS: OTCCM.S.A0001 && OTCCM.S.M.CAN_MANUALLY_CONTROLLED command: "readAttribute" attribute: "CurrentMode" response: @@ -139,14 +141,14 @@ tests: command: "readAttribute" attribute: "CurrentMode" response: - value: Step6_current_mode_dut + value: old_current_mode_dut constraints: type: int16u - label: "Step 9: Manually put the device in a state from which it will SUCCESSFULLY transition to PIXIT.OTCCM.MODE_CHANGE_OK" - PICS: PICS_SKIP_SAMPLE_APP + PICS: PICS_SKIP_SAMPLE_APP && OTCCM.S.M.CAN_MANUALLY_CONTROLLED verification: | Manual operation required cluster: "LogCommands" @@ -159,7 +161,7 @@ tests: value: "y" - label: "Step 10: TH reads from the DUT the CurrentMode attribute." - PICS: OTCCM.S.A0001 + PICS: OTCCM.S.A0001 && OTCCM.S.M.CAN_MANUALLY_CONTROLLED command: "readAttribute" attribute: "CurrentMode" response: diff --git a/src/app/tests/suites/certification/Test_TC_OTCCM_3_1.yaml b/src/app/tests/suites/certification/Test_TC_OTCCM_3_1.yaml index 9f805fb0dd8101..3d886d15ab6253 100644 --- a/src/app/tests/suites/certification/Test_TC_OTCCM_3_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_OTCCM_3_1.yaml @@ -16,7 +16,7 @@ name: 3.4 [TC-OTCCM-3.1] On Mode functionality with DUT as Server PICS: - OTCCM.S.A0003 - - OTCCM.S.F00 + - MOD.S.F00 - OO.S.C00.Rsp - OO.S.C01.Rsp @@ -47,14 +47,14 @@ tests: "Precondition: TH writes from the DUT the OnMode attribute.NOTE: To execute this test case set onmode to any integer value because as default it value has null." - PICS: OTCCM.S.A0003 && OTCCM.S.F00 + PICS: OTCCM.S.A0003 && MOD.S.F00 command: "writeAttribute" attribute: "OnMode" arguments: value: ConfigureOnMode - label: "Step 2: TH reads from the DUT the OnMode attribute." - PICS: OTCCM.S.A0003 && OTCCM.S.F00 + PICS: OTCCM.S.A0003 && MOD.S.F00 command: "readAttribute" attribute: "OnMode" response: @@ -63,7 +63,7 @@ tests: type: int8u - label: "Step 3: TH reads from the DUT the CurrentMode attribute." - PICS: OTCCM.S.A0001 && OTCCM.S.F00 + PICS: OTCCM.S.A0001 && MOD.S.F00 command: "readAttribute" attribute: "CurrentMode" response: @@ -74,6 +74,7 @@ tests: - label: "If on_mode_dut is equal to old_current_mode_dut proceed to step 4. Else proceed to step 6." + PICS: OTCCM.S.A0001 && MOD.S.F00 && OTCCM.S.A0003 cluster: "EqualityCommands" command: "UnsignedNumberEquals" arguments: @@ -89,7 +90,7 @@ tests: - label: "Step 4: TH reads from the DUT the SupportedModes attribute." runIf: IsExpectedValue - PICS: OTCCM.S.A0000 && OTCCM.S.F00 + PICS: OTCCM.S.A0000 && MOD.S.F00 command: "readAttribute" attribute: "SupportedModes" response: @@ -101,7 +102,7 @@ tests: "Step 5: TH sends a ChangeToMode command to the DUT with NewMode set to new_mode_th" runIf: IsExpectedValue - PICS: OTCCM.S.C00.Rsp && OTCCM.S.F00 + PICS: OTCCM.S.C00.Rsp && MOD.S.F00 command: "ChangeToMode" arguments: values: @@ -113,17 +114,17 @@ tests: value: 0x00 - label: "Step 6:TH sends a Off command to the DUT" - PICS: OO.S.C00.Rsp && OTCCM.S.F00 + PICS: OO.S.C00.Rsp && MOD.S.F00 cluster: "On/Off" command: "Off" - label: "Step 7:TH sends a On command to the DUT" - PICS: OO.S.C01.Rsp && OTCCM.S.F00 + PICS: OO.S.C01.Rsp && MOD.S.F00 cluster: "On/Off" command: "On" - label: "Step 8: TH reads from the DUT the CurrentMode attribute." - PICS: OTCCM.S.A0001 && OTCCM.S.F00 + PICS: OTCCM.S.A0001 && MOD.S.F00 command: "readAttribute" attribute: "CurrentMode" response: diff --git a/src/app/tests/suites/certification/Test_TC_OTCCM_3_3.yaml b/src/app/tests/suites/certification/Test_TC_OTCCM_3_3.yaml index bb1e8edf932f16..27184569f51b5a 100644 --- a/src/app/tests/suites/certification/Test_TC_OTCCM_3_3.yaml +++ b/src/app/tests/suites/certification/Test_TC_OTCCM_3_3.yaml @@ -18,7 +18,7 @@ name: PICS: - OTCCM.S.A0002 - OTCCM.S.A0003 - - OTCCM.S.F00 + - MOD.S.F00 - OO.S.A4003 config: @@ -135,7 +135,7 @@ tests: value: new_mode_th - label: "Step 8: TH reads from the DUT the OnMode attribute." - PICS: OTCCM.S.A0003 && OTCCM.S.F00 + PICS: OTCCM.S.A0003 && MOD.S.F00 command: "readAttribute" attribute: "OnMode" response: diff --git a/src/app/tests/suites/certification/Test_TC_PS_3_1.yaml b/src/app/tests/suites/certification/Test_TC_PS_3_1.yaml deleted file mode 100644 index d64c29714436f8..00000000000000 --- a/src/app/tests/suites/certification/Test_TC_PS_3_1.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default - -name: 63.2.3. [TC-PS-3.1] Endpoint composition and EndpointList - -PICS: - - PS.S - -config: - nodeId: 0x12344321 - cluster: "Basic Information" - endpoint: 0 - -tests: - - label: - "Step 1: TH performs a wildcard read of all attributes and endpoints" - verification: | - TH(chip-tool) sends the wildcard read command to read all attributes and endpoints from DUT(Reference app/all-clusters-app) - ./chip-tool any read-by-id 0xFFFFFFFF 0xFFFFFFFF 1 0xFFFF - disabled: true - - - label: - "Step 2: For each power source cluster with a non-empty EndpointsList - attribute, verify that the endpoint exists on the device; also verify - that the EndpointsList attribute includes the endpoint on which the - cluster is located" - verification: | - TH(chip-tool) sends the wildcard read command to read all attributes and endpoints from DUT(Reference app/all-clusters-app) - - ./chip-tool any read-by-id 0xFFFFFFFF 0xFFFFFFFF 1 0xFFFF - - [1690195509.133521][44004:44006] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_002F Attribute 0x0000_000F DataVersion: 2929707991 - [1690195509.133523][44004:44006] CHIP:TOO: BatReplacementNeeded: FALSE - [1690195509.133531][44004:44006] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_002F Attribute 0x0000_0010 DataVersion: 2929707991 - [1690195509.133534][44004:44006] CHIP:TOO: BatReplaceability: 0 - [1690195509.133549][44004:44006] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_002F Attribute 0x0000_001F DataVersion: 2929707991 - [1690195509.133556][44004:44006] CHIP:TOO: EndpointList: 0 entries - [1690195509.133558][44004:44006] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_002F Attribute 0x0000_FFFC DataVersion: 2929707991 - [1690195509.133560][44004:44006] CHIP:TOO: FeatureMap: 2 - - [1690195509.203569][44004:44006] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_002F Attribute 0x0000_0010 DataVersion: 1378119001 - [1690195509.203572][44004:44006] CHIP:TOO: BatReplaceability: 0 - [1690195509.203587][44004:44006] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_002F Attribute 0x0000_001F DataVersion: 1378119001 - [1690195509.203592][44004:44006] CHIP:TOO: EndpointList: 0 entries - [1690195509.203595][44004:44006] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_002F Attribute 0x0000_FFFC DataVersion: 1378119001 - [1690195509.203597][44004:44006] CHIP:TOO: FeatureMap: 2 - - - [1690195509.133531][44004:44006] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_002F Attribute 0x0000_0010 DataVersion: 2929707991 - [1690195509.133534][44004:44006] CHIP:TOO: BatReplaceability: 0 - [1690195509.133549][44004:44006] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_002F Attribute 0x0000_001F DataVersion: 2929707991 - [1690195509.133556][44004:44006] CHIP:TOO: EndpointList: 0 entries - [1690195509.133558][44004:44006] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_002F Attribute 0x0000_FFFC DataVersion: 2929707991 - [1690195509.133560][44004:44006] CHIP:TOO: FeatureMap: 2 - disabled: true - - - label: - "Step 3: For each power source cluster on an endpoint with the Bridged - Node device type, ensure the EndpointList in the Power Source cluster - includes all the endpoints listed in the PartsList of the Descriptor - cluster as well as its own endpoint id." - verification: | - - disabled: true - - - label: - "Step 4: For each power source cluster on an endpoint that is a child - endpoint of an endpoint with a Bridged Node device type, ensure the - EndpointList in the Power Source cluster contains a list with one - entry that lists its own endpoint id" - verification: | - - disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_PWRTL_1_1.yaml b/src/app/tests/suites/certification/Test_TC_PWRTL_1_1.yaml new file mode 100644 index 00000000000000..cfe6fd860be240 --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_PWRTL_1_1.yaml @@ -0,0 +1,119 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default + +name: 44.1.1. [TC-PWRTL-1.1] Global Attributes with DUT as Server + +PICS: + - PWRTL.S + +config: + nodeId: 0x12344321 + cluster: "Power Topology" + endpoint: 1 + +tests: + - label: "Step 1: Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Step 2: TH reads the ClusterRevision from DUT" + command: "readAttribute" + attribute: "ClusterRevision" + response: + value: 1 + constraints: + type: int16u + + - label: + "Step 3a: Given PWRTL.S.F00(Node) ensure featuremap has the correct + bit set" + PICS: PWRTL.S.F00 + command: "readAttribute" + attribute: "FeatureMap" + response: + constraints: + type: bitmap32 + hasMasksSet: [0x1] + hasMasksClear: [0x2, 0x4, 0x8] + + - label: + "Step 3b: Given PWRTL.S.F01(Leaf) ensure featuremap has the correct + bit set" + PICS: PWRTL.S.F01 + command: "readAttribute" + attribute: "FeatureMap" + response: + constraints: + type: bitmap32 + hasMasksSet: [0x2] + hasMasksClear: [0x1, 0x4, 0x8] + + - label: + "Step 3c: Given PWRTL.S.F02(Set) ensure featuremap has the correct bit + set" + PICS: PWRTL.S.F02 + command: "readAttribute" + attribute: "FeatureMap" + response: + constraints: + type: bitmap32 + hasMasksSet: [0x4] + hasMasksClear: [0x1, 0x2] + + - label: + "Step 3d: Given PWRTL.S.F03(Dynamic Power Flow) ensure featuremap has + the correct bit set" + PICS: PWRTL.S.F03 + command: "readAttribute" + attribute: "FeatureMap" + response: + constraints: + type: bitmap32 + hasMasksSet: [0x4, 0x8] + + - label: "Step 4a: TH reads AttributeList from DUT" + PICS: "!PICS_SF_SET && !PICS_SF_DYPF" + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [] + + - label: + "Step 4b: TH reads feature dependent attribute(AvailableEndpoints) + AttributeList from DUT" + PICS: "PICS_SF_SET && !PICS_SF_DYPF" + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [0] + + - label: + "Step 4c: TH reads feature dependent attribute(ActiveEndpoints) + AttributeList from DUT" + PICS: "PICS_SF_SET && PICS_SF_DYPF" + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [0, 1] diff --git a/src/app/tests/suites/certification/Test_TC_REFALM_2_2.yaml b/src/app/tests/suites/certification/Test_TC_REFALM_2_2.yaml index 3404d4ff6d9ed2..54a872047dc99d 100644 --- a/src/app/tests/suites/certification/Test_TC_REFALM_2_2.yaml +++ b/src/app/tests/suites/certification/Test_TC_REFALM_2_2.yaml @@ -11,7 +11,6 @@ # 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default name: 223.2.2. [TC-REFALM-2.2] Primary functionality with DUT as Server @@ -20,117 +19,189 @@ PICS: config: nodeId: 0x12344321 - cluster: "Basic Information" - endpoint: 0 + cluster: "Refrigerator Alarm" + endpoint: 1 + PIXIT.REFALM.AlarmThreshold: + type: int16u + defaultValue: 5 tests: - - label: "Note" - verification: | - This is a simulated example log for instructional purposes only. In real scenarios, the actual log may vary depending on the feature implementation in Reference App. - disabled: true - - label: "Step 1: Commission DUT to TH (can be skipped if done in a preceding test)" - verification: | - - disabled: true + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId - label: "Step 2: Ensure that the door on the DUT is closed" verification: | Ensure that the door on the DUT is closed - disabled: true - - - label: "Step 3: TH reads from the DUT the State attribute" + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_USER_PROMPT + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: "Step 3:TH reads from the DUT the State attribute" + command: "readAttribute" + attribute: "State" PICS: REFALM.S.A0002 - verification: | - ./chip-tool refrigeratoralarm read state 1 1 - On TH(chip-tool), Verify that the DUT response contains a 32-bit value with bit 0 set to 0. - - [1688447820.603249][4247:4249] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0057 Attribute 0x0000_0002 DataVersion: 1795162772 - [1688447820.603415][4247:4249] CHIP:TOO: State: 1 - [1688447820.603708][4247:4249] CHIP:EM: <<< [E:2198i S:4260 M:156565261 (Ack:46517349)] (S) Msg TX to 1:0000000000000001 [10DB] --- Type 0000:10 (SecureChannel:StandaloneAck) - disabled: true + response: + constraints: + type: bitmap32 + hasMasksClear: [0x1] - label: "Step 4: Manually open the door on the DUT" verification: | Manually open the door on the DUT - disabled: true + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_USER_PROMPT + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" - label: "Step 5: Wait for the time defined in PIXIT.REFALM.AlarmThreshold" - verification: | - Wait for the time defined in PIXIT.REFALM.AlarmThreshold - disabled: true + cluster: "DelayCommands" + command: "WaitForMs" + PICS: PICS_USER_PROMPT + arguments: + values: + - name: "ms" + value: PIXIT.REFALM.AlarmThreshold * 1000 - label: "Step 6: TH reads from the DUT the State attribute" - PICS: REFALM.S.A0002 - verification: | - ./chip-tool refrigeratoralarm read state 1 1 - On TH(chip-tool), Verify that the DUT response contains a 32-bit value with bit 0 set to 1. - - [1688447820.603249][4247:4249] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0057 Attribute 0x0000_0002 DataVersion: 1795162772 - [1688447820.603415][4247:4249] CHIP:TOO: State: 1 - [1688447820.603708][4247:4249] CHIP:EM: <<< [E:2198i S:4260 M:156565261 (Ack:46517349)] (S) Msg TX to 1:0000000000000001 [10DB] --- Type 0000:10 (SecureChannel:StandaloneAck) - disabled: true + command: "readAttribute" + attribute: "State" + PICS: REFALM.S.A0002 && PICS_USER_PROMPT + response: + constraints: + type: bitmap32 + hasMasksSet: [0x1] - label: "Step 7: Ensure that the door on the DUT is closed" verification: | Ensure that the door on the DUT is closed - disabled: true + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_USER_PROMPT + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" - label: "Step 8: TH reads from the DUT the State attribute" - PICS: REFALM.S.A0002 - verification: | - ./chip-tool refrigeratoralarm read state 1 1 - On TH(chip-tool), Verify that the DUT response contains a 32-bit value with bit 0 set to 0. - - [1688447820.603249][4247:4249] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0057 Attribute 0x0000_0002 DataVersion: 1795162772 - [1688447820.603415][4247:4249] CHIP:TOO: State: 0 - [1688447820.603708][4247:4249] CHIP:EM: <<< [E:2198i S:4260 M:156565261 (Ack:46517349)] (S) Msg TX to 1:0000000000000001 [10DB] --- Type 0000:10 (SecureChannel:StandaloneAck) - disabled: true - + command: "readAttribute" + attribute: "State" + PICS: REFALM.S.A0002 PICS_USER_PROMPT + response: + constraints: + type: bitmap32 + hasMasksClear: [0x1] + + # Issue: https://github.com/project-chip/connectedhomeip/issues/28325 + # Issue: https://github.com/project-chip/connectedhomeip/issues/27235 - label: "Step 9: TH sends Reset command to the DUT" - PICS: REFALM.S.C00.Rsp + PICS: REFALM.S.C00.Rsp && PICS_USER_PROMPT verification: | Reset command is not implemeted in Chip-tool - disabled: true + cluster: "LogCommands" + command: "UserPrompt" + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" - label: "Step 10: TH sends ModifyEnabledAlarms command to the DUT" - PICS: REFALM.S.C01.Rsp + PICS: REFALM.S.C01.Rsp && PICS_USER_PROMPT verification: | ModifyEnabledAlarms is not implemeted in Chip-tool - disabled: true + cluster: "LogCommands" + command: "UserPrompt" + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" - label: "Step 11: Set up subscription to the Notify event." PICS: REFALM.S.E00 && REFALM.S.A0002 + command: "subscribeEvent" + event: "Notify" + minInterval: 2 + maxInterval: 10 + + - label: "Step 12a: Repeating step 4 Manually open the door on the DUT" verification: | - Please use Interactive mode to subscribe the OperationalError event - Here the command to enter interactive mode after provision :- - ./chip-tool interactive start - - Please subscribe to the Notify event by sending below mentioned command - refrigeratoralarm subscribe-event notify 2 10 1 1 - - [1690959967.087585][3549:3551] CHIP:EM: Rxd Ack; Removing MessageCounter:144404037 from Retrans Table on exchange 19895i - [1690959967.087651][3549:3551] CHIP:DMG: ReportDataMessage = - [1690959967.087684][3549:3551] CHIP:DMG: { - [1690959967.087712][3549:3551] CHIP:DMG: SubscriptionId = 0x959257ec, - [1690959967.087743][3549:3551] CHIP:DMG: InteractionModelRevision = 1 - [1690959967.087770][3549:3551] CHIP:DMG: } - [1690959967.087813][3549:3551] CHIP:DMG: MoveToState ReadClient[0xffff80010ac0]: Moving to [AwaitingSu] - [1690959967.087923][3549:3551] CHIP:EM: <<< [E:19895i S:58037 M:144404038 (Ack:133694741)] (S) Msg TX to 1:0000000000000001 [7C8C] --- Type 0001:01 (IM:StatusResponse) - [1690959967.087966][3549:3551] CHIP:IN: (S) Sending msg 144404038 on secure session with LSID: 58037 - disabled: true - - - label: "Step 12: Repeat steps 4 then 5" - PICS: REFALM.S.E00 - verification: | - Repeat steps 4 - Manually open the door on the DUT - then 5 - Wait for the time defined in PIXIT.REFALM.AlarmThreshold - disabled: true + Manually open the door on the DUT + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_USER_PROMPT + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: + "Step 12b: Repeat step 5 Wait for the time defined in + PIXIT.REFALM.AlarmThreshold" + cluster: "DelayCommands" + command: "WaitForMs" + PICS: PICS_USER_PROMPT + arguments: + values: + - name: "ms" + value: PIXIT.REFALM.AlarmThreshold * 1000 - - label: "Step 13: Repeat step 7" - PICS: REFALM.S.E00 + - label: + "Step 12c: After step 5 (repeated), receive a Notify event with the + State attribute bit 0 set to 1." + command: "readAttribute" + attribute: "State" + PICS: REFALM.S.A0002 && PICS_USER_PROMPT + response: + constraints: + type: bitmap32 + hasMasksSet: [0x1] + + - label: + "Step 13a : Repeat step 7 Ensure that the door on the DUT is closed" verification: | - Repeat step 7 - that is Ensure that the door on the DUT is closed - disabled: true + Manually open the door on the DUT + cluster: "LogCommands" + command: "UserPrompt" + PICS: PICS_USER_PROMPT + arguments: + values: + - name: "message" + value: "Enter 'y' after success" + - name: "expectedValue" + value: "y" + + - label: + "Step 13b: Receive a Notify event with the State attribute bit 0 set + to 0" + command: "readAttribute" + attribute: "State" + PICS: REFALM.S.A0002 && PICS_USER_PROMPT + response: + constraints: + type: bitmap32 + hasMasksClear: [0x1] diff --git a/src/app/tests/suites/certification/Test_TC_SC_3_3.yaml b/src/app/tests/suites/certification/Test_TC_SC_3_3.yaml index f6b17380499be0..048b5241da7a20 100644 --- a/src/app/tests/suites/certification/Test_TC_SC_3_3.yaml +++ b/src/app/tests/suites/certification/Test_TC_SC_3_3.yaml @@ -99,8 +99,8 @@ tests: responderSessionID is of uint16 sigma2ResumeMIC is of Octet String maximum of length 16 bytes responderSEDParams is from any one of the following: - SLEEPY_IDLE_INTERVAL - Verify that it is of uint32 - SLEEPY_ACTIVE_INTERVAL - Verify that it is of uint32 + SESSION_IDLE_INTERVAL - Verify that it is of uint32 + SESSION_ACTIVE_INTERVAL - Verify that it is of uint32 [1683973658.044236][21637:21637] CHIP:EM: Rxd Ack; Removing MessageCounter:113416101 from Retrans Table on exchange 32995r diff --git a/src/app/tests/suites/certification/Test_TC_SC_4_10.yaml b/src/app/tests/suites/certification/Test_TC_SC_4_10.yaml index 298b831b262f41..987bc6279093a8 100644 --- a/src/app/tests/suites/certification/Test_TC_SC_4_10.yaml +++ b/src/app/tests/suites/certification/Test_TC_SC_4_10.yaml @@ -42,7 +42,7 @@ tests: verification: | avahi-browse -rt _matter._tcp On the TH(Chip-tool) Log: Verify the DUT is advertising for: - -SII key is higher than the SLEEPY_IDLE_INTERVAL default value (> 300 milliseconds) + - SII key is higher than the SESSION_IDLE_INTERVAL default value (> 500 milliseconds) - SII key and SAI key is less than 3600000 (1hour in milliseconds) + eth0 IPv6 3A235FF3FA2DAC10-0000000000000055 _matter._tcp local diff --git a/src/app/tests/suites/certification/Test_TC_S_1_1.yaml b/src/app/tests/suites/certification/Test_TC_S_1_1.yaml index 36314424458714..c8a8c359e1cdc8 100644 --- a/src/app/tests/suites/certification/Test_TC_S_1_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_S_1_1.yaml @@ -62,7 +62,7 @@ tests: hasMasksSet: [0x1] - label: - "Step 4: TH reads AttributeList mandatory attributes(global attribute + "Step 4a: TH reads AttributeList mandatory attributes(global attribute 65531)" PICS: S.S command: "readAttribute" @@ -70,7 +70,18 @@ tests: response: constraints: type: list - contains: [0, 1, 2, 65528, 65529, 65531, 65532, 65533] + contains: [1, 2, 65528, 65529, 65531, 65532, 65533] + + - label: + "Step 4b: TH reads the LastConfiguredBy optional attribute from the + AttributeList (global attribute 65531)" + PICS: S.S.A0000 + command: "readAttribute" + attribute: "AttributeList" + response: + constraints: + type: list + contains: [0] - label: "Step 5: TH reads from the DUT the EventList attribute" PICS: PICS_EVENT_LIST_ENABLED diff --git a/src/app/tests/suites/certification/Test_TC_S_2_1.yaml b/src/app/tests/suites/certification/Test_TC_S_2_1.yaml index ed8e61f47f6d09..152539147ca37a 100644 --- a/src/app/tests/suites/certification/Test_TC_S_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_S_2_1.yaml @@ -17,8 +17,6 @@ name: 123.2.1. [TC-S-2.1] Attributes with DUT as Server PICS: - S.S - - S.S.AM - - S.S.AO config: nodeId: 0x12344321 diff --git a/src/app/tests/suites/certification/Test_TC_S_2_2.yaml b/src/app/tests/suites/certification/Test_TC_S_2_2.yaml index d569b12d512a8a..02407f8807d993 100644 --- a/src/app/tests/suites/certification/Test_TC_S_2_2.yaml +++ b/src/app/tests/suites/certification/Test_TC_S_2_2.yaml @@ -344,7 +344,6 @@ tests: type: int16u - label: "Step 3d: TH reads attribute FabricSceneInfo from DUT" - PICS: PICS_SDK_CI_ONLY command: "readAttribute" attribute: "FabricSceneInfo" response: @@ -644,48 +643,18 @@ tests: to 60 000 000 (60 000s) and a set of extension fields appropriate to AC1." verification: | - ./chip-tool scenes add-scene 0x0001 1 60000000 "Test Name" '[{"clusterId": value, "attributeValueList":[{"attributeId": value, "attributeValue": value}]}' nodeId endpointId - - Note: The number of ExtensionFieldSets, the value of clusterId of each ExtensionFieldSet, the number of attributes in attributeValueList and their values varies for each application - - Verify the "status is success" on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: - [1670970505.887060][5742:5744] CHIP:DMG: InvokeResponseMessage = - [1670970505.887118][5742:5744] CHIP:DMG: { - [1670970505.887172][5742:5744] CHIP:DMG: suppressResponse = false, - [1670970505.887231][5742:5744] CHIP:DMG: InvokeResponseIBs = - [1670970505.887307][5742:5744] CHIP:DMG: [ - [1670970505.887366][5742:5744] CHIP:DMG: InvokeResponseIB = - [1670970505.887444][5742:5744] CHIP:DMG: { - [1670970505.887507][5742:5744] CHIP:DMG: CommandDataIB = - [1670970505.887576][5742:5744] CHIP:DMG: { - [1670970505.887713][5742:5744] CHIP:DMG: CommandPathIB = - [1670970505.887804][5742:5744] CHIP:DMG: { - [1670970505.887940][5742:5744] CHIP:DMG: EndpointId = 0x1, - [1670970505.888093][5742:5744] CHIP:DMG: ClusterId = 0x5, - [1670970505.888242][5742:5744] CHIP:DMG: CommandId = 0x0, - [1670970505.888385][5742:5744] CHIP:DMG: }, - [1670970505.888692][5742:5744] CHIP:DMG: - [1670970505.888769][5742:5744] CHIP:DMG: CommandFields = - [1670970505.888852][5742:5744] CHIP:DMG: { - [1670970505.889030][5742:5744] CHIP:DMG: 0x0 = 0, - [1670970505.889183][5742:5744] CHIP:DMG: 0x1 = 1, - [1670970505.889406][5742:5744] CHIP:DMG: 0x2 = 1, - [1670970505.889515][5742:5744] CHIP:DMG: }, - [1670970505.889603][5742:5744] CHIP:DMG: }, - [1670970505.889684][5742:5744] CHIP:DMG: - [1670970505.889745][5742:5744] CHIP:DMG: }, - [1670970505.889821][5742:5744] CHIP:DMG: - [1670970505.889878][5742:5744] CHIP:DMG: ], - [1670970505.889953][5742:5744] CHIP:DMG: - [1670970505.890009][5742:5744] CHIP:DMG: InteractionModelRevision = 1 - [1670970505.890066][5742:5744] CHIP:DMG: }, - [1670970505.890212][5742:5744] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0005 Command=0x0000_0000 - [1670970505.890328][5742:5744] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - [1670970505.890458][5742:5744] CHIP:TOO: AddSceneResponse: { - [1670970505.890551][5742:5744] CHIP:TOO: status: 0 - [1670970505.890608][5742:5744] CHIP:TOO: groupId: 1 - [1670970505.890717][5742:5744] CHIP:TOO: sceneId: 1 - [1670970505.890774][5742:5744] CHIP:TOO: } + ./chip-tool scenesmanagement add-scene 0x0001 0x01 60000000 "scene name" '[{"clusterID": "0x0300", "attributeValueList":[{"attributeID": "0x4001", "attributeValue": "0x01"}]}]' 1 1 + + Verify DUT sends a AddSceneResponse command to TH with the Status field set to 0x00 (SUCCESS), the GroupID field set to G1 and the SceneID field set to 0x01 on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: + + [1706763610.675038][4232:4234] CHIP:DMG: }, + [1706763610.675108][4232:4234] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1706763610.675134][4232:4234] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1706763610.675187][4232:4234] CHIP:TOO: AddSceneResponse: { + [1706763610.675215][4232:4234] CHIP:TOO: status: 0 + [1706763610.675229][4232:4234] CHIP:TOO: groupID: 1 + [1706763610.675244][4232:4234] CHIP:TOO: sceneID: 1 + [1706763610.675258][4232:4234] CHIP:TOO: } cluster: "LogCommands" command: "UserPrompt" PICS: PICS_SKIP_SAMPLE_APP @@ -753,7 +722,7 @@ tests: set to G1, the SceneID field set to 0x01, the TransitionTime field set to 70 000 000 (70 000s) and no extension field sets. This should fail and return a status of 0x85 (INVALID_COMMAND)." - PICS: S.S.C00.Rsp && PICS_SDK_CI_ONLY + PICS: S.S.C00.Rsp command: "AddScene" arguments: values: @@ -781,7 +750,7 @@ tests: set to G1, the SceneID field set to 0x01, the TransitionTime field set to 60 000 001 (60 000.001s) and no extension field sets. This should fail and return a status of 0x85 (INVALID_COMMAND)." - PICS: S.S.C00.Rsp && PICS_SDK_CI_ONLY + PICS: S.S.C00.Rsp command: "AddScene" arguments: values: diff --git a/src/app/tests/suites/certification/Test_TC_S_2_3.yaml b/src/app/tests/suites/certification/Test_TC_S_2_3.yaml index 21549a843b29ac..859204e549f7b2 100644 --- a/src/app/tests/suites/certification/Test_TC_S_2_3.yaml +++ b/src/app/tests/suites/certification/Test_TC_S_2_3.yaml @@ -309,48 +309,19 @@ tests: to G1, the SceneID field set to 0x01, the TransitionTime field set to 1000 (1s) and a set of extension fields appropriate to AC1." verification: | - ./chip-tool scenes add-scene GroupID SceneID TransitionTime "SceneName" '[{"clusterId": value, "attributeValueList":[{"attributeId": value, "attributeValue": value}]}' nodeId endpointId + ./chip-tool scenesmanagement add-scene GroupID SceneID TransitionTime "SceneName" '[{"clusterId": value, "attributeValueList":[{"attributeId": value, "attributeValue": value}]}' nodeId endpointId Note: The number of ExtensionFieldSets, the value of clusterId of each ExtensionFieldSet, the number of attributes in attributeValueList and their values varies for each application Verify the "status is success" on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: - [1670970505.887060][5742:5744] CHIP:DMG: InvokeResponseMessage = - [1670970505.887118][5742:5744] CHIP:DMG: { - [1670970505.887172][5742:5744] CHIP:DMG: suppressResponse = false, - [1670970505.887231][5742:5744] CHIP:DMG: InvokeResponseIBs = - [1670970505.887307][5742:5744] CHIP:DMG: [ - [1670970505.887366][5742:5744] CHIP:DMG: InvokeResponseIB = - [1670970505.887444][5742:5744] CHIP:DMG: { - [1670970505.887507][5742:5744] CHIP:DMG: CommandDataIB = - [1670970505.887576][5742:5744] CHIP:DMG: { - [1670970505.887713][5742:5744] CHIP:DMG: CommandPathIB = - [1670970505.887804][5742:5744] CHIP:DMG: { - [1670970505.887940][5742:5744] CHIP:DMG: EndpointId = 0x1, - [1670970505.888093][5742:5744] CHIP:DMG: ClusterId = 0x5, - [1670970505.888242][5742:5744] CHIP:DMG: CommandId = 0x0, - [1670970505.888385][5742:5744] CHIP:DMG: }, - [1670970505.888692][5742:5744] CHIP:DMG: - [1670970505.888769][5742:5744] CHIP:DMG: CommandFields = - [1670970505.888852][5742:5744] CHIP:DMG: { - [1670970505.889030][5742:5744] CHIP:DMG: 0x0 = 0, - [1670970505.889183][5742:5744] CHIP:DMG: 0x1 = 1, - [1670970505.889406][5742:5744] CHIP:DMG: 0x2 = 1, - [1670970505.889515][5742:5744] CHIP:DMG: }, - [1670970505.889603][5742:5744] CHIP:DMG: }, - [1670970505.889684][5742:5744] CHIP:DMG: - [1670970505.889745][5742:5744] CHIP:DMG: }, - [1670970505.889821][5742:5744] CHIP:DMG: - [1670970505.889878][5742:5744] CHIP:DMG: ], - [1670970505.889953][5742:5744] CHIP:DMG: - [1670970505.890009][5742:5744] CHIP:DMG: InteractionModelRevision = 1 - [1670970505.890066][5742:5744] CHIP:DMG: }, - [1670970505.890212][5742:5744] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0005 Command=0x0000_0000 - [1670970505.890328][5742:5744] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - [1670970505.890458][5742:5744] CHIP:TOO: AddSceneResponse: { - [1670970505.890551][5742:5744] CHIP:TOO: status: 0 - [1670970505.890608][5742:5744] CHIP:TOO: groupId: 257 - [1670970505.890717][5742:5744] CHIP:TOO: sceneId: 1 - [1670970505.890774][5742:5744] CHIP:TOO: } + [1705680175.863785][5823:5825] CHIP:DMG: }, + [1705680175.863851][5823:5825] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1705680175.863880][5823:5825] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1705680175.863931][5823:5825] CHIP:TOO: AddSceneResponse: { + [1705680175.863956][5823:5825] CHIP:TOO: status: 0 + [1705680175.863967][5823:5825] CHIP:TOO: groupID: 257 + [1705680175.863977][5823:5825] CHIP:TOO: sceneID: 1 + [1705680175.863986][5823:5825] CHIP:TOO: } cluster: "LogCommands" command: "UserPrompt" PICS: S.S.C00.Rsp && PICS_SKIP_SAMPLE_APP @@ -405,15 +376,39 @@ tests: set to G1 and the SceneID field set to 0x01." PICS: S.S.C01.Rsp && PICS_SKIP_SAMPLE_APP verification: | - ./chip-tool scenes view-scene GroupId SceneId Node-Id EndpointId - - Note: The number of ExtensionFieldSets, the value of clusterId of each ExtensionFieldSet, the number of attributes in attributeValueList and their values varies for each application - - Verify that the extension fields in the log match the ones expected and that - Status = 0x00 - GroupID = G1 - SceneID = 0x01 - TransitionTime = 0x0001 + ./chip-tool scenesmanagement view-scene 0x0101 0x01 1 1 + + Verify DUT sends a ViewSceneResponse command to TH with the Status field set to 0x00 (SUCCESS), the GroupID field set to G1, the SceneID field set to 0x01, the TransitionTime field set to 1000 and a set of extension fields appropriate to AC1 on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: + + + NOTE: The values below are expected to match the values from the specific AC tested + + [1708071897.294470][7731:7733] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0001 + [1708071897.294486][7731:7733] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0001 + [1708071897.294520][7731:7733] CHIP:TOO: ViewSceneResponse: { + [1708071897.294527][7731:7733] CHIP:TOO: status: 0 + [1708071897.294530][7731:7733] CHIP:TOO: groupID: 257 + [1708071897.294533][7731:7733] CHIP:TOO: sceneID: 1 + [1708071897.294536][7731:7733] CHIP:TOO: transitionTime: 1000 + [1708071897.294540][7731:7733] CHIP:TOO: sceneName: scene name + [1708071897.294554][7731:7733] CHIP:TOO: extensionFieldSets: 2 entries + [1708071897.294569][7731:7733] CHIP:TOO: [1]: { + [1708071897.294574][7731:7733] CHIP:TOO: ClusterID: 6 + [1708071897.294580][7731:7733] CHIP:TOO: AttributeValueList: 1 entries + [1708071897.294589][7731:7733] CHIP:TOO: [1]: { + [1708071897.294593][7731:7733] CHIP:TOO: AttributeID: 1 + [1708071897.294596][7731:7733] CHIP:TOO: AttributeValue: 1 + [1708071897.294599][7731:7733] CHIP:TOO: } + [1708071897.294603][7731:7733] CHIP:TOO: } + [1708071897.294611][7731:7733] CHIP:TOO: [2]: { + [1708071897.294615][7731:7733] CHIP:TOO: ClusterID: 8 + [1708071897.294621][7731:7733] CHIP:TOO: AttributeValueList: 1 entries + [1708071897.294628][7731:7733] CHIP:TOO: [1]: { + [1708071897.294633][7731:7733] CHIP:TOO: AttributeID: 0 + [1708071897.294636][7731:7733] CHIP:TOO: AttributeValue: 100 + [1708071897.294639][7731:7733] CHIP:TOO: } + [1708071897.294643][7731:7733] CHIP:TOO: } + [1708071897.294647][7731:7733] CHIP:TOO: } cluster: "LogCommands" command: "UserPrompt" arguments: @@ -449,7 +444,7 @@ tests: - label: "Step 5a: TH configures AC2 on DUT for all implemented application - clusters supporting scenes." + clusters supporting scenesmanagement." cluster: "Level Control" PICS: PICS_SDK_CI_ONLY command: "MoveToLevelWithOnOff" @@ -466,7 +461,7 @@ tests: - label: "Step 5a: TH configures AC2 on DUT for all implemented application - clusters supporting scenes." + clusters supporting scenesmanagement." verification: | Is DUT configured with AC2? cluster: "LogCommands" @@ -563,41 +558,8 @@ tests: field set to G1, the SceneID field set to 0x03, the TransitionTime field set to G1 and a set of extension fields appropriate to AC1." verification: | - ./chip-tool scenes add-scene GroupID SceneID TransitionTime "SceneName" '[{"clusterId": value, "attributeValueList":[{"attributeId": value, "attributeValue": value}]}' groupID endpointId - - Note: The number of ExtensionFieldSets, the value of clusterId of each ExtensionFieldSet, the number of attributes in attributeValueList and their values varies for each application - - Verify the "status is success" on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: - [1670970505.887060][5742:5744] CHIP:DMG: InvokeResponseMessage = - [1670970505.887118][5742:5744] CHIP:DMG: { - [1670970505.887172][5742:5744] CHIP:DMG: suppressResponse = false, - [1670970505.887231][5742:5744] CHIP:DMG: InvokeResponseIBs = - [1670970505.887307][5742:5744] CHIP:DMG: [ - [1670970505.887366][5742:5744] CHIP:DMG: InvokeResponseIB = - [1670970505.887444][5742:5744] CHIP:DMG: { - [1670970505.887507][5742:5744] CHIP:DMG: CommandDataIB = - [1670970505.887576][5742:5744] CHIP:DMG: { - [1670970505.887713][5742:5744] CHIP:DMG: CommandPathIB = - [1670970505.887804][5742:5744] CHIP:DMG: { - [1670970505.887940][5742:5744] CHIP:DMG: EndpointId = 0x1, - [1670970505.888093][5742:5744] CHIP:DMG: ClusterId = 0x5, - [1670970505.888242][5742:5744] CHIP:DMG: CommandId = 0x0, - [1670970505.888385][5742:5744] CHIP:DMG: }, - [1670970505.888692][5742:5744] CHIP:DMG: - [1670970505.888769][5742:5744] CHIP:DMG: CommandFields = - [1670970505.888852][5742:5744] CHIP:DMG: { - [1670970505.889030][5742:5744] CHIP:DMG: 0x0 = 0, - [1670970505.889183][5742:5744] CHIP:DMG: 0x1 = 1, - [1670970505.889406][5742:5744] CHIP:DMG: 0x2 = 1, - [1670970505.889515][5742:5744] CHIP:DMG: }, - [1670970505.889603][5742:5744] CHIP:DMG: }, - [1670970505.889684][5742:5744] CHIP:DMG: - [1670970505.889745][5742:5744] CHIP:DMG: }, - [1670970505.889821][5742:5744] CHIP:DMG: - [1670970505.889878][5742:5744] CHIP:DMG: ], - [1670970505.889953][5742:5744] CHIP:DMG: - [1670970505.890009][5742:5744] CHIP:DMG: InteractionModelRevision = 1 - [1670970505.890066][5742:5744] CHIP:DMG: }, + ./chip-tool scenesmanagement add-scene 0x0101 0x03 1 "scene name" '[{"clusterID": "0x0300", "attributeValueList":[{"attributeID": "0x4002", "attributeValue": "0x01"}]}]' 0xffffffffffff0101 1 + Note: As this is a multicast command, no log is expected. cluster: "LogCommands" command: "UserPrompt" PICS: S.S.C00.Rsp && PICS_SKIP_SAMPLE_APP @@ -651,15 +613,30 @@ tests: set to G1 and the SceneID field set to 0x03." PICS: S.S.C01.Rsp && PICS_SKIP_SAMPLE_APP verification: | - ./chip-tool scenes view-scene GroupId SceneId Node-Id EndpointId + ./chip-tool scenesmanagement view-scene GroupId SceneId Node-Id EndpointId Note: The number of ExtensionFieldSets, the value of clusterId of each ExtensionFieldSet, the number of attributes in attributeValueList and their values varies for each application - Verify that the extension fields in the log match the ones expected and that - Status = 0x00 - GroupID = G1 - SceneID = 0x03 - TransitionTime = 0x03E8 + Verify that the extension fields in the log match the ones expected and that the log output is similar to the following: + [1707285444.028460][13682:13684] CHIP:DMG: }, + [1707285444.028553][13682:13684] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0001 + [1707285444.028579][13682:13684] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0001 + [1707285444.028670][13682:13684] CHIP:TOO: ViewSceneResponse: { + [1707285444.028685][13682:13684] CHIP:TOO: status: 0 + [1707285444.028696][13682:13684] CHIP:TOO: groupID: 257 + [1707285444.028706][13682:13684] CHIP:TOO: sceneID: 3 + [1707285444.028717][13682:13684] CHIP:TOO: transitionTime: 1 + [1707285444.028728][13682:13684] CHIP:TOO: sceneName: scene name + [1707285444.028766][13682:13684] CHIP:TOO: extensionFieldSets: XX entries + [1707285444.028814][13682:13684] CHIP:TOO: [XX]: { + [1707285444.028828][13682:13684] CHIP:TOO: ClusterID: XX + [1707285444.028853][13682:13684] CHIP:TOO: AttributeValueList: XX entries + [1707285444.028882][13682:13684] CHIP:TOO: [XX]: { + [1707285444.028896][13682:13684] CHIP:TOO: AttributeID: XX + [1707285444.028913][13682:13684] CHIP:TOO: AttributeValue: XX + [1707285444.028925][13682:13684] CHIP:TOO: } + [1707285444.028937][13682:13684] CHIP:TOO: } + [1707285444.028950][13682:13684] CHIP:TOO: } cluster: "LogCommands" command: "UserPrompt" arguments: @@ -676,7 +653,7 @@ tests: - label: "Step 6c: TH sends a ViewScene command to group G1 with the GroupID field set to G1 and the SceneID field set to 0x03." - PICS: S.S.C01.Rsp && PICS_SDK_CI_ONLY + PICS: S.S.C01.Rsp command: "ViewScene" groupId: G1 arguments: @@ -711,7 +688,7 @@ tests: - label: "Step 6e: TH sends a ViewScene command to DUT with the GroupID field set to G1 and the SceneID field set to 0x03." - PICS: S.S.C01.Rsp && PICS_SDK_CI_ONLY + PICS: S.S.C01.Rsp command: "ViewScene" arguments: values: diff --git a/src/app/tests/suites/certification/Test_TC_S_2_4.yaml b/src/app/tests/suites/certification/Test_TC_S_2_4.yaml index eac34fdea1fee6..c3ba72dcf05b80 100644 --- a/src/app/tests/suites/certification/Test_TC_S_2_4.yaml +++ b/src/app/tests/suites/certification/Test_TC_S_2_4.yaml @@ -296,7 +296,7 @@ tests: - label: "Step 6a: TH configures AC2 on DUT for all implemented application clusters supporting scenes." - PICS: PICS_SDK_CI_ONLY + PICS: S.S.C05.Rsp && PICS_SDK_CI_ONLY cluster: "Level Control" command: "MoveToLevelWithOnOff" arguments: @@ -317,7 +317,7 @@ tests: Is DUT configured with AC2? cluster: "LogCommands" command: "UserPrompt" - PICS: PICS_SKIP_SAMPLE_APP + PICS: S.S.C05.Rsp && PICS_SKIP_SAMPLE_APP arguments: values: - name: "message" diff --git a/src/app/tests/suites/certification/Test_TC_S_2_5.yaml b/src/app/tests/suites/certification/Test_TC_S_2_5.yaml index 31ed8b17a2bcdb..e0a2998e06d965 100644 --- a/src/app/tests/suites/certification/Test_TC_S_2_5.yaml +++ b/src/app/tests/suites/certification/Test_TC_S_2_5.yaml @@ -61,14 +61,51 @@ tests: the GroupKeyMap attribute with one entry as follows: List item 1: FabricIndex: 1 GroupId: 0x0001 GroupKeySetId: 0x01a1" verification: | - ./chip-tool groupkeymanagement write group-key-map '[{"groupId": 1, "groupKeySetID": 1, "fabricIndex": 1}]' 1 0 - - [1688019387.509419][1710:1712] CHIP:DMG: } - [1688019387.509461][1710:1712] CHIP:DMG: - [1688019387.509497][1710:1712] CHIP:DMG: StatusIB = - [1688019387.509534][1710:1712] CHIP:DMG: { - [1688019387.509572][1710:1712] CHIP:DMG: status = 0x00 (SUCCESS), - [1688019387.509610][1710:1712] CHIP:DMG: }, + ./chip-tool groupkeymanagement write group-key-map '[{"groupId": "0x0001", "groupKeySetID": "0x01a1", "fabricIndex": 1} ]' 1 0 + + Verify DUT responds with SUCCESS status response on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: + + [1701076939.782934][16287:16289] CHIP:DMG: WriteResponseMessage = + [1701076939.782939][16287:16289] CHIP:DMG: { + [1701076939.782942][16287:16289] CHIP:DMG: AttributeStatusIBs = + [1701076939.782948][16287:16289] CHIP:DMG: [ + [1701076939.782951][16287:16289] CHIP:DMG: AttributeStatusIB = + [1701076939.782956][16287:16289] CHIP:DMG: { + [1701076939.782960][16287:16289] CHIP:DMG: AttributePathIB = + [1701076939.782965][16287:16289] CHIP:DMG: { + [1701076939.782970][16287:16289] CHIP:DMG: Endpoint = 0x0, + [1701076939.782973][16287:16289] CHIP:DMG: Cluster = 0x3f, + [1701076939.782977][16287:16289] CHIP:DMG: Attribute = 0x0000_0000, + [1701076939.782981][16287:16289] CHIP:DMG: } + [1701076939.782986][16287:16289] CHIP:DMG: + [1701076939.782990][16287:16289] CHIP:DMG: StatusIB = + [1701076939.782993][16287:16289] CHIP:DMG: { + [1701076939.782997][16287:16289] CHIP:DMG: status = 0x00 (SUCCESS), + [1701076939.783000][16287:16289] CHIP:DMG: }, + [1701076939.783004][16287:16289] CHIP:DMG: + [1701076939.783007][16287:16289] CHIP:DMG: }, + [1701076939.783014][16287:16289] CHIP:DMG: + [1701076939.783017][16287:16289] CHIP:DMG: AttributeStatusIB = + [1701076939.783021][16287:16289] CHIP:DMG: { + [1701076939.783024][16287:16289] CHIP:DMG: AttributePathIB = + [1701076939.783027][16287:16289] CHIP:DMG: { + [1701076939.783030][16287:16289] CHIP:DMG: Endpoint = 0x0, + [1701076939.783034][16287:16289] CHIP:DMG: Cluster = 0x3f, + [1701076939.783038][16287:16289] CHIP:DMG: Attribute = 0x0000_0000, + [1701076939.783042][16287:16289] CHIP:DMG: ListIndex = Null, + [1701076939.783045][16287:16289] CHIP:DMG: } + [1701076939.783050][16287:16289] CHIP:DMG: + [1701076939.783053][16287:16289] CHIP:DMG: StatusIB = + [1701076939.783056][16287:16289] CHIP:DMG: { + [1701076939.783060][16287:16289] CHIP:DMG: status = 0x00 (SUCCESS), + [1701076939.783063][16287:16289] CHIP:DMG: }, + [1701076939.783067][16287:16289] CHIP:DMG: + [1701076939.783069][16287:16289] CHIP:DMG: }, + [1701076939.783074][16287:16289] CHIP:DMG: + [1701076939.783077][16287:16289] CHIP:DMG: ], + [1701076939.783084][16287:16289] CHIP:DMG: + [1701076939.783087][16287:16289] CHIP:DMG: InteractionModelRevision = 11 + [1701076939.783090][16287:16289] CHIP:DMG: } disabled: true - label: "Step 1: TH sends a RemoveAllGroups command to DUT." @@ -76,12 +113,12 @@ tests: verification: | ./chip-tool groups remove-all-groups 1 1 - [1688019423.251477][1716:1718] CHIP:DMG: }, + Verify DUT responds with SUCCESS status response on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: [1688019423.251524][1716:1718] CHIP:DMG: - [1688019423.251561][1716:1718] CHIP:DMG: StatusIB = - [1688019423.251602][1716:1718] CHIP:DMG: { - [1688019423.251643][1716:1718] CHIP:DMG: status = 0x00 (SUCCESS), - [1688019423.251686][1716:1718] CHIP:DMG: }, + [1688019423.251561][1716:1718] CHIP:DMG: StatusIB = + [1688019423.251602][1716:1718] CHIP:DMG: { + [1688019423.251643][1716:1718] CHIP:DMG: status = 0x00 (SUCCESS), + [1688019423.251686][1716:1718] CHIP:DMG: }, [1688019423.251727][1716:1718] CHIP:DMG: disabled: true @@ -92,11 +129,16 @@ tests: verification: | ./chip-tool groups add-group 0x0001 grp1 1 1 - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0004 Command 0x0000_0000 - CHIP:TOO: AddGroupResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 1 - CHIP:TOO: } + Verify the AddGroupResponse with following fields: + Status is SUCCESS + Group ID is 0x0001 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1701259653.925863][10637:10639] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0004 Command=0x0000_0000 + [1701259653.925872][10637:10639] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0004 Command 0x0000_0000 + [1701259653.925891][10637:10639] CHIP:TOO: AddGroupResponse: { + [1701259653.925896][10637:10639] CHIP:TOO: status: 0 + [1701259653.925899][10637:10639] CHIP:TOO: groupID: 1 + [1701259653.925902][10637:10639] CHIP:TOO: } disabled: true - label: @@ -106,32 +148,137 @@ tests: verification: | ./chip-tool scenesmanagement remove-all-scenes 0x0001 1 1 - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0003 - CHIP:TOO: RemoveAllScenesResponse: { - CHIP:TOO: status: 1 - CHIP:TOO: groupID: 1 - CHIP:TOO: } + Verify the RemoveAllScenesResponse with following fields: + Status is SUCCESS + Group ID is 0x0001 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1706764352.114217][4432:4434] CHIP:DMG: }, + [1706764352.114233][4432:4434] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0003 + [1706764352.114241][4432:4434] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0003 + [1706764352.114257][4432:4434] CHIP:TOO: RemoveAllScenesResponse: { + [1706764352.114264][4432:4434] CHIP:TOO: status: 0 + [1706764352.114267][4432:4434] CHIP:TOO: groupID: 1 + [1706764352.114269][4432:4434] CHIP:TOO: } disabled: true - label: "Step 4a: TH reads from the DUT the SceneTableSize attribute" verification: | ./chip-tool scenesmanagement read scene-table-size 1 1 - [1688019474.695136][1726:1728] CHIP:DMG: } - [1688019474.695335][1726:1728] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Attribute 0x0000_0006 DataVersion: 1550229741 - [1688019474.695397][1726:1728] CHIP:TOO: SceneTableSize: (Default table size: 16) + Verify the "SceneTableSize" attribute value is SceneTableSize(minimum=16) on the TH (Chip-tool) and below is the sample log provided for the raspi platform: + + [1706764370.034843][4435:4437] CHIP:DMG: } + [1706764370.034970][4435:4437] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0001 DataVersion: 3964423870 + [1706764370.035000][4435:4437] CHIP:TOO: SceneTableSize: 16 disabled: true - label: "Step 4b: TH sends a subscription request action for FabricSceneInfo to the DUT." verification: | + Please use Interactive mode to Verify the subscription of an event + Here the command to enter interactive mode:-- ./chip-tool interactive start - >>> any subscribe-by-id 0x0062 0x0002 min-interval max-interval node-id endpoint + + Set up the subscription between DUT and TH by sending the command mentioned below, and verify that the subscription is activated successfully + + scenesmanagement subscribe fabric-scene-info 0 200 1 1 + + Verify the DUT sends a report data for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into RemainingCapacity and is equals to (MaxRemainingCapacity) on the TH (Chip-tool) and below is the sample log provided for the raspi platform: + + [1706764401.002841][4438:4440] CHIP:DMG: ReportDataMessage = + [1706764401.002862][4438:4440] CHIP:DMG: { + [1706764401.002879][4438:4440] CHIP:DMG: SubscriptionId = 0x679cab48, + [1706764401.002891][4438:4440] CHIP:DMG: AttributeReportIBs = + [1706764401.002916][4438:4440] CHIP:DMG: [ + [1706764401.002926][4438:4440] CHIP:DMG: AttributeReportIB = + [1706764401.002950][4438:4440] CHIP:DMG: { + [1706764401.002960][4438:4440] CHIP:DMG: AttributeDataIB = + [1706764401.002972][4438:4440] CHIP:DMG: { + [1706764401.002985][4438:4440] CHIP:DMG: DataVersion = 0xec4c4ebe, + [1706764401.002996][4438:4440] CHIP:DMG: AttributePathIB = + [1706764401.003008][4438:4440] CHIP:DMG: { + [1706764401.003021][4438:4440] CHIP:DMG: Endpoint = 0x1, + [1706764401.003035][4438:4440] CHIP:DMG: Cluster = 0x62, + [1706764401.003048][4438:4440] CHIP:DMG: Attribute = 0x0000_0002, + [1706764401.003059][4438:4440] CHIP:DMG: } + [1706764401.003076][4438:4440] CHIP:DMG: + [1706764401.003088][4438:4440] CHIP:DMG: Data = [ + [1706764401.003105][4438:4440] CHIP:DMG: + [1706764401.003121][4438:4440] CHIP:DMG: { + [1706764401.003136][4438:4440] CHIP:DMG: 0x0 = 0, + [1706764401.003150][4438:4440] CHIP:DMG: 0x1 = 1, + [1706764401.003162][4438:4440] CHIP:DMG: 0x2 = 1, + [1706764401.003175][4438:4440] CHIP:DMG: 0x3 = false, + [1706764401.003190][4438:4440] CHIP:DMG: 0x4 = 7, + [1706764401.003203][4438:4440] CHIP:DMG: 0xfe = 1, + [1706764401.003216][4438:4440] CHIP:DMG: }, + [1706764401.003229][4438:4440] CHIP:DMG: ], + [1706764401.003239][4438:4440] CHIP:DMG: }, + [1706764401.003260][4438:4440] CHIP:DMG: + [1706764401.003270][4438:4440] CHIP:DMG: }, + [1706764401.003292][4438:4440] CHIP:DMG: + [1706764401.003301][4438:4440] CHIP:DMG: ], + [1706764401.003324][4438:4440] CHIP:DMG: + [1706764401.003334][4438:4440] CHIP:DMG: InteractionModelRevision = 11 + [1706764401.003343][4438:4440] CHIP:DMG: } + [1706764401.003557][4438:4440] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 3964423870 + [1706764401.003615][4438:4440] CHIP:TOO: FabricSceneInfo: 1 entries + [1706764401.003676][4438:4440] CHIP:TOO: [1]: { + [1706764401.003698][4438:4440] CHIP:TOO: SceneCount: 0 + [1706764401.003708][4438:4440] CHIP:TOO: CurrentScene: 1 + [1706764401.003718][4438:4440] CHIP:TOO: CurrentGroup: 1 + [1706764401.003728][4438:4440] CHIP:TOO: SceneValid: FALSE + [1706764401.003740][4438:4440] CHIP:TOO: RemainingCapacity: 7 + [1706764401.003750][4438:4440] CHIP:TOO: FabricIndex: 1 + [1706764401.003761][4438:4440] CHIP:TOO: } + disabled: true + + - label: + "Step 4c: Keep subscription session active for the remainder of the + test" + verification: | + Keep subscription session active for the remainder of the test + + Confirm that the subscription session is active for the remainder of the test by the reception of Liveness checks: + [1706798074.365883][5179:5181] CHIP:DMG: Refresh LivenessCheckTime for 64224 milliseconds with SubscriptionId = 0x8537dfcd Peer = 01:0000000000000001 + disabled: true + + - label: + "Step 5a: TH sends a AddScene command to DUT with the GroupID field + set to G1, the SceneID field set to 0x01, the TransitionTime field set + to 20000 (20s) and no extension field sets." + PICS: S.S.C00.Rsp + verification: | + ./chip-tool scenesmanagement add-scene 0x0001 0x01 20000 scene1 [] 1 1 + + Verify the AddSceneResponse with following fields: + Status is SUCCESS + Group ID is 0x0001 + SceneID field set to 0x01 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1706764438.086631][4438:4440] CHIP:DMG: }, + [1706764438.086653][4438:4440] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1706764438.086665][4438:4440] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1706764438.086681][4438:4440] CHIP:TOO: AddSceneResponse: { + [1706764438.086685][4438:4440] CHIP:TOO: status: 0 + [1706764438.086688][4438:4440] CHIP:TOO: groupID: 1 + [1706764438.086690][4438:4440] CHIP:TOO: sceneID: 1 + [1706764438.086692][4438:4440] CHIP:TOO: } + disabled: true + + - label: + "Step 5b: Verify that the DUT sends a report data for FabricSceneInfo + after the MinIntervalFloor time; store the RemainingCapacity field + from this fabric’s entry reported in FabricSceneInfo into + RemainingCapacity; verify RemainingCapacity equals + (MaxRemainingCapacity-1)." + verification: | + Verify that the DUT sends a report data for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into RemainingCapacity and is equals to (MaxRemainingCapacity-1). [1706764465.493922][4438:4440] CHIP:DMG: ReportDataMessage = [1706764465.493926][4438:4440] CHIP:DMG: { - [1706764465.493928][4438:4440] CHIP:DMG: SubscriptionId = 0x8537dfcd, + [1706764465.493928][4438:4440] CHIP:DMG: SubscriptionId = 0xcd5a528f, [1706764465.493931][4438:4440] CHIP:DMG: AttributeReportIBs = [1706764465.493937][4438:4440] CHIP:DMG: [ [1706764465.493939][4438:4440] CHIP:DMG: AttributeReportIB = @@ -175,102 +322,6 @@ tests: [1706764465.494167][4438:4440] CHIP:TOO: RemainingCapacity: 6 [1706764465.494170][4438:4440] CHIP:TOO: FabricIndex: 1 [1706764465.494174][4438:4440] CHIP:TOO: } - ... - [1706797894.367789][5179:5181] CHIP:DMG: Subscription established with SubscriptionID = 0x8537dfcd MinInterval = 0s MaxInterval = 60s Peer = 01:0000000000000001 - ... - [1706798074.365189][5179:5181] CHIP:EM: >>> [E:29283r S:30665 M:266174816] (S) Msg RX from 1:0000000000000001 [0714] --- Type 0001:05 (IM:ReportData) - [1706798074.365317][5179:5181] CHIP:EM: Handling via exchange: 29283r, Delegate: 0xaaaacccf2a88 - [1706798074.365449][5179:5181] CHIP:DMG: ReportDataMessage = - [1706798074.365517][5179:5181] CHIP:DMG: { - [1706798074.365576][5179:5181] CHIP:DMG: SubscriptionId = 0x8537dfcd, - [1706798074.365638][5179:5181] CHIP:DMG: InteractionModelRevision = 11 - [1706798074.365696][5179:5181] CHIP:DMG: } - [1706798074.365883][5179:5181] CHIP:DMG: Refresh LivenessCheckTime for 64224 milliseconds with SubscriptionId = 0x85 - 37dfcd Peer = 01:0000000000000001 - - disabled: true - - - label: - "Step 4c: Keep subscription session active for the remainder of the - test" - verification: | - Confirm that the subscription session is active for the remainder of the test by the reception of Liveness checks: - - [1706798074.365883][5179:5181] CHIP:DMG: Refresh LivenessCheckTime for 64224 milliseconds with SubscriptionId = 0x8537dfcd Peer = 01:0000000000000001 - - disabled: true - - - label: - "Step 5a: TH sends a AddScene command to DUT with the GroupID field - set to G1, the SceneID field set to 0x01, the TransitionTime field set - to 20000 (20s) and no extension field sets." - PICS: S.S.C00.Rsp - verification: | - ./chip-tool scenesmanagement add-scene 0x0001 0x1 20000 scene1 [] 1 1 - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - CHIP:TOO: AddSceneResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 1 - CHIP:TOO: sceneID: 1 - CHIP:TOO: } - disabled: true - - - label: - "Step 5b: Verify that the DUT sends a report data for FabricSceneInfo - after the MinIntervalFloor time; store the RemainingCapacity field - from this fabric’s entry reported in FabricSceneInfo into - RemainingCapacity; verify RemainingCapacity equals - (MaxRemainingCapacity-1)." - verification: | - CHIP:DMG: ReportDataMessage = - CHIP:DMG: { - CHIP:DMG: SubscriptionId = 0x8537dfcd, - CHIP:DMG: AttributeReportIBs = - CHIP:DMG: [ - CHIP:DMG: AttributeReportIB = - CHIP:DMG: { - CHIP:DMG: AttributeDataIB = - CHIP:DMG: { - CHIP:DMG: DataVersion = 0x92ecb45d, - CHIP:DMG: AttributePathIB = - CHIP:DMG: { - CHIP:DMG: Endpoint = 0x1, - CHIP:DMG: Cluster = 0x62, - CHIP:DMG: Attribute = 0x0000_0002, - CHIP:DMG: } - CHIP:DMG: - CHIP:DMG: Data = [ - CHIP:DMG: - CHIP:DMG: { - CHIP:DMG: 0x0 = 1, - CHIP:DMG: 0x1 = 0, - CHIP:DMG: 0x2 = 0, - CHIP:DMG: 0x3 = false, - CHIP:DMG: 0x4 = 6, - CHIP:DMG: 0xfe = 1, - CHIP:DMG: }, - CHIP:DMG: ], - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: ], - CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 11 - CHIP:DMG: } - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 1 - CHIP:TOO: CurrentScene: 0 - CHIP:TOO: CurrentGroup: 0 - CHIP:TOO: SceneValid: FALSE - CHIP:TOO: RemainingCapacity: 6 - CHIP:TOO: FabricIndex: 1 - CHIP:TOO: } - CHIP:DMG: Refresh LivenessCheckTime for 9224 milliseconds with SubscriptionId = 0x8537dfcd Peer = 01:0000000000000001 - disabled: true - label: @@ -280,14 +331,21 @@ tests: 8a." PICS: S.S.C04.Rsp verification: | - ./chip-tool scenesmanagement store-scene 0x0001 0x2 20000 scene2 [] 1 1 - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - CHIP:TOO: AddSceneResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 1 - CHIP:TOO: sceneID: 2 - CHIP:TOO: } + ./chiptool scenesmanagement store-scene 0x0001 0x02 1 1 + + Verify the StoreSceneResponse with following fields: + Status is SUCCESS + Group ID is 0x0001 + SceneID field set to 0x02 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1706764492.588457][4438:4440] CHIP:DMG: }, + [1706764492.588474][4438:4440] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0004 + [1706764492.588479][4438:4440] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0004 + [1706764492.588490][4438:4440] CHIP:TOO: StoreSceneResponse: { + [1706764492.588494][4438:4440] CHIP:TOO: status: 0 + [1706764492.588497][4438:4440] CHIP:TOO: groupID: 1 + [1706764492.588500][4438:4440] CHIP:TOO: sceneID: 2 + [1706764492.588503][4438:4440] CHIP:TOO: } disabled: true - label: @@ -297,53 +355,54 @@ tests: RemainingCapacity; verify RemainingCapacity equals (MaxRemainingCapacity-2)." verification: | - CHIP:DMG: ReportDataMessage = - CHIP:DMG: { - CHIP:DMG: SubscriptionId = 0x8537dfcd, - CHIP:DMG: AttributeReportIBs = - CHIP:DMG: [ - CHIP:DMG: AttributeReportIB = - CHIP:DMG: { - CHIP:DMG: AttributeDataIB = - CHIP:DMG: { - CHIP:DMG: DataVersion = 0x92ecb45d, - CHIP:DMG: AttributePathIB = - CHIP:DMG: { - CHIP:DMG: Endpoint = 0x1, - CHIP:DMG: Cluster = 0x62, - CHIP:DMG: Attribute = 0x0000_0002, - CHIP:DMG: } - CHIP:DMG: - CHIP:DMG: Data = [ - CHIP:DMG: - CHIP:DMG: { - CHIP:DMG: 0x0 = 2, - CHIP:DMG: 0x1 = 2, - CHIP:DMG: 0x2 = 1, - CHIP:DMG: 0x3 = true, - CHIP:DMG: 0x4 = 5, - CHIP:DMG: 0xfe = 1, - CHIP:DMG: }, - CHIP:DMG: ], - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: ], - CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 11 - CHIP:DMG: } - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 2 - CHIP:TOO: CurrentScene: 2 - CHIP:TOO: CurrentGroup: 1 - CHIP:TOO: SceneValid: TRUE - CHIP:TOO: RemainingCapacity: 5 - CHIP:TOO: FabricIndex: 1 - CHIP:TOO: } - CHIP:DMG: Refresh LivenessCheckTime for 9224 milliseconds with SubscriptionId = 0x8537dfcd Peer = 01:0000000000000001 + Verify that the DUT sends a report data for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into RemainingCapacity and is equals to (MaxRemainingCapacity-2). + + [1706764510.478452][4438:4440] CHIP:DMG: ReportDataMessage = + [1706764510.478456][4438:4440] CHIP:DMG: { + [1706764510.478462][4438:4440] CHIP:DMG: SubscriptionId = 0x6b998a6d, + [1706764510.478466][4438:4440] CHIP:DMG: AttributeReportIBs = + [1706764510.478475][4438:4440] CHIP:DMG: [ + [1706764510.478478][4438:4440] CHIP:DMG: AttributeReportIB = + [1706764510.478485][4438:4440] CHIP:DMG: { + [1706764510.478488][4438:4440] CHIP:DMG: AttributeDataIB = + [1706764510.478492][4438:4440] CHIP:DMG: { + [1706764510.478496][4438:4440] CHIP:DMG: DataVersion = 0xec4c4ec3, + [1706764510.478499][4438:4440] CHIP:DMG: AttributePathIB = + [1706764510.478503][4438:4440] CHIP:DMG: { + [1706764510.478507][4438:4440] CHIP:DMG: Endpoint = 0x1, + [1706764510.478511][4438:4440] CHIP:DMG: Cluster = 0x62, + [1706764510.478515][4438:4440] CHIP:DMG: Attribute = 0x0000_0002, + [1706764510.478518][4438:4440] CHIP:DMG: } + [1706764510.478522][4438:4440] CHIP:DMG: + [1706764510.478526][4438:4440] CHIP:DMG: Data = [ + [1706764510.478530][4438:4440] CHIP:DMG: + [1706764510.478535][4438:4440] CHIP:DMG: { + [1706764510.478542][4438:4440] CHIP:DMG: 0x0 = 2, + [1706764510.478547][4438:4440] CHIP:DMG: 0x1 = 2, + [1706764510.478551][4438:4440] CHIP:DMG: 0x2 = 1, + [1706764510.478556][4438:4440] CHIP:DMG: 0x3 = true, + [1706764510.478561][4438:4440] CHIP:DMG: 0x4 = 5, + [1706764510.478566][4438:4440] CHIP:DMG: 0xfe = 1, + [1706764510.478570][4438:4440] CHIP:DMG: }, + [1706764510.478575][4438:4440] CHIP:DMG: ], + [1706764510.478578][4438:4440] CHIP:DMG: }, + [1706764510.478586][4438:4440] CHIP:DMG: + [1706764510.478589][4438:4440] CHIP:DMG: }, + [1706764510.478597][4438:4440] CHIP:DMG: + [1706764510.478601][4438:4440] CHIP:DMG: ], + [1706764510.478609][4438:4440] CHIP:DMG: + [1706764510.478612][4438:4440] CHIP:DMG: InteractionModelRevision = 11 + [1706764510.478616][4438:4440] CHIP:DMG: } + [1706764510.478681][4438:4440] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 3964423875 + [1706764510.478697][4438:4440] CHIP:TOO: FabricSceneInfo: 1 entries + [1706764510.478710][4438:4440] CHIP:TOO: [1]: { + [1706764510.478714][4438:4440] CHIP:TOO: SceneCount: 2 + [1706764510.478718][4438:4440] CHIP:TOO: CurrentScene: 2 + [1706764510.478721][4438:4440] CHIP:TOO: CurrentGroup: 1 + [1706764510.478725][4438:4440] CHIP:TOO: SceneValid: TRUE + [1706764510.478729][4438:4440] CHIP:TOO: RemainingCapacity: 5 + [1706764510.478733][4438:4440] CHIP:TOO: FabricIndex: 1 + [1706764510.478737][4438:4440] CHIP:TOO: } disabled: true - label: @@ -353,7 +412,21 @@ tests: field sets. If RemainingCapacity is 0, continue to Step 8a." PICS: S.S.C00.Rsp verification: | - ./chip-tool scenesmanagement add-scene 0x0001 0x3 20000 scene3 [] 1 1 + ./chip-tool scenesmanagement add-scene 0x0001 0x03 20000 scene1 [] 1 1 + + Verify the AddSceneResponse with following fields: + Status is SUCCESS + Group ID is 0x0001 + SceneID field set to 0x03 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1706764534.554889][4438:4440] CHIP:DMG: }, + [1706764534.554927][4438:4440] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1706764534.554933][4438:4440] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1706764534.554947][4438:4440] CHIP:TOO: AddSceneResponse: { + [1706764534.554952][4438:4440] CHIP:TOO: status: 0 + [1706764534.554955][4438:4440] CHIP:TOO: groupID: 1 + [1706764534.554958][4438:4440] CHIP:TOO: sceneID: 3 + [1706764534.554961][4438:4440] CHIP:TOO: } disabled: true - label: @@ -363,53 +436,54 @@ tests: RemainingCapacity; verify RemainingCapacity equals (MaxRemainingCapacity-3)." verification: | - CHIP:DMG: ReportDataMessage = - CHIP:DMG: { - CHIP:DMG: SubscriptionId = 0x8537dfcd, - CHIP:DMG: AttributeReportIBs = - CHIP:DMG: [ - CHIP:DMG: AttributeReportIB = - CHIP:DMG: { - CHIP:DMG: AttributeDataIB = - CHIP:DMG: { - CHIP:DMG: DataVersion = 0x92ecb45d, - CHIP:DMG: AttributePathIB = - CHIP:DMG: { - CHIP:DMG: Endpoint = 0x1, - CHIP:DMG: Cluster = 0x62, - CHIP:DMG: Attribute = 0x0000_0002, - CHIP:DMG: } - CHIP:DMG: - CHIP:DMG: Data = [ - CHIP:DMG: - CHIP:DMG: { - CHIP:DMG: 0x0 = 3, - CHIP:DMG: 0x1 = 2, - CHIP:DMG: 0x2 = 1, - CHIP:DMG: 0x3 = true, - CHIP:DMG: 0x4 = 4, - CHIP:DMG: 0xfe = 1, - CHIP:DMG: }, - CHIP:DMG: ], - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: ], - CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 11 - CHIP:DMG: } - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 3 - CHIP:TOO: CurrentScene: 2 - CHIP:TOO: CurrentGroup: 1 - CHIP:TOO: SceneValid: TRUE - CHIP:TOO: RemainingCapacity: 4 - CHIP:TOO: FabricIndex: 1 - CHIP:TOO: } - CHIP:DMG: Refresh LivenessCheckTime for 9224 milliseconds with SubscriptionId = 0x8537dfcd Peer = 01:0000000000000001 + Verify that the DUT sends a report data for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into RemainingCapacity and is equals to (MaxRemainingCapacity-3). + + [1706764553.457875][4438:4440] CHIP:DMG: ReportDataMessage = + [1706764553.457878][4438:4440] CHIP:DMG: { + [1706764553.457880][4438:4440] CHIP:DMG: SubscriptionId = 0xa7ba9271, + [1706764553.457883][4438:4440] CHIP:DMG: AttributeReportIBs = + [1706764553.457888][4438:4440] CHIP:DMG: [ + [1706764553.457892][4438:4440] CHIP:DMG: AttributeReportIB = + [1706764553.457901][4438:4440] CHIP:DMG: { + [1706764553.457905][4438:4440] CHIP:DMG: AttributeDataIB = + [1706764553.457910][4438:4440] CHIP:DMG: { + [1706764553.457913][4438:4440] CHIP:DMG: DataVersion = 0xec4c4ec5, + [1706764553.457915][4438:4440] CHIP:DMG: AttributePathIB = + [1706764553.457918][4438:4440] CHIP:DMG: { + [1706764553.457920][4438:4440] CHIP:DMG: Endpoint = 0x1, + [1706764553.457923][4438:4440] CHIP:DMG: Cluster = 0x62, + [1706764553.457926][4438:4440] CHIP:DMG: Attribute = 0x0000_0002, + [1706764553.457929][4438:4440] CHIP:DMG: } + [1706764553.457932][4438:4440] CHIP:DMG: + [1706764553.457935][4438:4440] CHIP:DMG: Data = [ + [1706764553.457938][4438:4440] CHIP:DMG: + [1706764553.457941][4438:4440] CHIP:DMG: { + [1706764553.457944][4438:4440] CHIP:DMG: 0x0 = 3, + [1706764553.457947][4438:4440] CHIP:DMG: 0x1 = 2, + [1706764553.457950][4438:4440] CHIP:DMG: 0x2 = 1, + [1706764553.457953][4438:4440] CHIP:DMG: 0x3 = true, + [1706764553.457957][4438:4440] CHIP:DMG: 0x4 = 4, + [1706764553.457963][4438:4440] CHIP:DMG: 0xfe = 1, + [1706764553.457968][4438:4440] CHIP:DMG: }, + [1706764553.457973][4438:4440] CHIP:DMG: ], + [1706764553.457977][4438:4440] CHIP:DMG: }, + [1706764553.457985][4438:4440] CHIP:DMG: + [1706764553.457990][4438:4440] CHIP:DMG: }, + [1706764553.457998][4438:4440] CHIP:DMG: + [1706764553.458002][4438:4440] CHIP:DMG: ], + [1706764553.458011][4438:4440] CHIP:DMG: + [1706764553.458016][4438:4440] CHIP:DMG: InteractionModelRevision = 11 + [1706764553.458019][4438:4440] CHIP:DMG: } + [1706764553.458074][4438:4440] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 3964423877 + [1706764553.458086][4438:4440] CHIP:TOO: FabricSceneInfo: 1 entries + [1706764553.458095][4438:4440] CHIP:TOO: [1]: { + [1706764553.458098][4438:4440] CHIP:TOO: SceneCount: 3 + [1706764553.458100][4438:4440] CHIP:TOO: CurrentScene: 2 + [1706764553.458102][4438:4440] CHIP:TOO: CurrentGroup: 1 + [1706764553.458104][4438:4440] CHIP:TOO: SceneValid: TRUE + [1706764553.458107][4438:4440] CHIP:TOO: RemainingCapacity: 4 + [1706764553.458109][4438:4440] CHIP:TOO: FabricIndex: 1 + [1706764553.458111][4438:4440] CHIP:TOO: } disabled: true - label: @@ -417,14 +491,20 @@ tests: set to G1 and the SceneID field set to 0x01." PICS: S.S.C02.Rsp verification: | - ./chip-tool scenesmanagement remove-scene 0x0001 0x1 1 1 - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0002 - CHIP:TOO: RemoveSceneResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 1 - CHIP:TOO: sceneID: 1 - CHIP:TOO: } + ./chip-tool scenesmanagement remove-scene 0x0001 0x01 1 1 + + Verify the RemoveScenesResponse with following fields: + Status is SUCCESS + Group ID is 0x0001 + SceneID field set to 0x01 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1706764583.008025][4438:4440] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0002 + [1706764583.008031][4438:4440] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0002 + [1706764583.008044][4438:4440] CHIP:TOO: RemoveSceneResponse: { + [1706764583.008049][4438:4440] CHIP:TOO: status: 0 + [1706764583.008054][4438:4440] CHIP:TOO: groupID: 1 + [1706764583.008059][4438:4440] CHIP:TOO: sceneID: 1 + [1706764583.008064][4438:4440] CHIP:TOO: } disabled: true - label: @@ -434,53 +514,54 @@ tests: RemainingCapacity; verify RemainingCapacity equals (MaxRemainingCapacity-2)." verification: | - CHIP:DMG: ReportDataMessage = - CHIP:DMG: { - CHIP:DMG: SubscriptionId = 0x8537dfcd, - CHIP:DMG: AttributeReportIBs = - CHIP:DMG: [ - CHIP:DMG: AttributeReportIB = - CHIP:DMG: { - CHIP:DMG: AttributeDataIB = - CHIP:DMG: { - CHIP:DMG: DataVersion = 0x92ecb45d, - CHIP:DMG: AttributePathIB = - CHIP:DMG: { - CHIP:DMG: Endpoint = 0x1, - CHIP:DMG: Cluster = 0x62, - CHIP:DMG: Attribute = 0x0000_0002, - CHIP:DMG: } - CHIP:DMG: - CHIP:DMG: Data = [ - CHIP:DMG: - CHIP:DMG: { - CHIP:DMG: 0x0 = 2, - CHIP:DMG: 0x1 = 2, - CHIP:DMG: 0x2 = 1, - CHIP:DMG: 0x3 = true, - CHIP:DMG: 0x4 = 5, - CHIP:DMG: 0xfe = 1, - CHIP:DMG: }, - CHIP:DMG: ], - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: ], - CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 11 - CHIP:DMG: } - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 2 - CHIP:TOO: CurrentScene: 2 - CHIP:TOO: CurrentGroup: 1 - CHIP:TOO: SceneValid: TRUE - CHIP:TOO: RemainingCapacity: 5 - CHIP:TOO: FabricIndex: 1 - CHIP:TOO: } - CHIP:DMG: Refresh LivenessCheckTime for 9224 milliseconds with SubscriptionId = 0x8537dfcd Peer = 01:0000000000000001 + Verify that the DUT sends a report data for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into RemainingCapacity and is equals to (MaxRemainingCapacity-2). + + [1706764600.346946][4438:4440] CHIP:DMG: ReportDataMessage = + [1706764600.346951][4438:4440] CHIP:DMG: { + [1706764600.346955][4438:4440] CHIP:DMG: SubscriptionId = 0xb5fdbb95, + [1706764600.346959][4438:4440] CHIP:DMG: AttributeReportIBs = + [1706764600.346968][4438:4440] CHIP:DMG: [ + [1706764600.346973][4438:4440] CHIP:DMG: AttributeReportIB = + [1706764600.346982][4438:4440] CHIP:DMG: { + [1706764600.346986][4438:4440] CHIP:DMG: AttributeDataIB = + [1706764600.346992][4438:4440] CHIP:DMG: { + [1706764600.346999][4438:4440] CHIP:DMG: DataVersion = 0xec4c4ec7, + [1706764600.347003][4438:4440] CHIP:DMG: AttributePathIB = + [1706764600.347010][4438:4440] CHIP:DMG: { + [1706764600.347016][4438:4440] CHIP:DMG: Endpoint = 0x1, + [1706764600.347021][4438:4440] CHIP:DMG: Cluster = 0x62, + [1706764600.347027][4438:4440] CHIP:DMG: Attribute = 0x0000_0002, + [1706764600.347031][4438:4440] CHIP:DMG: } + [1706764600.347038][4438:4440] CHIP:DMG: + [1706764600.347043][4438:4440] CHIP:DMG: Data = [ + [1706764600.347048][4438:4440] CHIP:DMG: + [1706764600.347054][4438:4440] CHIP:DMG: { + [1706764600.347060][4438:4440] CHIP:DMG: 0x0 = 2, + [1706764600.347065][4438:4440] CHIP:DMG: 0x1 = 2, + [1706764600.347071][4438:4440] CHIP:DMG: 0x2 = 1, + [1706764600.347077][4438:4440] CHIP:DMG: 0x3 = true, + [1706764600.347083][4438:4440] CHIP:DMG: 0x4 = 5, + [1706764600.347089][4438:4440] CHIP:DMG: 0xfe = 1, + [1706764600.347094][4438:4440] CHIP:DMG: }, + [1706764600.347098][4438:4440] CHIP:DMG: ], + [1706764600.347103][4438:4440] CHIP:DMG: }, + [1706764600.347111][4438:4440] CHIP:DMG: + [1706764600.347115][4438:4440] CHIP:DMG: }, + [1706764600.347124][4438:4440] CHIP:DMG: + [1706764600.347128][4438:4440] CHIP:DMG: ], + [1706764600.347135][4438:4440] CHIP:DMG: + [1706764600.347138][4438:4440] CHIP:DMG: InteractionModelRevision = 11 + [1706764600.347140][4438:4440] CHIP:DMG: } + [1706764600.347196][4438:4440] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 3964423879 + [1706764600.347211][4438:4440] CHIP:TOO: FabricSceneInfo: 1 entries + [1706764600.347224][4438:4440] CHIP:TOO: [1]: { + [1706764600.347230][4438:4440] CHIP:TOO: SceneCount: 2 + [1706764600.347234][4438:4440] CHIP:TOO: CurrentScene: 2 + [1706764600.347257][4438:4440] CHIP:TOO: CurrentGroup: 1 + [1706764600.347261][4438:4440] CHIP:TOO: SceneValid: TRUE + [1706764600.347267][4438:4440] CHIP:TOO: RemainingCapacity: 5 + [1706764600.347272][4438:4440] CHIP:TOO: FabricIndex: 1 + [1706764600.347276][4438:4440] CHIP:TOO: } disabled: true - label: @@ -488,13 +569,19 @@ tests: field set to G1." PICS: S.S.C03.Rsp verification: | - ./chip-tool scenesmanagement remove-all-scenes 0x0001 1 1 - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0003 - CHIP:TOO: RemoveAllScenesResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 1 - CHIP:TOO: } + scenesmanagement remove-all-scenes 0x0001 1 1 + + Verify the RemoveAllScenesResponse with following fields: + Status is SUCCESS + Group ID is 0x0001 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1706764629.391457][4438:4440] CHIP:DMG: }, + [1706764629.391475][4438:4440] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0003 + [1706764629.391479][4438:4440] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0003 + [1706764629.391488][4438:4440] CHIP:TOO: RemoveAllScenesResponse: { + [1706764629.391492][4438:4440] CHIP:TOO: status: 0 + [1706764629.391495][4438:4440] CHIP:TOO: groupID: 1 + [1706764629.391498][4438:4440] CHIP:TOO: } disabled: true - label: @@ -504,53 +591,54 @@ tests: RemainingCapacity; verify RemainingCapacity equals (MaxRemainingCapacity)." verification: | - CHIP:DMG: ReportDataMessage = - CHIP:DMG: { - CHIP:DMG: SubscriptionId = 0x8537dfcd, - CHIP:DMG: AttributeReportIBs = - CHIP:DMG: [ - CHIP:DMG: AttributeReportIB = - CHIP:DMG: { - CHIP:DMG: AttributeDataIB = - CHIP:DMG: { - CHIP:DMG: DataVersion = 0x92ecb45d, - CHIP:DMG: AttributePathIB = - CHIP:DMG: { - CHIP:DMG: Endpoint = 0x1, - CHIP:DMG: Cluster = 0x62, - CHIP:DMG: Attribute = 0x0000_0002, - CHIP:DMG: } - CHIP:DMG: - CHIP:DMG: Data = [ - CHIP:DMG: - CHIP:DMG: { - CHIP:DMG: 0x0 = 0, - CHIP:DMG: 0x1 = 2, - CHIP:DMG: 0x2 = 1, - CHIP:DMG: 0x3 = false, - CHIP:DMG: 0x4 = 7, - CHIP:DMG: 0xfe = 1, - CHIP:DMG: }, - CHIP:DMG: ], - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: ], - CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 11 - CHIP:DMG: } - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 0 - CHIP:TOO: CurrentScene: 2 - CHIP:TOO: CurrentGroup: 1 - CHIP:TOO: SceneValid: FALSE - CHIP:TOO: RemainingCapacity: 7 - CHIP:TOO: FabricIndex: 1 - CHIP:TOO: } - CHIP:DMG: Refresh LivenessCheckTime for 9224 milliseconds with SubscriptionId = 0x8537dfcd Peer = 01:0000000000000001 + Verify that the DUT sends a report data for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into RemainingCapacity and is equals to (MaxRemainingCapacity). + + [1706764645.968086][4438:4440] CHIP:DMG: ReportDataMessage = + [1706764645.968089][4438:4440] CHIP:DMG: { + [1706764645.968092][4438:4440] CHIP:DMG: SubscriptionId = 0x8dd9174a, + [1706764645.968094][4438:4440] CHIP:DMG: AttributeReportIBs = + [1706764645.968101][4438:4440] CHIP:DMG: [ + [1706764645.968103][4438:4440] CHIP:DMG: AttributeReportIB = + [1706764645.968109][4438:4440] CHIP:DMG: { + [1706764645.968112][4438:4440] CHIP:DMG: AttributeDataIB = + [1706764645.968115][4438:4440] CHIP:DMG: { + [1706764645.968119][4438:4440] CHIP:DMG: DataVersion = 0xec4c4ec9, + [1706764645.968122][4438:4440] CHIP:DMG: AttributePathIB = + [1706764645.968127][4438:4440] CHIP:DMG: { + [1706764645.968130][4438:4440] CHIP:DMG: Endpoint = 0x1, + [1706764645.968134][4438:4440] CHIP:DMG: Cluster = 0x62, + [1706764645.968137][4438:4440] CHIP:DMG: Attribute = 0x0000_0002, + [1706764645.968140][4438:4440] CHIP:DMG: } + [1706764645.968145][4438:4440] CHIP:DMG: + [1706764645.968148][4438:4440] CHIP:DMG: Data = [ + [1706764645.968151][4438:4440] CHIP:DMG: + [1706764645.968154][4438:4440] CHIP:DMG: { + [1706764645.968158][4438:4440] CHIP:DMG: 0x0 = 0, + [1706764645.968162][4438:4440] CHIP:DMG: 0x1 = 2, + [1706764645.968166][4438:4440] CHIP:DMG: 0x2 = 1, + [1706764645.968169][4438:4440] CHIP:DMG: 0x3 = false, + [1706764645.968173][4438:4440] CHIP:DMG: 0x4 = 7, + [1706764645.968177][4438:4440] CHIP:DMG: 0xfe = 1, + [1706764645.968180][4438:4440] CHIP:DMG: }, + [1706764645.968184][4438:4440] CHIP:DMG: ], + [1706764645.968186][4438:4440] CHIP:DMG: }, + [1706764645.968192][4438:4440] CHIP:DMG: + [1706764645.968195][4438:4440] CHIP:DMG: }, + [1706764645.968201][4438:4440] CHIP:DMG: + [1706764645.968203][4438:4440] CHIP:DMG: ], + [1706764645.968210][4438:4440] CHIP:DMG: + [1706764645.968212][4438:4440] CHIP:DMG: InteractionModelRevision = 11 + [1706764645.968215][4438:4440] CHIP:DMG: } + [1706764645.968262][4438:4440] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 3964423881 + [1706764645.968272][4438:4440] CHIP:TOO: FabricSceneInfo: 1 entries + [1706764645.968283][4438:4440] CHIP:TOO: [1]: { + [1706764645.968286][4438:4440] CHIP:TOO: SceneCount: 0 + [1706764645.968289][4438:4440] CHIP:TOO: CurrentScene: 2 + [1706764645.968291][4438:4440] CHIP:TOO: CurrentGroup: 1 + [1706764645.968294][4438:4440] CHIP:TOO: SceneValid: FALSE + [1706764645.968297][4438:4440] CHIP:TOO: RemainingCapacity: 7 + [1706764645.968300][4438:4440] CHIP:TOO: FabricIndex: 1 + [1706764645.968303][4438:4440] CHIP:TOO: } disabled: true - label: @@ -558,12 +646,14 @@ tests: KeySetRemove command to the GroupKeyManagement cluster with the GroupKeySetID field set to 0x01a1" verification: | - ./chip-tool groupkeymanagement key-set-remove 1 1 0 + ./chip-tool groupkeymanagement key-set-remove 0x01a1 1 0 + + Verify DUT responds with SUCCESS status response on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: - [1688019719.867880][1746:1748] CHIP:DMG: }, + [1688019719.867880][1746:1748] CHIP:DMG: }, [1688019719.867923][1746:1748] CHIP:DMG: - [1688019719.867956][1746:1748] CHIP:DMG: StatusIB = - [1688019719.867995][1746:1748] CHIP:DMG: { - [1688019719.868033][1746:1748] CHIP:DMG: status = 0x00 (SUCCESS), - [1688019719.868071][1746:1748] CHIP:DMG: }, + [1688019719.867956][1746:1748] CHIP:DMG: StatusIB = + [1688019719.867995][1746:1748] CHIP:DMG: { + [1688019719.868033][1746:1748] CHIP:DMG: status = 0x00 (SUCCESS), + [1688019719.868071][1746:1748] CHIP:DMG: }, disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_S_2_6.yaml b/src/app/tests/suites/certification/Test_TC_S_2_6.yaml index 2d5e5cf0df2b99..2c8d0ce4e5a820 100644 --- a/src/app/tests/suites/certification/Test_TC_S_2_6.yaml +++ b/src/app/tests/suites/certification/Test_TC_S_2_6.yaml @@ -27,11 +27,64 @@ config: endpoint: 0 tests: - - label: "Precondition" + - label: "Precondition: Commission DUT to TH1" verification: | - - TH1, TH2, and TH3 should be on separate, distinct fabrics. - - A given fabric SHALL NOT consume more than half (rounded down towards 0) of the Scene Table entries (as indicated in the SceneTableSize attribute). - - MaxRemainingCapacity is SceneTableSize/2. + Once DUT reach the commissionable state send the following command on TH1: + ./chip-tool pairing onnetwork 1 20202021 + Verify the commissioning completed with success on TH(chip-tool) from DUT + [1650455358.501816][4366:4371] CHIP:TOO: Device commissioning completed with success + disabled: true + + - label: "Precondition: Commission DUT to TH2 (Open Commissioning Window)" + verification: | + Open a commissioning window On TH1(Chiptool)using below command + + ./chip-tool pairing open-commissioning-window 1 1 400 2000 3841 + + Verify the Successfully opened pairing window On TH1(Chiptool)e device + + [1657186324.710951][10820:10825] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_003C Command=0x0000_0000 Status=0x0 + [1657186324.710980][10820:10825] CHIP:CTL: Successfully opened pairing window On TH(Chiptool)e device + [1657186324.711048][10820:10825] CHIP:CTL: Manual pairing code: [36253605617] + [1657186324.711108][10820:10825] CHIP:CTL: SetupQRCode: [MT:-24J0IRV01A7TB7E700] + disabled: true + + - label: "Precondition: Commission DUT to TH2 (Pairing)" + verification: | + Now send the below command for commissionin DUT to TH2 with Manual pairing code generated in TH1 using open commission window + + ./chip-tool pairing code 2 36253605617 --commissioner-name beta + + Verify the commissioning completed with success on TH2(chip-tool) from DUT + + [1657186359.584672][3509:3514] CHIP:CTL: Successfully finished commissioning step 'Cleanup' + [1657186359.584743][3509:3514] CHIP:TOO: Device commissioning completed with success + disabled: true + + - label: "Precondition: Commission DUT to TH3 (Open Commissioning Window)" + verification: | + Open a commissioning window On TH1(Chiptool)using below command + + ./chip-tool pairing open-commissioning-window 1 1 400 2000 3842 + + Verify the Successfully opened pairing window On TH1(Chiptool)e device + + [1701254594.851779][10096:10098] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_003C Command=0x0000_0000 Status=0x0 + [1701254594.851783][10096:10098] CHIP:CTL: Successfully opened pairing window on the device + [1701254594.851789][10096:10098] CHIP:CTL: Manual pairing code: [36545248276] + [1701254594.851795][10096:10098] CHIP:CTL: SetupQRCode: [MT:-24J0Q1212K4.08JP10] + disabled: true + + - label: "Precondition: Commission DUT to TH3 (Pairing)" + verification: | + send the below command for commissionin DUT to TH3 with Manual pairing code generated in TH1 using open commission window + + ./chip-tool pairing code 3 36545248276 --commissioner-name gamma + + Verify the commissioning completed with success on TH3(chip-tool) from DUT + + [1657186359.584672][3509:3514] CHIP:CTL: Successfully finished commissioning step 'Cleanup' + [1657186359.584743][3509:3514] CHIP:TOO: Device commissioning completed with success disabled: true - label: @@ -41,96 +94,138 @@ tests: verification: | ./chip-tool scenesmanagement remove-all-scenes 0x0000 1 1 - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0003 - CHIP:TOO: RemoveAllScenesResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 0 - CHIP:TOO: } + Verify the RemoveAllScenesResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1701173905.688536][36687:36689] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0003 + [1701173905.688553][36687:36689] CHIP:TOO: RemoveAllScenesResponse: { + [1701173905.688558][36687:36689] CHIP:TOO: status: 0 + [1701173905.688561][36687:36689] CHIP:TOO: groupID: 0 + [1701173905.688563][36687:36689] CHIP:TOO: } disabled: true - - label: "Step 1b: Repeat Step 1a with TH2 and TH3." + - label: "Step 1b: Repeat Step 1a with TH2." PICS: S.S.C03.Rsp verification: | ./chip-tool scenesmanagement remove-all-scenes 0x0000 2 1 --commissioner-name beta + + Verify the RemoveAllScenesResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1700826575.191275][15971:15973] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0003 + [1700826575.191321][15971:15973] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0003 + [1700826575.191938][15971:15973] CHIP:TOO: RemoveAllScenesResponse: { + [1700826575.191974][15971:15973] CHIP:TOO: status: 0 + [1700826575.191985][15971:15973] CHIP:TOO: groupID: 0 + [1700826575.191995][15971:15973] CHIP:TOO: } + disabled: true + + - label: "Step 1C: Repeat Step 1a with TH3." + PICS: S.S.C03.Rsp + verification: | ./chip-tool scenesmanagement remove-all-scenes 0x0000 3 1 --commissioner-name gamma + + Verify the RemoveAllScenesResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1700826595.190538][15975:15977] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0003 + [1700826595.190578][15975:15977] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0003 + [1700826595.190637][15975:15977] CHIP:TOO: RemoveAllScenesResponse: { + [1700826595.190652][15975:15977] CHIP:TOO: status: 0 + [1700826595.190661][15975:15977] CHIP:TOO: groupID: 0 + [1700826595.190669][15975:15977] CHIP:TOO: } disabled: true - label: "Step 2a: TH1 reads from the DUT the SceneTableSize attribute" verification: | ./chip-tool scenesmanagement read scene-table-size 1 1 - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Attribute 0x0000_0006 DataVersion: 2793536935 - CHIP:TOO: SceneTableSize: 16 + Verify the "SceneTableSize" attribute value is SceneTableSize(minimum=16) which is recorded into SceneTableSize on the TH (Chip-tool) and below is the sample log provided for the raspi platform: + + [1700826614.634340][15990:15992] CHIP:DMG: } + [1700826614.634390][15990:15992] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0006 DataVersion: 1908396086 + [1700826614.634399][15990:15992] CHIP:TOO: SceneTableSize: 16 disabled: true - label: "Step 2b: TH1 sends a subscription request action for FabricSceneInfo to the DUT." verification: | - ./chipt-tool interactive start - any subscribe-by-id 0x0062 0x0002 0 5 1 1 + Please use Interactive mode to Verify the subscription + Here the command to enter interactive mode:-- + ./chip-tool interactive start - CHIP:DMG: ReportDataMessage = - CHIP:DMG: { - CHIP:DMG: SubscriptionId = 0xce6a96bc, - CHIP:DMG: AttributeReportIBs = - CHIP:DMG: [ - CHIP:DMG: AttributeReportIB = - CHIP:DMG: { - CHIP:DMG: AttributeDataIB = - CHIP:DMG: { - CHIP:DMG: DataVersion = 0x92ecb46c, - CHIP:DMG: AttributePathIB = - CHIP:DMG: { - CHIP:DMG: Endpoint = 0x1, - CHIP:DMG: Cluster = 0x62, - CHIP:DMG: Attribute = 0x0000_0002, - CHIP:DMG: } - CHIP:DMG: - CHIP:DMG: Data = [ - CHIP:DMG: - CHIP:DMG: { - CHIP:DMG: 0x0 = 0, - CHIP:DMG: 0x1 = 0, - CHIP:DMG: 0x2 = 0, - CHIP:DMG: 0x3 = false, - CHIP:DMG: 0x4 = 7, - CHIP:DMG: 0xfe = 1, - CHIP:DMG: }, - CHIP:DMG: ], - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: ], - CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 11 - CHIP:DMG: } - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 2464986220 - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 0 - CHIP:TOO: CurrentScene: 0 - CHIP:TOO: CurrentGroup: 0 - CHIP:TOO: SceneValid: FALSE - CHIP:TOO: RemainingCapacity: 7 - CHIP:TOO: FabricIndex: 1 - CHIP:TOO: } + Set up the subscription between DUT and TH by sending the command mentioned below, and verify that the subscription is activated successfully + + scenesmanagement subscribe fabric-scene-info 100 200 1 1 + Verify the DUT sends a report data to TH1 for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into Remaining1stCapacity and is equals to (MaxRemainingCapacity) on the TH (Chip-tool) and below is the sample log provided for the raspi platform: + + [1701251118.633541][8779:8781] CHIP:DMG: ReportDataMessage = + [1701251118.633544][8779:8781] CHIP:DMG: { + [1701251118.633547][8779:8781] CHIP:DMG: SubscriptionId = 0x349c4fb0, + [1701251118.633550][8779:8781] CHIP:DMG: AttributeReportIBs = + [1701251118.633557][8779:8781] CHIP:DMG: [ + [1701251118.633560][8779:8781] CHIP:DMG: AttributeReportIB = + [1701251118.633567][8779:8781] CHIP:DMG: { + [1701251118.633570][8779:8781] CHIP:DMG: AttributeDataIB = + [1701251118.633574][8779:8781] CHIP:DMG: { + [1701251118.633577][8779:8781] CHIP:DMG: DataVersion = 0xe203cd66, + [1701251118.633581][8779:8781] CHIP:DMG: AttributePathIB = + [1701251118.633584][8779:8781] CHIP:DMG: { + [1701251118.633587][8779:8781] CHIP:DMG: Endpoint = 0x1, + [1701251118.633591][8779:8781] CHIP:DMG: Cluster = 0x62, + [1701251118.633594][8779:8781] CHIP:DMG: Attribute = 0x0000_0002, + [1701251118.633598][8779:8781] CHIP:DMG: } + [1701251118.633602][8779:8781] CHIP:DMG: + [1701251118.633606][8779:8781] CHIP:DMG: Data = [ + [1701251118.633610][8779:8781] CHIP:DMG: + [1701251118.633614][8779:8781] CHIP:DMG: { + [1701251118.633618][8779:8781] CHIP:DMG: 0x0 = 0, + [1701251118.633621][8779:8781] CHIP:DMG: 0x1 = 0, + [1701251118.633625][8779:8781] CHIP:DMG: 0x2 = 0, + [1701251118.633629][8779:8781] CHIP:DMG: 0x3 = false, + [1701251118.633633][8779:8781] CHIP:DMG: 0x4 = 7, + [1701251118.633637][8779:8781] CHIP:DMG: 0xfe = 1, + [1701251118.633640][8779:8781] CHIP:DMG: }, + [1701251118.633644][8779:8781] CHIP:DMG: ], + [1701251118.633646][8779:8781] CHIP:DMG: }, + [1701251118.633652][8779:8781] CHIP:DMG: + [1701251118.633655][8779:8781] CHIP:DMG: }, + [1701251118.633661][8779:8781] CHIP:DMG: + [1701251118.633663][8779:8781] CHIP:DMG: ], + [1701251118.633669][8779:8781] CHIP:DMG: + [1701251118.633672][8779:8781] CHIP:DMG: InteractionModelRevision = 11 + [1701251118.633675][8779:8781] CHIP:DMG: } + [1701251118.633729][8779:8781] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 3791900006 + [1701251118.633743][8779:8781] CHIP:TOO: FabricSceneInfo: 1 entries + [1701251118.633758][8779:8781] CHIP:TOO: [1]: { + [1701251118.633765][8779:8781] CHIP:TOO: SceneCount: 0 + [1701251118.633768][8779:8781] CHIP:TOO: CurrentScene: 0 + [1701251118.633770][8779:8781] CHIP:TOO: CurrentGroup: 0 + [1701251118.633773][8779:8781] CHIP:TOO: SceneValid: FALSE + [1701251118.633776][8779:8781] CHIP:TOO: RemainingCapacity: 7 + [1701251118.633779][8779:8781] CHIP:TOO: FabricIndex: 1 + [1701251118.633783][8779:8781] CHIP:TOO: } disabled: true - label: "Step 2c: Keep subscription session active for the remaining of the test" verification: | + Keep subscription session active for the remaining of the test + Confirm that the subscription session is active for the remainder of the test by the reception of Liveness checks: CHIP:EM: >>> [E:44665r S:45698 M:201545516] (S) Msg RX from 1:0000000000000001 [1042] --- Type 0001:05 (IM:ReportData) CHIP:EM: Handling via exchange: 44665r, Delegate: 0xaaaaea044808 CHIP:DMG: ReportDataMessage = CHIP:DMG: { - CHIP:DMG: SubscriptionId = 0xce6a96bc, - CHIP:DMG: InteractionModelRevision = 11 + CHIP:DMG: SubscriptionId = 0xce6a96bc, + CHIP:DMG: InteractionModelRevision = 11 CHIP:DMG: } CHIP:DMG: Refresh LivenessCheckTime for 9224 milliseconds with SubscriptionId = 0xce6a96bc Peer = 01:0000000000000001 disabled: true @@ -138,28 +233,123 @@ tests: - label: "Step 2d: Repeat Step 2b and 2c with TH2 and TH3" verification: | TH2: - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Attribute 0x0000_0007 DataVersion: 2793536968 - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 0 - CHIP:TOO: CurrentScene: 0 - CHIP:TOO: CurrentGroup: 0 - CHIP:TOO: SceneValid: FALSE - CHIP:TOO: RemainingCapacity: 7 - CHIP:TOO: FabricIndex: 2 - CHIP:TOO: } - - TH3: - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Attribute 0x0000_0007 DataVersion: 2793536968 - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 0 - CHIP:TOO: CurrentScene: 0 - CHIP:TOO: CurrentGroup: 0 - CHIP:TOO: SceneValid: FALSE - CHIP:TOO: RemainingCapacity: 7 - CHIP:TOO: FabricIndex: 3 - CHIP:TOO: } + + Please use Interactive mode to Verify the subscription of an event + Here the command to enter interactive mode:-- + ./chip-tool interactive start + + Set up the subscription between DUT and TH by sending the command mentioned below, and verify that the subscription is activated successfully + + scenesmanagement subscribe fabric-scene-info 100 200 2 1 --commissioner-name beta + + Verify the DUT sends a report data to TH2 for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into Remaining2ndCapacity and is equals to (MaxRemainingCapacity) on the TH2 (Chip-tool) and below is the sample log provided for the raspi platform: + + [1701242801.625064][7636:7638] CHIP:DMG: ReportDataMessage = + [1701242801.625076][7636:7638] CHIP:DMG: { + [1701242801.625089][7636:7638] CHIP:DMG: SubscriptionId = 0x9682625a, + [1701242801.625100][7636:7638] CHIP:DMG: AttributeReportIBs = + [1701242801.625126][7636:7638] CHIP:DMG: [ + [1701242801.625136][7636:7638] CHIP:DMG: AttributeReportIB = + [1701242801.625161][7636:7638] CHIP:DMG: { + [1701242801.625172][7636:7638] CHIP:DMG: AttributeDataIB = + [1701242801.625184][7636:7638] CHIP:DMG: { + [1701242801.625198][7636:7638] CHIP:DMG: DataVersion = 0x4daee67b, + [1701242801.625209][7636:7638] CHIP:DMG: AttributePathIB = + [1701242801.625223][7636:7638] CHIP:DMG: { + [1701242801.625237][7636:7638] CHIP:DMG: Endpoint = 0x1, + [1701242801.625250][7636:7638] CHIP:DMG: Cluster = 0x62, + [1701242801.625263][7636:7638] CHIP:DMG: Attribute = 0x0000_0002, + [1701242801.625275][7636:7638] CHIP:DMG: } + [1701242801.625291][7636:7638] CHIP:DMG: + [1701242801.625303][7636:7638] CHIP:DMG: Data = [ + [1701242801.625316][7636:7638] CHIP:DMG: + [1701242801.625330][7636:7638] CHIP:DMG: { + [1701242801.625346][7636:7638] CHIP:DMG: 0x0 = 0, + [1701242801.625361][7636:7638] CHIP:DMG: 0x1 = 0, + [1701242801.625375][7636:7638] CHIP:DMG: 0x2 = 0, + [1701242801.625390][7636:7638] CHIP:DMG: 0x3 = false, + [1701242801.625405][7636:7638] CHIP:DMG: 0x4 = 7, + [1701242801.625418][7636:7638] CHIP:DMG: 0xfe = 2, + [1701242801.625432][7636:7638] CHIP:DMG: }, + [1701242801.625444][7636:7638] CHIP:DMG: ], + [1701242801.625455][7636:7638] CHIP:DMG: }, + [1701242801.625477][7636:7638] CHIP:DMG: + [1701242801.625487][7636:7638] CHIP:DMG: }, + [1701242801.625509][7636:7638] CHIP:DMG: + [1701242801.625519][7636:7638] CHIP:DMG: ], + [1701242801.625541][7636:7638] CHIP:DMG: + [1701242801.625552][7636:7638] CHIP:DMG: InteractionModelRevision = 11 + [1701242801.625562][7636:7638] CHIP:DMG: } + [1701242801.625758][7636:7638] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 1303307899 + [1701242801.625808][7636:7638] CHIP:TOO: FabricSceneInfo: 1 entries + [1701242801.625852][7636:7638] CHIP:TOO: [1]: { + [1701242801.625874][7636:7638] CHIP:TOO: SceneCount: 0 + [1701242801.625885][7636:7638] CHIP:TOO: CurrentScene: 0 + [1701242801.625896][7636:7638] CHIP:TOO: CurrentGroup: 0 + [1701242801.625907][7636:7638] CHIP:TOO: SceneValid: FALSE + [1701242801.625919][7636:7638] CHIP:TOO: RemainingCapacity: 7 + [1701242801.625930][7636:7638] CHIP:TOO: FabricIndex: 2 + [1701242801.625941][7636:7638] CHIP:TOO: } + disabled: true + + - label: "Step 2e: Repeat Step 2b and 2c with TH3." + verification: | + Please use Interactive mode to Verify the subscription of an event + Here the command to enter interactive mode:-- + ./chip-tool interactive start + + Set up the subscription between DUT and TH by sending the command mentioned below, and verify that the subscription is activated successfully + + scenesmanagement subscribe fabric-scene-info 100 200 3 1 --commissioner-name gamma + + Verify the DUT sends a report data to TH3 for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into Remaining3ndCapacity and is equals to (MaxRemainingCapacity) on the TH3 (Chip-tool) and below is the sample log provided for the raspi platform: + + [1701242829.236595][7642:7644] CHIP:DMG: ReportDataMessage = + [1701242829.236616][7642:7644] CHIP:DMG: { + [1701242829.236629][7642:7644] CHIP:DMG: SubscriptionId = 0x31889fa9, + [1701242829.236640][7642:7644] CHIP:DMG: AttributeReportIBs = + [1701242829.236665][7642:7644] CHIP:DMG: [ + [1701242829.236675][7642:7644] CHIP:DMG: AttributeReportIB = + [1701242829.236702][7642:7644] CHIP:DMG: { + [1701242829.236712][7642:7644] CHIP:DMG: AttributeDataIB = + [1701242829.236724][7642:7644] CHIP:DMG: { + [1701242829.236738][7642:7644] CHIP:DMG: DataVersion = 0x4daee67b, + [1701242829.236750][7642:7644] CHIP:DMG: AttributePathIB = + [1701242829.236766][7642:7644] CHIP:DMG: { + [1701242829.236778][7642:7644] CHIP:DMG: Endpoint = 0x1, + [1701242829.236792][7642:7644] CHIP:DMG: Cluster = 0x62, + [1701242829.236807][7642:7644] CHIP:DMG: Attribute = 0x0000_0001, + [1701242829.236818][7642:7644] CHIP:DMG: } + [1701242829.236834][7642:7644] CHIP:DMG: + [1701242829.236847][7642:7644] CHIP:DMG: Data = [ + [1701242829.236861][7642:7644] CHIP:DMG: + [1701242829.236875][7642:7644] CHIP:DMG: { + [1701242829.236891][7642:7644] CHIP:DMG: 0x0 = 0, + [1701242829.236905][7642:7644] CHIP:DMG: 0x1 = 0, + [1701242829.236921][7642:7644] CHIP:DMG: 0x2 = 0, + [1701242829.236935][7642:7644] CHIP:DMG: 0x3 = false, + [1701242829.236952][7642:7644] CHIP:DMG: 0x4 = 7, + [1701242829.236966][7642:7644] CHIP:DMG: 0xfe = 3, + [1701242829.236979][7642:7644] CHIP:DMG: }, + [1701242829.236992][7642:7644] CHIP:DMG: ], + [1701242829.237003][7642:7644] CHIP:DMG: }, + [1701242829.237026][7642:7644] CHIP:DMG: + [1701242829.237036][7642:7644] CHIP:DMG: }, + [1701242829.237059][7642:7644] CHIP:DMG: + [1701242829.237069][7642:7644] CHIP:DMG: ], + [1701242829.237092][7642:7644] CHIP:DMG: + [1701242829.237102][7642:7644] CHIP:DMG: InteractionModelRevision = 11 + [1701242829.237112][7642:7644] CHIP:DMG: } + [1701242829.237312][7642:7644] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0001 DataVersion: 1303307899 + [1701242829.237369][7642:7644] CHIP:TOO: FabricSceneInfo: 1 entries + [1701242829.237411][7642:7644] CHIP:TOO: [1]: { + [1701242829.237433][7642:7644] CHIP:TOO: SceneCount: 0 + [1701242829.237443][7642:7644] CHIP:TOO: CurrentScene: 0 + [1701242829.237454][7642:7644] CHIP:TOO: CurrentGroup: 0 + [1701242829.237465][7642:7644] CHIP:TOO: SceneValid: FALSE + [1701242829.237477][7642:7644] CHIP:TOO: RemainingCapacity: 7 + [1701242829.237487][7642:7644] CHIP:TOO: FabricIndex: 3 + [1701242829.237498][7642:7644] CHIP:TOO: } disabled: true - label: @@ -168,14 +358,20 @@ tests: set to 20000 (20s) and no extension field sets." PICS: S.S.C00.Rsp verification: | - ./chip-tool scenesmanagement add-scene 0x0000 0x1 20000 scene1 [] 1 1 - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - CHIP:TOO: AddSceneResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 0 - CHIP:TOO: sceneID: 1 - CHIP:TOO: } + ./chip-tool scenesmanagement add-scene 0x0000 0x01 20000 scene1 [] 1 1 + + Verify the AddSceneResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 + SceneID field set to 0x01 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1700827169.206479][16026:16028] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1700827169.206492][16026:16028] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1700827169.206523][16026:16028] CHIP:TOO: AddSceneResponse: { + [1700827169.206537][16026:16028] CHIP:TOO: status: 0 + [1700827169.206548][16026:16028] CHIP:TOO: groupID: 0 + [1700827169.206558][16026:16028] CHIP:TOO: sceneID: 1 + [1700827169.206568][16026:16028] CHIP:TOO: } disabled: true - label: @@ -185,53 +381,56 @@ tests: FabricSceneInfo into Remaining1stCapacity; verify Remaining1stCapacity equals (MaxRemainingCapacity-1)." verification: | - Confirm that a report data message is received with the updated data: - CHIP:DMG: ReportDataMessage = - CHIP:DMG: { - CHIP:DMG: SubscriptionId = 0xce6a96bc, - CHIP:DMG: AttributeReportIBs = - CHIP:DMG: [ - CHIP:DMG: AttributeReportIB = - CHIP:DMG: { - CHIP:DMG: AttributeDataIB = - CHIP:DMG: { - CHIP:DMG: DataVersion = 0x92ecb46e, - CHIP:DMG: AttributePathIB = - CHIP:DMG: { - CHIP:DMG: Endpoint = 0x1, - CHIP:DMG: Cluster = 0x62, - CHIP:DMG: Attribute = 0x0000_0002, - CHIP:DMG: } - CHIP:DMG: - CHIP:DMG: Data = [ - CHIP:DMG: - CHIP:DMG: { - CHIP:DMG: 0x0 = 1, - CHIP:DMG: 0x1 = 0, - CHIP:DMG: 0x2 = 0, - CHIP:DMG: 0x3 = false, - CHIP:DMG: 0x4 = 6, - CHIP:DMG: 0xfe = 1, - CHIP:DMG: }, - CHIP:DMG: ], - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: ], - CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 11 - CHIP:DMG: } - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 2464986222 - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 0 - CHIP:TOO: CurrentScene: 0 - CHIP:TOO: CurrentGroup: 0 - CHIP:TOO: SceneValid: FALSE - CHIP:TOO: RemainingCapacity: 6 - CHIP:TOO: FabricIndex: 1 - CHIP:TOO: } + ./chipt-tool scenesmanagement subscribe fabric-scene-info 100 200 1 1 + + Verify the DUT sends a report data to TH1 for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into Remaining1stCapacity and is equals to (MaxRemainingCapacity-1) on the TH (Chip-tool) and below is the sample log provided for the raspi platform: + + [1701246692.659639][8121:8123] CHIP:DMG: ReportDataMessage = + [1701246692.659654][8121:8123] CHIP:DMG: { + [1701246692.659667][8121:8123] CHIP:DMG: SubscriptionId = 0xceee757a, + [1701246692.659678][8121:8123] CHIP:DMG: AttributeReportIBs = + [1701246692.659702][8121:8123] CHIP:DMG: [ + [1701246692.659711][8121:8123] CHIP:DMG: AttributeReportIB = + [1701246692.659737][8121:8123] CHIP:DMG: { + [1701246692.659748][8121:8123] CHIP:DMG: AttributeDataIB = + [1701246692.659758][8121:8123] CHIP:DMG: { + [1701246692.659772][8121:8123] CHIP:DMG: DataVersion = 0xa64c547f, + [1701246692.659783][8121:8123] CHIP:DMG: AttributePathIB = + [1701246692.659797][8121:8123] CHIP:DMG: { + [1701246692.659810][8121:8123] CHIP:DMG: Endpoint = 0x1, + [1701246692.659822][8121:8123] CHIP:DMG: Cluster = 0x62, + [1701246692.659836][8121:8123] CHIP:DMG: Attribute = 0x0000_0002, + [1701246692.659847][8121:8123] CHIP:DMG: } + [1701246692.659864][8121:8123] CHIP:DMG: + [1701246692.659876][8121:8123] CHIP:DMG: Data = [ + [1701246692.659889][8121:8123] CHIP:DMG: + [1701246692.659903][8121:8123] CHIP:DMG: { + [1701246692.659918][8121:8123] CHIP:DMG: 0x0 = 1, + [1701246692.659932][8121:8123] CHIP:DMG: 0x1 = 0, + [1701246692.659946][8121:8123] CHIP:DMG: 0x2 = 0, + [1701246692.659960][8121:8123] CHIP:DMG: 0x3 = false, + [1701246692.659974][8121:8123] CHIP:DMG: 0x4 = 6, + [1701246692.659987][8121:8123] CHIP:DMG: 0xfe = 1, + [1701246692.660001][8121:8123] CHIP:DMG: }, + [1701246692.660024][8121:8123] CHIP:DMG: ], + [1701246692.660035][8121:8123] CHIP:DMG: }, + [1701246692.660055][8121:8123] CHIP:DMG: + [1701246692.660065][8121:8123] CHIP:DMG: }, + [1701246692.660090][8121:8123] CHIP:DMG: + [1701246692.660100][8121:8123] CHIP:DMG: ], + [1701246692.660125][8121:8123] CHIP:DMG: + [1701246692.660135][8121:8123] CHIP:DMG: InteractionModelRevision = 11 + [1701246692.660145][8121:8123] CHIP:DMG: } + [1701246692.660363][8121:8123] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 2790020223 + [1701246692.660403][8121:8123] CHIP:TOO: FabricSceneInfo: 1 entries + [1701246692.660436][8121:8123] CHIP:TOO: [1]: { + [1701246692.660449][8121:8123] CHIP:TOO: SceneCount: 1 + [1701246692.660459][8121:8123] CHIP:TOO: CurrentScene: 0 + [1701246692.660471][8121:8123] CHIP:TOO: CurrentGroup: 0 + [1701246692.660482][8121:8123] CHIP:TOO: SceneValid: FALSE + [1701246692.660494][8121:8123] CHIP:TOO: RemainingCapacity: 6 + [1701246692.660505][8121:8123] CHIP:TOO: FabricIndex: 1 + [1701246692.660516][8121:8123] CHIP:TOO: } disabled: true - label: @@ -244,34 +443,137 @@ tests: verification: | ./chip-tool scenesmanagement add-scene 0x0000 0x02 20000 scene2 [] 1 1 - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - CHIP:TOO: AddSceneResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 0 - CHIP:TOO: sceneID: 2 - CHIP:TOO: } + Verify the AddSceneResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 + SceneID field set to 0x02 on the TH1(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1700827508.579671][16026:16028] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1700827508.579675][16026:16028] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1700827508.579684][16026:16028] CHIP:TOO: AddSceneResponse: { + [1700827508.579688][16026:16028] CHIP:TOO: status: 0 + [1700827508.579691][16026:16028] CHIP:TOO: groupID: 0 + [1700827508.579694][16026:16028] CHIP:TOO: sceneID: 2 + [1700827508.579697][16026:16028] CHIP:TOO: } + + + ./chip-tool scenesmanagement subscribe fabric-scene-info 100 200 1 1 + Verify the DUT sends a report data messages after the MinIntervalFloor time to TH1 for RemainingCapacity field in FabricSceneInfo for that fabric with updated valueon the TH1 (Chip-tool) and below is the sample log provided for the raspi platform: + [1701243677.717829][7642:7644] CHIP:DMG: ReportDataMessage = + [1701243677.717834][7642:7644] CHIP:DMG: { + [1701243677.717839][7642:7644] CHIP:DMG: SubscriptionId = 0xbbe8695b, + [1701243677.717844][7642:7644] CHIP:DMG: AttributeReportIBs = + [1701243677.717854][7642:7644] CHIP:DMG: [ + [1701243677.717858][7642:7644] CHIP:DMG: AttributeReportIB = + [1701243677.717866][7642:7644] CHIP:DMG: { + [1701243677.717870][7642:7644] CHIP:DMG: AttributeDataIB = + [1701243677.717875][7642:7644] CHIP:DMG: { + [1701243677.717881][7642:7644] CHIP:DMG: DataVersion = 0x4daee689, + [1701243677.717886][7642:7644] CHIP:DMG: AttributePathIB = + [1701243677.717893][7642:7644] CHIP:DMG: { + [1701243677.717899][7642:7644] CHIP:DMG: Endpoint = 0x1, + [1701243677.717906][7642:7644] CHIP:DMG: Cluster = 0x62, + [1701243677.717912][7642:7644] CHIP:DMG: Attribute = 0x0000_0002, + [1701243677.717917][7642:7644] CHIP:DMG: } + [1701243677.717924][7642:7644] CHIP:DMG: + [1701243677.717929][7642:7644] CHIP:DMG: Data = [ + [1701243677.717935][7642:7644] CHIP:DMG: + [1701243677.717941][7642:7644] CHIP:DMG: { + [1701243677.717948][7642:7644] CHIP:DMG: 0x0 = 2, + [1701243677.717954][7642:7644] CHIP:DMG: 0x1 = 0, + [1701243677.717960][7642:7644] CHIP:DMG: 0x2 = 0, + [1701243677.717967][7642:7644] CHIP:DMG: 0x3 = false, + [1701243677.717973][7642:7644] CHIP:DMG: 0x4 = 5, + [1701243677.717979][7642:7644] CHIP:DMG: 0xfe = 1, + [1701243677.717986][7642:7644] CHIP:DMG: }, + [1701243677.717991][7642:7644] CHIP:DMG: ], + [1701243677.717996][7642:7644] CHIP:DMG: }, + [1701243677.718006][7642:7644] CHIP:DMG: + [1701243677.718010][7642:7644] CHIP:DMG: }, + [1701243677.718020][7642:7644] CHIP:DMG: + [1701243677.718024][7642:7644] CHIP:DMG: ], + [1701243677.718034][7642:7644] CHIP:DMG: + [1701243677.718037][7642:7644] CHIP:DMG: InteractionModelRevision = 11 + [1701243677.718040][7642:7644] CHIP:DMG: } + [1701243677.718133][7642:7644] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 1303307913 + [1701243677.718146][7642:7644] CHIP:TOO: FabricSceneInfo: 1 entries + [1701243677.718154][7642:7644] CHIP:TOO: [1]: { + [1701243677.718157][7642:7644] CHIP:TOO: SceneCount: 2 + [1701243677.718160][7642:7644] CHIP:TOO: CurrentScene: 0 + [1701243677.718162][7642:7644] CHIP:TOO: CurrentGroup: 0 + [1701243677.718165][7642:7644] CHIP:TOO: SceneValid: FALSE + [1701243677.718168][7642:7644] CHIP:TOO: RemainingCapacity: 5 + [1701243677.718170][7642:7644] CHIP:TOO: FabricIndex: 1 + [1701243677.718173][7642:7644] CHIP:TOO: } . . . - ./chip-tool scenesmanagement add-scene 0x0000 0x07 20000 scene2 [] 1 1 - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - CHIP:TOO: AddSceneResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 0 - CHIP:TOO: sceneID: 7 - CHIP:TOO: } - - You should see the following data in the next report: - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 7 - CHIP:TOO: CurrentScene: 0 - CHIP:TOO: CurrentGroup: 0 - CHIP:TOO: SceneValid: FALSE - CHIP:TOO: RemainingCapacity: 0 - CHIP:TOO: FabricIndex: 1 - CHIP:TOO: } + ./chip-tool scenesmanagement add-scene 0x0000 0x07 20000 scene8 [] 1 1 + + Verify the AddSceneResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 + SceneID field set to 0x07 on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1700827941.415335][16068:16070] CHIP:DMG: }, + [1700827941.415392][16068:16070] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1700827941.415406][16068:16070] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1700827941.415462][16068:16070] CHIP:TOO: AddSceneResponse: { + [1700827941.415477][16068:16070] CHIP:TOO: status: 0 + [1700827941.415488][16068:16070] CHIP:TOO: groupID: 0 + [1700827941.415498][16068:16070] CHIP:TOO: sceneID: 7 + [1700827941.415508][16068:16070] CHIP:TOO: } + + ./chip-tool scenesmanagement subscribe fabric-scene-info 100 200 1 1 + + Verify the DUT sends a report data messages after the MinIntervalFloor time to TH1 for RemainingCapacity field in FabricSceneInfo for that fabric with updated valueon the TH1 (Chip-tool) and below is the sample log provided for the raspi platform: + + [1701244322.682421][7642:7644] CHIP:DMG: ReportDataMessage = + [1701244322.682435][7642:7644] CHIP:DMG: { + [1701244322.682447][7642:7644] CHIP:DMG: SubscriptionId = 0xbbe8695b, + [1701244322.682458][7642:7644] CHIP:DMG: AttributeReportIBs = + [1701244322.682484][7642:7644] CHIP:DMG: [ + [1701244322.682495][7642:7644] CHIP:DMG: AttributeReportIB = + [1701244322.682518][7642:7644] CHIP:DMG: { + [1701244322.682528][7642:7644] CHIP:DMG: AttributeDataIB = + [1701244322.682542][7642:7644] CHIP:DMG: { + [1701244322.682555][7642:7644] CHIP:DMG: DataVersion = 0x4daee697, + [1701244322.682566][7642:7644] CHIP:DMG: AttributePathIB = + [1701244322.682579][7642:7644] CHIP:DMG: { + [1701244322.682592][7642:7644] CHIP:DMG: Endpoint = 0x1, + [1701244322.682605][7642:7644] CHIP:DMG: Cluster = 0x62, + [1701244322.682619][7642:7644] CHIP:DMG: Attribute = 0x0000_0002, + [1701244322.682631][7642:7644] CHIP:DMG: } + [1701244322.682647][7642:7644] CHIP:DMG: + [1701244322.682659][7642:7644] CHIP:DMG: Data = [ + [1701244322.682672][7642:7644] CHIP:DMG: + [1701244322.682687][7642:7644] CHIP:DMG: { + [1701244322.682701][7642:7644] CHIP:DMG: 0x0 = 7, + [1701244322.682715][7642:7644] CHIP:DMG: 0x1 = 0, + [1701244322.682729][7642:7644] CHIP:DMG: 0x2 = 0, + [1701244322.682742][7642:7644] CHIP:DMG: 0x3 = false, + [1701244322.682756][7642:7644] CHIP:DMG: 0x4 = 0, + [1701244322.682770][7642:7644] CHIP:DMG: 0xfe = 1, + [1701244322.682784][7642:7644] CHIP:DMG: }, + [1701244322.682807][7642:7644] CHIP:DMG: ], + [1701244322.682818][7642:7644] CHIP:DMG: }, + [1701244322.682843][7642:7644] CHIP:DMG: + [1701244322.682853][7642:7644] CHIP:DMG: }, + [1701244322.682876][7642:7644] CHIP:DMG: + [1701244322.682887][7642:7644] CHIP:DMG: ], + [1701244322.682908][7642:7644] CHIP:DMG: + [1701244322.682919][7642:7644] CHIP:DMG: InteractionModelRevision = 11 + [1701244322.682930][7642:7644] CHIP:DMG: } + [1701244322.683149][7642:7644] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 1303307927 + [1701244322.683191][7642:7644] CHIP:TOO: FabricSceneInfo: 1 entries + [1701244322.683224][7642:7644] CHIP:TOO: [1]: { + [1701244322.683236][7642:7644] CHIP:TOO: SceneCount: 7 + [1701244322.683247][7642:7644] CHIP:TOO: CurrentScene: 0 + [1701244322.683258][7642:7644] CHIP:TOO: CurrentGroup: 0 + [1701244322.683269][7642:7644] CHIP:TOO: SceneValid: FALSE + [1701244322.683282][7642:7644] CHIP:TOO: RemainingCapacity: 0 + [1701244322.683293][7642:7644] CHIP:TOO: FabricIndex: 1 + [1701244322.683304][7642:7644] CHIP:TOO: } disabled: true - label: @@ -281,51 +583,366 @@ tests: field sets." PICS: S.S.C00.Rsp verification: | - ./chip-tool scenesmanagement add-scene 0x0000 0x08 20000 scene101 [] 1 1 - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - CHIP:TOO: AddSceneResponse: { - CHIP:TOO: status: 137 - CHIP:TOO: groupID: 0 - CHIP:TOO: sceneID: 8 - CHIP:TOO: } + ./chip-tool scenesmanagement add-scene 0x0000 0x08 20000 scene9 [] 1 1 + + Verify the AddSceneResponse with following fields: + Status is RESOURCE_EXHAUSTED(0x89) on the TH1(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1701244361.448569][7642:7644] CHIP:DMG: }, + [1701244361.448586][7642:7644] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1701244361.448590][7642:7644] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1701244361.448600][7642:7644] CHIP:TOO: AddSceneResponse: { + [1701244361.448604][7642:7644] CHIP:TOO: status: 137 + [1701244361.448608][7642:7644] CHIP:TOO: groupID: 0 + [1701244361.448611][7642:7644] CHIP:TOO: sceneID: 8 + [1701244361.448614][7642:7644] CHIP:TOO: } disabled: true - label: "Step 5a: Repeat Step 4a with TH2" PICS: S.S.C00.Rsp verification: | - ./chip-tool scenesmanagement add-scene 0x0000 0x2 20000 scene1 [] 2 1 --commissioner-name beta - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - CHIP:TOO: AddSceneResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 0 - CHIP:TOO: sceneID: 2 - CHIP:TOO: } + ./chip-tool scenesmanagement add-scene 0x0000 0x02 0x0014 scene1 [] 2 1 --commissioner-name beta + + Verify the AddSceneResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 + SceneID field set to 0x02 on the TH2(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1700828173.261569][16115:16117] CHIP:DMG: }, + [1700828173.261586][16115:16117] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1700828173.261600][16115:16117] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1700828173.261629][16115:16117] CHIP:TOO: AddSceneResponse: { + [1700828173.261633][16115:16117] CHIP:TOO: status: 0 + [1700828173.261636][16115:16117] CHIP:TOO: groupID: 0 + [1700828173.261638][16115:16117] CHIP:TOO: sceneID: 2 + [1700828173.261640][16115:16117] CHIP:TOO: } + + ./chip-tool scenesmanagement subscribe fabric-scene-info 100 200 2 1 --commissioner-name beta + + Verify the DUT sends a report data messages after the MinIntervalFloor time to TH2 for RemainingCapacity field in FabricSceneInfo for that fabric with updated value on the TH2 (Chip-tool) and below is the sample log provided for the raspi platform: + + [1701244532.841112][7824:7826] CHIP:DMG: ReportDataMessage = + [1701244532.841116][7824:7826] CHIP:DMG: { + [1701244532.841120][7824:7826] CHIP:DMG: SubscriptionId = 0xf6c52c20, + [1701244532.841123][7824:7826] CHIP:DMG: AttributeReportIBs = + [1701244532.841131][7824:7826] CHIP:DMG: [ + [1701244532.841134][7824:7826] CHIP:DMG: AttributeReportIB = + [1701244532.841141][7824:7826] CHIP:DMG: { + [1701244532.841144][7824:7826] CHIP:DMG: AttributeDataIB = + [1701244532.841148][7824:7826] CHIP:DMG: { + [1701244532.841152][7824:7826] CHIP:DMG: DataVersion = 0x4daee699, + [1701244532.841155][7824:7826] CHIP:DMG: AttributePathIB = + [1701244532.841159][7824:7826] CHIP:DMG: { + [1701244532.841163][7824:7826] CHIP:DMG: Endpoint = 0x1, + [1701244532.841167][7824:7826] CHIP:DMG: Cluster = 0x62, + [1701244532.841171][7824:7826] CHIP:DMG: Attribute = 0x0000_0002, + [1701244532.841175][7824:7826] CHIP:DMG: } + [1701244532.841179][7824:7826] CHIP:DMG: + [1701244532.841183][7824:7826] CHIP:DMG: Data = [ + [1701244532.841187][7824:7826] CHIP:DMG: + [1701244532.841192][7824:7826] CHIP:DMG: { + [1701244532.841196][7824:7826] CHIP:DMG: 0x0 = 1, + [1701244532.841200][7824:7826] CHIP:DMG: 0x1 = 0, + [1701244532.841204][7824:7826] CHIP:DMG: 0x2 = 0, + [1701244532.841209][7824:7826] CHIP:DMG: 0x3 = false, + [1701244532.841213][7824:7826] CHIP:DMG: 0x4 = 6, + [1701244532.841217][7824:7826] CHIP:DMG: 0xfe = 2, + [1701244532.841221][7824:7826] CHIP:DMG: }, + [1701244532.841225][7824:7826] CHIP:DMG: ], + [1701244532.841228][7824:7826] CHIP:DMG: }, + [1701244532.841237][7824:7826] CHIP:DMG: + [1701244532.841240][7824:7826] CHIP:DMG: }, + [1701244532.841248][7824:7826] CHIP:DMG: + [1701244532.841251][7824:7826] CHIP:DMG: ], + [1701244532.841257][7824:7826] CHIP:DMG: + [1701244532.841261][7824:7826] CHIP:DMG: InteractionModelRevision = 11 + [1701244532.841264][7824:7826] CHIP:DMG: } + [1701244532.841324][7824:7826] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 1303307929 + [1701244532.841340][7824:7826] CHIP:TOO: FabricSceneInfo: 1 entries + [1701244532.841351][7824:7826] CHIP:TOO: [1]: { + [1701244532.841355][7824:7826] CHIP:TOO: SceneCount: 1 + [1701244532.841358][7824:7826] CHIP:TOO: CurrentScene: 0 + [1701244532.841361][7824:7826] CHIP:TOO: CurrentGroup: 0 + [1701244532.841365][7824:7826] CHIP:TOO: SceneValid: FALSE + [1701244532.841368][7824:7826] CHIP:TOO: RemainingCapacity: 6 + [1701244532.841371][7824:7826] CHIP:TOO: FabricIndex: 2 + [1701244532.841375][7824:7826] CHIP:TOO: } + . + . + . + ./chip-tool scenesmanagement add-scene 0x0000 0x08 0x0014 scene7 [] 2 1 --commissioner-name beta + + Verify the AddSceneResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 + SceneID field set to 0x08 on the TH2(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1700829509.052437][16198:16200] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1700829509.052452][16198:16200] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1700829509.052485][16198:16200] CHIP:TOO: AddSceneResponse: { + [1700829509.052500][16198:16200] CHIP:TOO: status: 0 + [1700829509.052511][16198:16200] CHIP:TOO: groupID: 0 + [1700829509.052521][16198:16200] CHIP:TOO: sceneID: 8 + [1700829509.052532][16198:16200] CHIP:TOO: } + + ./chip-tool scenesmanagement subscribe fabric-scene-info 100 200 2 1 --commissioner-name beta + + Verify the DUT sends a report data messages after the MinIntervalFloor time to TH2 for RemainingCapacity field in FabricSceneInfo for that fabric with updated value(decreasing to 0) on the TH2 (Chip-tool) and below is the sample log provided for the raspi platform: + + [1701245132.869725][7824:7826] CHIP:DMG: ReportDataMessage = + [1701245132.869737][7824:7826] CHIP:DMG: { + [1701245132.869748][7824:7826] CHIP:DMG: SubscriptionId = 0xf6c52c20, + [1701245132.869756][7824:7826] CHIP:DMG: AttributeReportIBs = + [1701245132.869779][7824:7826] CHIP:DMG: [ + [1701245132.869790][7824:7826] CHIP:DMG: AttributeReportIB = + [1701245132.869814][7824:7826] CHIP:DMG: { + [1701245132.869825][7824:7826] CHIP:DMG: AttributeDataIB = + [1701245132.869835][7824:7826] CHIP:DMG: { + [1701245132.869854][7824:7826] CHIP:DMG: DataVersion = 0x4daee6a5, + [1701245132.869866][7824:7826] CHIP:DMG: AttributePathIB = + [1701245132.869879][7824:7826] CHIP:DMG: { + [1701245132.869893][7824:7826] CHIP:DMG: Endpoint = 0x1, + [1701245132.869906][7824:7826] CHIP:DMG: Cluster = 0x62, + [1701245132.869923][7824:7826] CHIP:DMG: Attribute = 0x0000_0002, + [1701245132.869935][7824:7826] CHIP:DMG: } + [1701245132.869951][7824:7826] CHIP:DMG: + [1701245132.869963][7824:7826] CHIP:DMG: Data = [ + [1701245132.869978][7824:7826] CHIP:DMG: + [1701245132.869995][7824:7826] CHIP:DMG: { + [1701245132.870010][7824:7826] CHIP:DMG: 0x0 = 7, + [1701245132.870026][7824:7826] CHIP:DMG: 0x1 = 0, + [1701245132.870038][7824:7826] CHIP:DMG: 0x2 = 0, + [1701245132.870052][7824:7826] CHIP:DMG: 0x3 = false, + [1701245132.870066][7824:7826] CHIP:DMG: 0x4 = 0, + [1701245132.870081][7824:7826] CHIP:DMG: 0xfe = 2, + [1701245132.870094][7824:7826] CHIP:DMG: }, + [1701245132.870106][7824:7826] CHIP:DMG: ], + [1701245132.870117][7824:7826] CHIP:DMG: }, + [1701245132.870140][7824:7826] CHIP:DMG: + [1701245132.870149][7824:7826] CHIP:DMG: }, + [1701245132.870171][7824:7826] CHIP:DMG: + [1701245132.870180][7824:7826] CHIP:DMG: ], + [1701245132.870205][7824:7826] CHIP:DMG: + [1701245132.870215][7824:7826] CHIP:DMG: InteractionModelRevision = 11 + [1701245132.870225][7824:7826] CHIP:DMG: } + [1701245132.870446][7824:7826] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 1303307941 + [1701245132.870486][7824:7826] CHIP:TOO: FabricSceneInfo: 1 entries + [1701245132.870517][7824:7826] CHIP:TOO: [1]: { + [1701245132.870530][7824:7826] CHIP:TOO: SceneCount: 7 + [1701245132.870541][7824:7826] CHIP:TOO: CurrentScene: 0 + [1701245132.870549][7824:7826] CHIP:TOO: CurrentGroup: 0 + [1701245132.870561][7824:7826] CHIP:TOO: SceneValid: FALSE + [1701245132.870573][7824:7826] CHIP:TOO: RemainingCapacity: 0 + [1701245132.870584][7824:7826] CHIP:TOO: FabricIndex: 2 + [1701245132.870594][7824:7826] CHIP:TOO: } + + ./chip-tool scenesmanagement subscribe fabric-scene-info 100 200 3 1 --commissioner-name gamma + + Verify that the DUT sends report data messages after the MinIntervalFloor time to TH3 for RemainingCapacity field in FabricSceneInfo for that fabric with updated value (decreasing to SceneTableSize - (2 * MaxRemainingCapacity)) on the TH2 (Chip-tool) and below is the sample log provided for the raspi platform: + + [1705916737.108024][21608:21610] CHIP:DMG: ReportDataMessage = + [1705916737.108028][21608:21610] CHIP:DMG: { + [1705916737.108031][21608:21610] CHIP:DMG: SubscriptionId = 0xbb681f96, + [1705916737.108034][21608:21610] CHIP:DMG: AttributeReportIBs = + [1705916737.108041][21608:21610] CHIP:DMG: [ + [1705916737.108043][21608:21610] CHIP:DMG: AttributeReportIB = + [1705916737.108050][21608:21610] CHIP:DMG: { + [1705916737.108053][21608:21610] CHIP:DMG: AttributeDataIB = + [1705916737.108056][21608:21610] CHIP:DMG: { + [1705916737.108060][21608:21610] CHIP:DMG: DataVersion = 0xb6069420, + [1705916737.108063][21608:21610] CHIP:DMG: AttributePathIB = + [1705916737.108066][21608:21610] CHIP:DMG: { + [1705916737.108070][21608:21610] CHIP:DMG: Endpoint = 0x1, + [1705916737.108073][21608:21610] CHIP:DMG: Cluster = 0x62, + [1705916737.108077][21608:21610] CHIP:DMG: Attribute = 0x0000_0002, + [1705916737.108080][21608:21610] CHIP:DMG: } + [1705916737.108084][21608:21610] CHIP:DMG: + [1705916737.108087][21608:21610] CHIP:DMG: Data = [ + [1705916737.108091][21608:21610] CHIP:DMG: + [1705916737.108094][21608:21610] CHIP:DMG: { + [1705916737.108098][21608:21610] CHIP:DMG: 0x0 = 0, + [1705916737.108102][21608:21610] CHIP:DMG: 0x1 = 0, + [1705916737.108106][21608:21610] CHIP:DMG: 0x2 = 0, + [1705916737.108109][21608:21610] CHIP:DMG: 0x3 = false, + [1705916737.108113][21608:21610] CHIP:DMG: 0x4 = 2, + [1705916737.108117][21608:21610] CHIP:DMG: 0xfe = 3, + [1705916737.108120][21608:21610] CHIP:DMG: }, + [1705916737.108123][21608:21610] CHIP:DMG: ], + [1705916737.108126][21608:21610] CHIP:DMG: }, + [1705916737.108132][21608:21610] CHIP:DMG: + [1705916737.108135][21608:21610] CHIP:DMG: }, + [1705916737.108141][21608:21610] CHIP:DMG: + [1705916737.108144][21608:21610] CHIP:DMG: ], + [1705916737.108150][21608:21610] CHIP:DMG: + [1705916737.108153][21608:21610] CHIP:DMG: InteractionModelRevision = 11 + [1705916737.108155][21608:21610] CHIP:DMG: } + [1705916737.108218][21608:21610] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 3053884448 + [1705916737.108239][21608:21610] CHIP:TOO: FabricSceneInfo: 1 entries + [1705916737.108259][21608:21610] CHIP:TOO: [1]: { + [1705916737.108266][21608:21610] CHIP:TOO: SceneCount: 0 + [1705916737.108268][21608:21610] CHIP:TOO: CurrentScene: 0 + [1705916737.108271][21608:21610] CHIP:TOO: CurrentGroup: 0 + [1705916737.108274][21608:21610] CHIP:TOO: SceneValid: FALSE + [1705916737.108277][21608:21610] CHIP:TOO: RemainingCapacity: 2 + [1705916737.108280][21608:21610] CHIP:TOO: FabricIndex: 3 + [1705916737.108283][21608:21610] CHIP:TOO: } disabled: true - label: "Step 5b: Repeat Step 4b with TH2" PICS: S.S.C00.Rsp verification: | - ./chip-tool scenesmanagement add-scene 0x0000 0x11 20000 scene201 [] 2 1 --commissioner-name beta - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - CHIP:TOO: AddSceneResponse: { - CHIP:TOO: status: 137 - CHIP:TOO: groupID: 0 - CHIP:TOO: sceneID: 17 - CHIP:TOO: } + ./chip-tool scenesmanagement add-scene 0x0000 0x09 0x0014 scene8 [] 2 1 --commissioner-name beta + + Verify the AddSceneResponse with following fields: + Status is RESOURCE_EXHAUSTED(0x89) on the TH2(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1701245223.543911][7824:7826] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1701245223.543925][7824:7826] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1701245223.543957][7824:7826] CHIP:TOO: AddSceneResponse: { + [1701245223.543971][7824:7826] CHIP:TOO: status: 137 + [1701245223.543983][7824:7826] CHIP:TOO: groupID: 0 + [1701245223.543994][7824:7826] CHIP:TOO: sceneID: 9 + [1701245223.544004][7824:7826] CHIP:TOO: } disabled: true - label: "Step 6a: Repeat Step 4a with TH3" PICS: S.S.C00.Rsp verification: | - ./chip-tool scenesmanagement add-scene 0x0000 0x3 20000 scene1 [] 2 1 --commissioner-name gamma - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - CHIP:TOO: AddSceneResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 0 - CHIP:TOO: sceneID: 3 - CHIP:TOO: } + ./chip-tool scenesmanagement add-scene 0x0000 0x02 0x0014 scene1 [] 3 1 --commissioner-name gamma + + Verify the AddSceneResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 + SceneID field set to 0x02 on the TH3(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1705915133.113882][21363:21365] CHIP:DMG: }, + [1705915133.113949][21363:21365] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1705915133.113982][21363:21365] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1705915133.114065][21363:21365] CHIP:TOO: AddSceneResponse: { + [1705915133.114081][21363:21365] CHIP:TOO: status: 0 + [1705915133.114092][21363:21365] CHIP:TOO: groupID: 0 + [1705915133.114103][21363:21365] CHIP:TOO: sceneID: 2 + [1705915133.114113][21363:21365] CHIP:TOO: } + + scenesmanagement subscribe fabric-scene-info 100 200 3 1 --commissioner-name gamma + + Verify that the DUT sends report data messages after the MinIntervalFloor time to TH3 for RemainingCapacity field in FabricSceneInfo for that fabric with updated value on the TH3(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1705915183.311738][21363:21365] CHIP:DMG: ReportDataMessage = + [1705915183.311752][21363:21365] CHIP:DMG: { + [1705915183.311765][21363:21365] CHIP:DMG: SubscriptionId = 0x62039a894, + [1705915183.311775][21363:21365] CHIP:DMG: AttributeReportIBs = + [1705915183.311801][21363:21365] CHIP:DMG: [ + [1705915183.311811][21363:21365] CHIP:DMG: AttributeReportIB = + [1705915183.311835][21363:21365] CHIP:DMG: { + [1705915183.311845][21363:21365] CHIP:DMG: AttributeDataIB = + [1705915183.311858][21363:21365] CHIP:DMG: { + [1705915183.311871][21363:21365] CHIP:DMG: DataVersion = 0x7e84d696, + [1705915183.311882][21363:21365] CHIP:DMG: AttributePathIB = + [1705915183.311896][21363:21365] CHIP:DMG: { + [1705915183.311909][21363:21365] CHIP:DMG: Endpoint = 0x1, + [1705915183.311923][21363:21365] CHIP:DMG: Cluster = 0x62, + [1705915183.311937][21363:21365] CHIP:DMG: Attribute = 0x0000_0002, + [1705915183.311948][21363:21365] CHIP:DMG: } + [1705915183.311964][21363:21365] CHIP:DMG: + [1705915183.311976][21363:21365] CHIP:DMG: Data = [ + [1705915183.311990][21363:21365] CHIP:DMG: + [1705915183.312003][21363:21365] CHIP:DMG: { + [1705915183.312018][21363:21365] CHIP:DMG: 0x0 = 1, + [1705915183.312033][21363:21365] CHIP:DMG: 0x1 = 0, + [1705915183.312047][21363:21365] CHIP:DMG: 0x2 = 0, + [1705915183.312072][21363:21365] CHIP:DMG: 0x3 = false, + [1705915183.312093][21363:21365] CHIP:DMG: 0x4 = 1, + [1705915183.312115][21363:21365] CHIP:DMG: 0xfe = 3, + [1705915183.312134][21363:21365] CHIP:DMG: }, + [1705915183.312154][21363:21365] CHIP:DMG: ], + [1705915183.312170][21363:21365] CHIP:DMG: }, + [1705915183.312197][21363:21365] CHIP:DMG: + [1705915183.312207][21363:21365] CHIP:DMG: }, + [1705915183.312228][21363:21365] CHIP:DMG: + [1705915183.312239][21363:21365] CHIP:DMG: ], + [1705915183.312263][21363:21365] CHIP:DMG: + [1705915183.312274][21363:21365] CHIP:DMG: InteractionModelRevision = 11 + [1705915183.312283][21363:21365] CHIP:DMG: } + [1705915183.312491][21363:21365] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 2122634902 + [1705915183.312553][21363:21365] CHIP:TOO: FabricSceneInfo: 1 entries + [1705915183.312599][21363:21365] CHIP:TOO: [1]: { + [1705915183.312613][21363:21365] CHIP:TOO: SceneCount: 1 + [1705915183.312623][21363:21365] CHIP:TOO: CurrentScene: 0 + [1705915183.312645][21363:21365] CHIP:TOO: CurrentGroup: 0 + [1705915183.312656][21363:21365] CHIP:TOO: SceneValid: FALSE + [1705915183.312669][21363:21365] CHIP:TOO: RemainingCapacity: 1 + [1705915183.312679][21363:21365] CHIP:TOO: FabricIndex: 3 + [1705915183.312690][21363:21365] CHIP:TOO: } + + + scenesmanagement add-scene 0x0000 0x03 0x0014 scene2 [] 3 1 --commissioner-name gamma + + Verify the AddSceneResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 + SceneID field set to 0x03 on the TH3(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1705915237.987013][21363:21365] CHIP:DMG: }, + [1705915237.987077][21363:21365] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1705915237.987093][21363:21365] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1705915237.987124][21363:21365] CHIP:TOO: AddSceneResponse: { + [1705915237.987140][21363:21365] CHIP:TOO: status: 0 + [1705915237.987150][21363:21365] CHIP:TOO: groupID: 0 + [1705915237.987161][21363:21365] CHIP:TOO: sceneID: 3 + [1705915237.987171][21363:21365] CHIP:TOO: } + + + Verify that the DUT sends report data messages after the MinIntervalFloor time to TH3 for RemainingCapacity field in FabricSceneInfo for that fabric with updated value((decreasing to 0)) on the TH3(Chip-tool) log and below is the sample log provided for the raspi platform: + + + [1705915281.585175][21387:21389] CHIP:DMG: ReportDataMessage = + [1705915281.585187][21387:21389] CHIP:DMG: { + [1705915281.585198][21387:21389] CHIP:DMG: SubscriptionId = 0x111160d4, + [1705915281.585206][21387:21389] CHIP:DMG: AttributeReportIBs = + [1705915281.585228][21387:21389] CHIP:DMG: [ + [1705915281.585236][21387:21389] CHIP:DMG: AttributeReportIB = + [1705915281.585263][21387:21389] CHIP:DMG: { + [1705915281.585273][21387:21389] CHIP:DMG: AttributeDataIB = + [1705915281.585285][21387:21389] CHIP:DMG: { + [1705915281.585299][21387:21389] CHIP:DMG: DataVersion = 0x7e84d698, + [1705915281.585310][21387:21389] CHIP:DMG: AttributePathIB = + [1705915281.585323][21387:21389] CHIP:DMG: { + [1705915281.585336][21387:21389] CHIP:DMG: Endpoint = 0x1, + [1705915281.585349][21387:21389] CHIP:DMG: Cluster = 0x62, + [1705915281.585362][21387:21389] CHIP:DMG: Attribute = 0x0000_0002, + [1705915281.585374][21387:21389] CHIP:DMG: } + [1705915281.585390][21387:21389] CHIP:DMG: + [1705915281.585402][21387:21389] CHIP:DMG: Data = [ + [1705915281.585415][21387:21389] CHIP:DMG: + [1705915281.585428][21387:21389] CHIP:DMG: { + [1705915281.585443][21387:21389] CHIP:DMG: 0x0 = 2, + [1705915281.585458][21387:21389] CHIP:DMG: 0x1 = 0, + [1705915281.585472][21387:21389] CHIP:DMG: 0x2 = 0, + [1705915281.585486][21387:21389] CHIP:DMG: 0x3 = false, + [1705915281.585500][21387:21389] CHIP:DMG: 0x4 = 0, + [1705915281.585513][21387:21389] CHIP:DMG: 0xfe = 3, + [1705915281.585527][21387:21389] CHIP:DMG: }, + [1705915281.585539][21387:21389] CHIP:DMG: ], + [1705915281.585550][21387:21389] CHIP:DMG: }, + [1705915281.585573][21387:21389] CHIP:DMG: + [1705915281.585583][21387:21389] CHIP:DMG: }, + [1705915281.585605][21387:21389] CHIP:DMG: + [1705915281.585615][21387:21389] CHIP:DMG: ], + [1705915281.585638][21387:21389] CHIP:DMG: + [1705915281.585648][21387:21389] CHIP:DMG: InteractionModelRevision = 11 + [1705915281.585657][21387:21389] CHIP:DMG: } + [1705915281.585866][21387:21389] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 2122634904 + [1705915281.585940][21387:21389] CHIP:TOO: FabricSceneInfo: 1 entries + [1705915281.586006][21387:21389] CHIP:TOO: [1]: { + [1705915281.586029][21387:21389] CHIP:TOO: SceneCount: 2 + [1705915281.586040][21387:21389] CHIP:TOO: CurrentScene: 0 + [1705915281.586051][21387:21389] CHIP:TOO: CurrentGroup: 0 + [1705915281.586061][21387:21389] CHIP:TOO: SceneValid: FALSE + [1705915281.586073][21387:21389] CHIP:TOO: RemainingCapacity: 0 + [1705915281.586084][21387:21389] CHIP:TOO: FabricIndex: 3 + [1705915281.586095][21387:21389] CHIP:TOO: } + disabled: true - label: @@ -334,14 +951,19 @@ tests: set to 20000 20s and no extension field sets." PICS: S.S.C00.Rsp verification: | - ./chip-tool scenesmanagement add-scene 0x0000 0x01 20000 scene301 [] 3 1 --commissioner-name gamma - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0000 - CHIP:TOO: AddSceneResponse: { - CHIP:TOO: status: 137 - CHIP:TOO: groupID: 0 - CHIP:TOO: sceneID: 1 - CHIP:TOO: } + ./chipt-tool scenesmanagement add-scene 0x0000 0x01 20000 scene [] 3 1 --commissioner-name gamma + + Verify the AddSceneResponse with following fields: + Status is RESOURCE_EXHAUSTED(0x89) on the TH3(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1705915365.772920][21387:21389] CHIP:DMG: }, + [1705915365.772985][21387:21389] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000 + [1705915365.773001][21387:21389] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000 + [1705915365.773063][21387:21389] CHIP:TOO: AddSceneResponse: { + [1705915365.773079][21387:21389] CHIP:TOO: status: 137 + [1705915365.773091][21387:21389] CHIP:TOO: groupID: 0 + [1705915365.773102][21387:21389] CHIP:TOO: sceneID: 1 + [1705915365.773112][21387:21389] CHIP:TOO: } disabled: true - label: @@ -349,31 +971,41 @@ tests: set to 0x0000, the SceneID field set to 0x01." PICS: S.S.C04.Rsp verification: | - ./chip-tool scenesmanagement store-scene 0x0000 0xFE 20000 sceneFE [] 1 1 - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0004 - CHIP:TOO: StoreSceneResponse: { - CHIP:TOO: status: 137 - CHIP:TOO: groupID: 0 - CHIP:TOO: sceneID: 0xFE - CHIP:TOO: } + ./chipt-tool scenesmanagement store-scene 0x0000 0x01 3 1 --commissioner-name gamma + + Verify the StoreSceneResponse with following fields: + Status is RESOURCE_EXHAUSTED(0x89) on the TH3(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1705915551.740537][21417:21419] CHIP:DMG: }, + [1705915551.740557][21417:21419] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0004 + [1705915551.740566][21417:21419] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0004 + [1705915551.740585][21417:21419] CHIP:TOO: StoreSceneResponse: { + [1705915551.740590][21417:21419] CHIP:TOO: status: 137 + [1705915551.740593][21417:21419] CHIP:TOO: groupID: 0 + [1705915551.740596][21417:21419] CHIP:TOO: sceneID: 1 + [1705915551.740598][21417:21419] CHIP:TOO: } disabled: true - label: - "TH sends a CopyScene command to DUT with the mode field set to 0x00, - the group identifier from field set to 0x0000, the scene identifier - from field set to 0x01, the group identifier to field set to 0x0000 - and the scene identifier to field set to 0xFE." + "Step 8: TH sends a CopyScene command to DUT with the mode field set + to 0x00, the group identifier from field set to 0x0000, the scene + identifier from field set to 0x01, the group identifier to field set + to 0x0000 and the scene identifier to field set to 0xFE." PICS: S.S.C40.Rsp verification: | - ./chip-tool scenesmanagement copy-scene 0 0x0000 0x01 0x4E20 sceneFE [] 1 1 - - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0040 - CHIP:TOO: CopySceneResponse: { - CHIP:TOO: status: 137 - CHIP:TOO: groupID: 0 - CHIP:TOO: sceneID: 0xFE - CHIP:TOO: } + ./chipt-tool scenesmanagement copy-scene 0x00 0x0000 0x02 0x0000 0x00 3 1 --commissioner-name gamma + + Verify the CopySceneResponse with following fields: + Status is RESOURCE_EXHAUSTED(0x89) on the TH(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1705915659.672801][21417:21419] CHIP:DMG: }, + [1705915659.672875][21417:21419] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0040 + [1705915659.672891][21417:21419] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0040 + [1705915659.672923][21417:21419] CHIP:TOO: CopySceneResponse: { + [1705915659.672937][21417:21419] CHIP:TOO: status: 133 + [1705915659.672950][21417:21419] CHIP:TOO: groupIdentifierFrom: 0 + [1705915659.672979][21417:21419] CHIP:TOO: sceneIdentifierFrom: 2 + [1705915659.672991][21417:21419] CHIP:TOO: } disabled: true - label: @@ -381,13 +1013,18 @@ tests: field set to 0x0000." PICS: S.S.C03.Rsp verification: | - ./chip-tool scenesmanagement remove-all-scenes 0x0000 1 1 + ./chipt-tool scenesmanagement remove-all-scenes 0x0000 1 1 - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0003 - CHIP:TOO: RemoveAllScenesResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 0 - CHIP:TOO: } + Verify the RemoveAllScenesResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 on TH1(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1700829746.586347][16198:16200] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0003 + [1700829746.586351][16198:16200] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0003 + [1700829746.586362][16198:16200] CHIP:TOO: RemoveAllScenesResponse: { + [1700829746.586366][16198:16200] CHIP:TOO: status: 0 + [1700829746.586368][16198:16200] CHIP:TOO: groupID: 0 + [1700829746.586370][16198:16200] CHIP:TOO: } disabled: true - label: "Step 9b: Verify that the DUT sends a report data to TH1 for @@ -401,11 +1038,58 @@ tests: should send 'empty' report data since there is no update for this attribute for TH2)." verification: | - CHIP:DMG: ReportDataMessage = - CHIP:DMG: { - CHIP:DMG: SubscriptionId = 0xa9f0f186, - CHIP:DMG: InteractionModelRevision = 1 - CHIP:DMG: } + ./chipt-tool scenesmanagement subscribe fabric-scene-info 100 200 1 1 + + Verify that the DUT sends a report data to TH1 for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry the reported in FabricSceneInfo into Remaining1stCapacity; verify Remaining1stCapacity equals (MaxRemainingCapacity) on TH1(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1707984148.067226][18155:18157] CHIP:DMG: ReportDataMessage = + [1707984148.067240][18155:18157] CHIP:DMG: { + [1707984148.067250][18155:18157] CHIP:DMG: SubscriptionId = 0x53cf322d, + [1707984148.067258][18155:18157] CHIP:DMG: AttributeReportIBs = + [1707984148.067280][18155:18157] CHIP:DMG: [ + [1707984148.067295][18155:18157] CHIP:DMG: AttributeReportIB = + [1707984148.067320][18155:18157] CHIP:DMG: { + [1707984148.067331][18155:18157] CHIP:DMG: AttributeDataIB = + [1707984148.067343][18155:18157] CHIP:DMG: { + [1707984148.067355][18155:18157] CHIP:DMG: DataVersion = 0xc9875f20, + [1707984148.067367][18155:18157] CHIP:DMG: AttributePathIB = + [1707984148.067381][18155:18157] CHIP:DMG: { + [1707984148.067397][18155:18157] CHIP:DMG: Endpoint = 0x1, + [1707984148.067411][18155:18157] CHIP:DMG: Cluster = 0x62, + [1707984148.067431][18155:18157] CHIP:DMG: Attribute = 0x0000_0002, + [1707984148.067443][18155:18157] CHIP:DMG: } + [1707984148.067462][18155:18157] CHIP:DMG: + [1707984148.067474][18155:18157] CHIP:DMG: Data = [ + [1707984148.067488][18155:18157] CHIP:DMG: + [1707984148.067502][18155:18157] CHIP:DMG: { + [1707984148.067516][18155:18157] CHIP:DMG: 0x0 = 0, + [1707984148.067531][18155:18157] CHIP:DMG: 0x1 = 0, + [1707984148.067545][18155:18157] CHIP:DMG: 0x2 = 0, + [1707984148.067561][18155:18157] CHIP:DMG: 0x3 = false, + [1707984148.067575][18155:18157] CHIP:DMG: 0x4 = 7, + [1707984148.067589][18155:18157] CHIP:DMG: 0xfe = 1, + [1707984148.067603][18155:18157] CHIP:DMG: }, + [1707984148.067618][18155:18157] CHIP:DMG: ], + [1707984148.067629][18155:18157] CHIP:DMG: }, + [1707984148.067654][18155:18157] CHIP:DMG: + [1707984148.067664][18155:18157] CHIP:DMG: }, + [1707984148.067687][18155:18157] CHIP:DMG: + [1707984148.067696][18155:18157] CHIP:DMG: ], + [1707984148.067722][18155:18157] CHIP:DMG: + [1707984148.067733][18155:18157] CHIP:DMG: InteractionModelRevision = 11 + [1707984148.067744][18155:18157] CHIP:DMG: } + [1707984148.067925][18155:18157] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 3381092128 + [1707984148.067967][18155:18157] CHIP:TOO: FabricSceneInfo: 1 entries + [1707984148.067999][18155:18157] CHIP:TOO: [1]: { + [1707984148.068011][18155:18157] CHIP:TOO: SceneCount: 0 + [1707984148.068023][18155:18157] CHIP:TOO: CurrentScene: 0 + [1707984148.068033][18155:18157] CHIP:TOO: CurrentGroup: 0 + [1707984148.068045][18155:18157] CHIP:TOO: SceneValid: FALSE + [1707984148.068057][18155:18157] CHIP:TOO: RemainingCapacity: 7 + [1707984148.068068][18155:18157] CHIP:TOO: FabricIndex: 1 + [1707984148.068079][18155:18157] CHIP:TOO: } + + Verify that the DUT does not send report data to TH2 for FabricSceneInfo after the MinIntervalFloor time with updated value (it should send 'empty' report data since there is no update for this attribute for TH2). disabled: true - label: @@ -413,67 +1097,76 @@ tests: field set to 0x0000." PICS: S.S.C03.Rsp verification: | - ./chip-tool scenesmanagement remove-all-scenes 0x0000 2 1 --commissioner-name beta + ./chipt-tool scenesmanagement remove-all-scenes 0x0000 2 1 --commissioner-name beta - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0005 Command 0x0000_0003 - CHIP:TOO: RemoveAllScenesResponse: { - CHIP:TOO: status: 0 - CHIP:TOO: groupID: 0 - CHIP:TOO: } + Verify the RemoveAllScenesResponse with following fields: + Status is SUCCESS + Group ID is 0x0000 on TH2(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1705915798.595482][21433:21435] CHIP:DMG: }, + [1705915798.595500][21433:21435] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0003 + [1705915798.595509][21433:21435] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0003 + [1705915798.595529][21433:21435] CHIP:TOO: RemoveAllScenesResponse: { + [1705915798.595534][21433:21435] CHIP:TOO: status: 0 + [1705915798.595537][21433:21435] CHIP:TOO: groupID: 0 + [1705915798.595540][21433:21435] CHIP:TOO: } disabled: true - label: - Verify that the DUT sends a report data to TH2 for FabricSceneInfo - after the MinIntervalFloor time; store the RemainingCapacity field - from this fabric’s entry reported in FabricSceneInfo into - Remaining2ndCapacity; verify Remaining2ndCapacity equals - (MaxRemainingCapacity). + "Step 10b: Verify that the DUT sends a report data to TH2 for + FabricSceneInfo after the MinIntervalFloor time; store the + RemainingCapacity field from this fabric’s entry reported in + FabricSceneInfo into Remaining2ndCapacity; verify Remaining2ndCapacity + equals (MaxRemainingCapacity)." verification: | - CHIP:DMG: ReportDataMessage = - CHIP:DMG: { - CHIP:DMG: SubscriptionId = 0x7049d607, - CHIP:DMG: AttributeReportIBs = - CHIP:DMG: [ - CHIP:DMG: AttributeReportIB = - CHIP:DMG: { - CHIP:DMG: AttributeDataIB = - CHIP:DMG: { - CHIP:DMG: DataVersion = 0x92ecb45d, - CHIP:DMG: AttributePathIB = - CHIP:DMG: { - CHIP:DMG: Endpoint = 0x1, - CHIP:DMG: Cluster = 0x62, - CHIP:DMG: Attribute = 0x0000_0002, - CHIP:DMG: } - CHIP:DMG: - CHIP:DMG: Data = [ - CHIP:DMG: - CHIP:DMG: { - CHIP:DMG: 0x0 = 4, - CHIP:DMG: 0x1 = 4, - CHIP:DMG: 0x2 = 0, - CHIP:DMG: 0x3 = false, - CHIP:DMG: 0x4 = 3, - CHIP:DMG: 0xfe = 1, - CHIP:DMG: }, - CHIP:DMG: ], - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: }, - CHIP:DMG: - CHIP:DMG: ], - CHIP:DMG: - CHIP:DMG: InteractionModelRevision = 11 - CHIP:DMG: } - CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 2464986205 - CHIP:TOO: FabricSceneInfo: 1 entries - CHIP:TOO: [1]: { - CHIP:TOO: SceneCount: 4 - CHIP:TOO: CurrentScene: 4 - CHIP:TOO: CurrentGroup: 0 - CHIP:TOO: SceneValid: FALSE - CHIP:TOO: RemainingCapacity: 7 - CHIP:TOO: FabricIndex: 1 - CHIP:TOO: } - CHIP:DMG: Refresh LivenessCheckTime for 9224 milliseconds with SubscriptionId = 0x7049d607 Peer = 01:0000000000000001 + ./chip-tool scenesmanagement subscribe fabric-scene-info 100 200 2 1 --commissioner-name beta + + Verify that the DUT sends a report data to TH2 for FabricSceneInfo after the MinIntervalFloor time; store the RemainingCapacity field from this fabric’s entry reported in FabricSceneInfo into Remaining2ndCapacity; verify Remaining2ndCapacity equals (MaxRemainingCapacity) on TH2(Chip-tool) log and below is the sample log provided for the raspi platform: + + [1705915866.717469][21433:21435] CHIP:DMG: } + [1705915866.717543][21433:21435] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Attribute 0x0000_0002 DataVersion: 2122634913 + [1705915866.717578][21433:21435] CHIP:TOO: FabricSceneInfo: 1 entries + [1705915866.717600][21433:21435] CHIP:TOO: [1]: { + [1705915866.717607][21433:21435] CHIP:TOO: SceneCount: 0 + [1705915866.717613][21433:21435] CHIP:TOO: CurrentScene: 0 + [1705915866.717619][21433:21435] CHIP:TOO: CurrentGroup: 0 + [1705915866.717624][21433:21435] CHIP:TOO: SceneValid: FALSE + [1705915866.717630][21433:21435] CHIP:TOO: RemainingCapacity: 7 + [1705915866.717635][21433:21435] CHIP:TOO: FabricIndex: 2 + [1705915866.717640][21433:21435] CHIP:TOO: } + + disabled: true + + - label: + "Step 11a: TH1 removes the TH2 fabric by sending the RemoveFabric + command to the DUT with the FabricIndex set to th2FabricIndex" + verification: | + ./chip-tool operationalcredentials remove-fabric th2FabricIndex 1 0 + + On TH1(chip-tool) verify the success with the nocresponse with statuscode is success(0) + + [1784416866.004187][21433:21435] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_003E Command=0x0000_0008 + [1784416866.004214][21433:21435] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_003E Command 0x0000_0008 + [1784416866.004236][21433:21435] CHIP:TOO: NOCResponse: { + [1784416866.004250][21433:21435] CHIP:TOO: statusCode: 0 + [1784416866.004255][21433:21435] CHIP:TOO: fabricIndex: th2FabricIndex + [1784416866.004259][21433:21435] CHIP:TOO: } + [1784416866.004270][21433:21435] CHIP:DMG: ICR moving to [AwaitingDe] + disabled: true + + - label: + "Step 11b: TH1 removes the TH3 fabric by sending the RemoveFabric + command to the DUT with the FabricIndex set to th3FabricIndex" + verification: | + ./chip-tool operationalcredentials remove-fabric th3FabricIndex 1 0 + + On TH1(chip-tool) verify the success with the nocresponse with statuscode is success(0) + + [1784416866.004187][21433:21435] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_003E Command=0x0000_0008 + [1784416866.004214][21433:21435] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_003E Command 0x0000_0008 + [1784416866.004236][21433:21435] CHIP:TOO: NOCResponse: { + [1784416866.004250][21433:21435] CHIP:TOO: statusCode: 0 + [1784416866.004255][21433:21435] CHIP:TOO: fabricIndex: th3FabricIndex + [1784416866.004259][21433:21435] CHIP:TOO: } + [1784416866.004270][21433:21435] CHIP:DMG: ICR moving to [AwaitingDe] disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_S_3_1.yaml b/src/app/tests/suites/certification/Test_TC_S_3_1.yaml index 9fd90636871873..66912006363345 100644 --- a/src/app/tests/suites/certification/Test_TC_S_3_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_S_3_1.yaml @@ -29,66 +29,235 @@ tests: For DUT as client test cases, Chip-tool command used below are an example to verify the functionality. For certification test, we expect DUT should have a capability or way to run the equivalent command. disabled: true - - label: "Step 0:" + - label: "Step 0a: Precondition 1" verification: | - "Step 0: Preparation: - TH as server exposes a Scenes Management server cluster on Endpoint: EndpointID, supporting all possible commands and corresponding attributes. - Commission DUT to TH disabled: true + - label: + "Step 0b: Precondition 2: TH sends KeySetWrite command in the + GroupKeyManagement cluster to DUT using a key that is pre-installed on + the TH. GroupKeySet fields are as follows: * GroupKeySetID: 0x01a1 * + GroupKeySecurityPolicy: TrustFirst (0) * EpochKey0: + a0a1a2a3a4a5a6a7a8a9aaabacadaeaf * EpochStartTime0: 1110000 * + EpochKey1: b0b1b2b3b4b5b6b7b8b9babbbcbdbebf * EpochStartTime1: 1110001 + * EpochKey2: c0c1c2c3c4c5c6c7c8c9cacbcccdcecf * EpochStartTime2: + 1110002" + verification: | + Please execute the below commands before starting the test case : + + ./chip-tool groupkeymanagement key-set-write '{"groupKeySetID": "0x01a1","groupKeySecurityPolicy": 0, "epochKey0":"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf","epochStartTime0": 1110000,"epochKey1":"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf", "epochStartTime1": 1110001,"epochKey2":"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf", "epochStartTime2": 1110002 }' 1 0 + + Verify the KeySetWrite command On TH (all-Clusters-app) log and below is the sample log provided for the raspi platform: + + [1706722808.568204][5404:5404] CHIP:DMG: InvokeRequestMessage = + [1706722808.568218][5404:5404] CHIP:DMG: { + [1706722808.568225][5404:5404] CHIP:DMG: suppressResponse = false, + [1706722808.568237][5404:5404] CHIP:DMG: timedRequest = false, + [1706722808.568247][5404:5404] CHIP:DMG: InvokeRequests = + [1706722808.568272][5404:5404] CHIP:DMG: [ + [1706722808.568281][5404:5404] CHIP:DMG: CommandDataIB = + [1706722808.568290][5404:5404] CHIP:DMG: { + [1706722808.568298][5404:5404] CHIP:DMG: CommandPathIB = + [1706722808.568315][5404:5404] CHIP:DMG: { + [1706722808.568328][5404:5404] CHIP:DMG: EndpointId = 0x0, + [1706722808.568341][5404:5404] CHIP:DMG: ClusterId = 0x3f, + [1706722808.568356][5404:5404] CHIP:DMG: CommandId = 0x0, + [1706722808.568366][5404:5404] CHIP:DMG: }, + [1706722808.568381][5404:5404] CHIP:DMG: + [1706722808.568391][5404:5404] CHIP:DMG: CommandFields = + [1706722808.568403][5404:5404] CHIP:DMG: { + [1706722808.568414][5404:5404] CHIP:DMG: 0x0 = + [1706722808.568426][5404:5404] CHIP:DMG: { + [1706722808.568439][5404:5404] CHIP:DMG: 0x0 = 417, + [1706722808.568453][5404:5404] CHIP:DMG: 0x1 = 0, + [1706722808.568465][5404:5404] CHIP:DMG: 0x2 = [ + [1706722808.568482][5404:5404] CHIP:DMG: 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + [1706722808.568498][5404:5404] CHIP:DMG: ] (16 bytes) + [1706722808.568511][5404:5404] CHIP:DMG: 0x3 = 1110000, + [1706722808.568523][5404:5404] CHIP:DMG: 0x4 = [ + [1706722808.568539][5404:5404] CHIP:DMG: 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + [1706722808.568553][5404:5404] CHIP:DMG: ] (16 bytes) + [1706722808.568578][5404:5404] CHIP:DMG: 0x5 = 1110001, + [1706722808.568594][5404:5404] CHIP:DMG: 0x6 = [ + [1706722808.568610][5404:5404] CHIP:DMG: 0xc2, 0xc1, 0xc2, 0xc3, 0cd4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + [1706722808.568623][5404:5404] CHIP:DMG: ] (16 bytes) + [1706722808.568633][5404:5404] CHIP:DMG: 0x7 = 1110002, + [1706722808.568645][5404:5404] CHIP:DMG: }, + [1706722808.568661][5404:5404] CHIP:DMG: }, + [1706722808.568671][5404:5404] CHIP:DMG: }, + [1706722808.568695][5404:5404] CHIP:DMG: + [1706722808.568704][5404:5404] CHIP:DMG: ], + [1706722808.568729][5404:5404] CHIP:DMG: + [1706722808.568739][5404:5404] CHIP:DMG: InteractionModelRevision = 11 + [1706722808.568747][5404:5404] CHIP:DMG: }, + disabled: true + + - label: + "Step 0c: Precondition 3: TH binds GroupIds 0x0001 and 0x0002 with + GroupKeySetID 0x01a1 in the GroupKeyMap attribute list on + GroupKeyManagement cluster by writing the GroupKeyMap attribute with + two entries as follows: * List item 1: - FabricIndex: 1 - GroupId: + 0x0001 - GroupKeySetId: 0x01a1" + verification: | + Please execute the below commands before starting the test case : + + ./chip-tool groupkeymanagement write group-key-map '[{"groupId": "0x0001", "groupKeySetID": "0x01a1", "fabricIndex": 1} ]' 1 0 + + Verify the GroupKeyMap attribute On TH (all-Clusters-app) log and below is the sample log provided for the raspi platform: + + [1706722844.841613][5404:5404] CHIP:DMG: WriteRequestMessage = + [1706722844.841616][5404:5404] CHIP:DMG: { + [1706722844.841619][5404:5404] CHIP:DMG: suppressResponse = false, + [1706722844.841621][5404:5404] CHIP:DMG: timedRequest = false, + [1706722844.841625][5404:5404] CHIP:DMG: AttributeDataIBs = + [1706722844.841629][5404:5404] CHIP:DMG: [ + [1706722844.841632][5404:5404] CHIP:DMG: AttributeDataIB = + [1706722844.841636][5404:5404] CHIP:DMG: { + [1706722844.841639][5404:5404] CHIP:DMG: AttributePathIB = + [1706722844.841643][5404:5404] CHIP:DMG: { + [1706722844.841646][5404:5404] CHIP:DMG: Endpoint = 0x0, + [1706722844.841649][5404:5404] CHIP:DMG: Cluster = 0x3f, + [1706722844.841652][5404:5404] CHIP:DMG: Attribute = 0x0000_0000, + [1706722844.841655][5404:5404] CHIP:DMG: } + [1706722844.841659][5404:5404] CHIP:DMG: + [1706722844.841662][5404:5404] CHIP:DMG: Data = [ + [1706722844.841665][5404:5404] CHIP:DMG: + [1706722844.841668][5404:5404] CHIP:DMG: ], + [1706722844.841670][5404:5404] CHIP:DMG: }, + [1706722844.841677][5404:5404] CHIP:DMG: + [1706722844.841680][5404:5404] CHIP:DMG: AttributeDataIB = + [1706722844.841682][5404:5404] CHIP:DMG: { + [1706722844.841685][5404:5404] CHIP:DMG: AttributePathIB = + [1706722844.841687][5404:5404] CHIP:DMG: { + [1706722844.841690][5404:5404] CHIP:DMG: Endpoint = 0x0, + [1706722844.841693][5404:5404] CHIP:DMG: Cluster = 0x3f, + [1706722844.841696][5404:5404] CHIP:DMG: Attribute = 0x0000_0000, + [1706722844.841699][5404:5404] CHIP:DMG: ListIndex = Null, + [1706722844.841702][5404:5404] CHIP:DMG: } + [1706722844.841706][5404:5404] CHIP:DMG: + [1706722844.841708][5404:5404] CHIP:DMG: Data = + [1706722844.841711][5404:5404] CHIP:DMG: { + [1706722844.841715][5404:5404] CHIP:DMG: 0x1 = 1, + [1706722844.841718][5404:5404] CHIP:DMG: 0x2 = 417, + [1706722844.841721][5404:5404] CHIP:DMG: }, + [1706722844.841723][5404:5404] CHIP:DMG: }, + [1706722844.841727][5404:5404] CHIP:DMG: + [1706722844.841730][5404:5404] CHIP:DMG: ], + [1706722844.841736][5404:5404] CHIP:DMG: + [1706722844.841738][5404:5404] CHIP:DMG: moreChunkedMessages = false, + [1706722844.841741][5404:5404] CHIP:DMG: InteractionModelRevision = 11 + [1706722844.841743][5404:5404] CHIP:DMG: }, + disabled: true + + - label: + "Step 0d: Precondition 4: TH sends a RemoveAllGroups command to DUT." + verification: | + Please execute the below commands before starting the test case : + + ./chip-tool groups remove-all-groups 1 1 + + Verify DUT responds with SUCCESS status response on the TH(Chip-tool) Log and below is the sample log provided for the raspi platform: + + [1653485455.344097][11508:11513] CHIP:DMG: StatusIB = + [1653485455.344141][11508:11513] CHIP:DMG: { + [1653485455.344190][11508:11513] CHIP:DMG: status = 0x00 (SUCCESS), + [1653485455.344236][11508:11513] CHIP:DMG: }, + disabled: true + + - label: + "Step 0e: Precondition 5: TH sends a AddGroup command to DUT with the + GroupID field set to G1." + verification: | + Please execute the below commands before starting the test case : + + ./chip-tool groups add-group 0x01 Gp1 1 1 + + Verify the AddGroup Command on TH (all-Clusters-app) log and below is the sample log provided for the raspi platform: + + [1706722872.295182][5404:5404] CHIP:DMG: InvokeRequestMessage = + [1706722872.295185][5404:5404] CHIP:DMG: { + [1706722872.295188][5404:5404] CHIP:DMG: suppressResponse = false, + [1706722872.295191][5404:5404] CHIP:DMG: timedRequest = false, + [1706722872.295194][5404:5404] CHIP:DMG: InvokeRequests = + [1706722872.295199][5404:5404] CHIP:DMG: [ + [1706722872.295201][5404:5404] CHIP:DMG: CommandDataIB = + [1706722872.295205][5404:5404] CHIP:DMG: { + [1706722872.295207][5404:5404] CHIP:DMG: CommandPathIB = + [1706722872.295211][5404:5404] CHIP:DMG: { + [1706722872.295214][5404:5404] CHIP:DMG: EndpointId = 0x1, + [1706722872.295217][5404:5404] CHIP:DMG: ClusterId = 0x4, + [1706722872.295220][5404:5404] CHIP:DMG: CommandId = 0x0, + [1706722872.295223][5404:5404] CHIP:DMG: }, + [1706722872.295226][5404:5404] CHIP:DMG: + [1706722872.295229][5404:5404] CHIP:DMG: CommandFields = + [1706722872.295233][5404:5404] CHIP:DMG: { + [1706722872.295236][5404:5404] CHIP:DMG: 0x0 = 1, + [1706722872.295240][5404:5404] CHIP:DMG: 0x1 = "Gp1" (3 chars), + [1706722872.295243][5404:5404] CHIP:DMG: }, + [1706722872.295246][5404:5404] CHIP:DMG: }, + [1706722872.295250][5404:5404] CHIP:DMG: + [1706722872.295253][5404:5404] CHIP:DMG: ], + [1706722872.295257][5404:5404] CHIP:DMG: + [1706722872.295260][5404:5404] CHIP:DMG: InteractionModelRevision = 11 + [1706722872.295262][5404:5404] CHIP:DMG: }, + disabled: true + - label: "Step 1: DUT issues a C_ADD_SCENE command to the Test Harness." PICS: S.C.C00.Tx verification: | - ./chip-tool scenesmanagement add-scene 0x0001 0x01 1 "scene name" '[{"clusterID": "0x0300", "attributeValueList":[{"attributeID": "0x4001", "attributeValue": "0x01"}]}]' 1 1 + ./chip-tool scenesmanagement add-scene 0x0001 0x01 20 "scene name" '[{"clusterID": "0x0300", "attributeValueList":[{"attributeID": "0x4001", "attributeValue": "0x01"}]}]' 1 1 - Verify TH recieves "AddScene" command with following parameters: + Verify TH recieves "AddScene(0x0)" command with following parameters: - ID 0 (GroupID): the type is a group-id. - ID 1 (SceneID): the type is an uint8. - ID 2 (TransitionTime): the type is an uint16; max of 60000. - ID 3 (SceneName): the type is a string; max of 16 bytes - ID 4 (ExtensionFieldSetStructs): the type is a list of ExtensionFieldSetStruct: ClusterID and AttributeValueList. on TH (all-cluster-app) log and below is the sample log provided for the raspi platform: - [1701765953.034002][9503:9503] CHIP:DMG: InvokeRequestMessage = - [1701765953.034015][9503:9503] CHIP:DMG: { - [1701765953.034025][9503:9503] CHIP:DMG: suppressResponse = false, - [1701765953.034040][9503:9503] CHIP:DMG: timedRequest = false, - [1701765953.034049][9503:9503] CHIP:DMG: InvokeRequests = - [1701765953.034078][9503:9503] CHIP:DMG: [ - [1701765953.034088][9503:9503] CHIP:DMG: CommandDataIB = - [1701765953.034103][9503:9503] CHIP:DMG: { - [1701765953.034115][9503:9503] CHIP:DMG: CommandPathIB = - [1701765953.034128][9503:9503] CHIP:DMG: { - [1701765953.034139][9503:9503] CHIP:DMG: EndpointId = 0x1, - [1701765953.034152][9503:9503] CHIP:DMG: ClusterId = 0x5, - [1701765953.034165][9503:9503] CHIP:DMG: CommandId = 0x0, - [1701765953.034176][9503:9503] CHIP:DMG: }, - [1701765953.034195][9503:9503] CHIP:DMG: - [1701765953.034206][9503:9503] CHIP:DMG: CommandFields = - [1701765953.034219][9503:9503] CHIP:DMG: { - [1701765953.034232][9503:9503] CHIP:DMG: 0x0 = 1, - [1701765953.034246][9503:9503] CHIP:DMG: 0x1 = 1, - [1701765953.034259][9503:9503] CHIP:DMG: 0x2 = 1, - [1701765953.034286][9503:9503] CHIP:DMG: 0x3 = "scene name" (10 chars), - [1701765953.034299][9503:9503] CHIP:DMG: 0x4 = [ - [1701765953.034313][9503:9503] CHIP:DMG: - [1701765953.034342][9503:9503] CHIP:DMG: { - [1701765953.034356][9503:9503] CHIP:DMG: 0x0 = 768, - [1701765953.034368][9503:9503] CHIP:DMG: 0x1 = [ - [1701765953.034382][9503:9503] CHIP:DMG: - [1701765953.034397][9503:9503] CHIP:DMG: { - [1701765953.034416][9503:9503] CHIP:DMG: 0x0 = 16385, - [1701765953.034432][9503:9503] CHIP:DMG: 0x1 = 1, - [1701765953.034448][9503:9503] CHIP:DMG: }, - [1701765953.034463][9503:9503] CHIP:DMG: ], - [1701765953.034475][9503:9503] CHIP:DMG: }, - [1701765953.034487][9503:9503] CHIP:DMG: ], - [1701765953.034500][9503:9503] CHIP:DMG: }, - [1701765953.034510][9503:9503] CHIP:DMG: }, - [1701765953.034537][9503:9503] CHIP:DMG: - [1701765953.034547][9503:9503] CHIP:DMG: ], - [1701765953.034573][9503:9503] CHIP:DMG: - [1701765953.034584][9503:9503] CHIP:DMG: InteractionModelRevision = 11 - [1701765953.034594][9503:9503] CHIP:DMG: }, + [1706722915.343620][5404:5404] CHIP:DMG: InvokeRequestMessage = + [1706722915.343637][5404:5404] CHIP:DMG: { + [1706722915.343649][5404:5404] CHIP:DMG: suppressResponse = false, + [1706722915.343664][5404:5404] CHIP:DMG: timedRequest = false, + [1706722915.343676][5404:5404] CHIP:DMG: InvokeRequests = + [1706722915.343714][5404:5404] CHIP:DMG: [ + [1706722915.343729][5404:5404] CHIP:DMG: CommandDataIB = + [1706722915.343743][5404:5404] CHIP:DMG: { + [1706722915.343758][5404:5404] CHIP:DMG: CommandPathIB = + [1706722915.343776][5404:5404] CHIP:DMG: { + [1706722915.343794][5404:5404] CHIP:DMG: EndpointId = 0x1, + [1706722915.343812][5404:5404] CHIP:DMG: ClusterId = 0x62, + [1706722915.343831][5404:5404] CHIP:DMG: CommandId = 0x0, + [1706722915.343846][5404:5404] CHIP:DMG: }, + [1706722915.343867][5404:5404] CHIP:DMG: + [1706722915.343883][5404:5404] CHIP:DMG: CommandFields = + [1706722915.343900][5404:5404] CHIP:DMG: { + [1706722915.343920][5404:5404] CHIP:DMG: 0x0 = 1, + [1706722915.343939][5404:5404] CHIP:DMG: 0x1 = 1, + [1706722915.343958][5404:5404] CHIP:DMG: 0x2 = 20, + [1706722915.343981][5404:5404] CHIP:DMG: 0x3 = "scene name" (10 chars), + [1706722915.343999][5404:5404] CHIP:DMG: 0x4 = [ + [1706722915.344018][5404:5404] CHIP:DMG: + [1706722915.344037][5404:5404] CHIP:DMG: { + [1706722915.344073][5404:5404] CHIP:DMG: 0x0 = 768, + [1706722915.344094][5404:5404] CHIP:DMG: 0x1 = [ + [1706722915.344117][5404:5404] CHIP:DMG: + [1706722915.344142][5404:5404] CHIP:DMG: { + [1706722915.344174][5404:5404] CHIP:DMG: 0x0 = 16385, + [1706722915.344200][5404:5404] CHIP:DMG: 0x1 = 1, + [1706722915.344226][5404:5404] CHIP:DMG: }, + [1706722915.344248][5404:5404] CHIP:DMG: ], + [1706722915.344268][5404:5404] CHIP:DMG: }, + [1706722915.344286][5404:5404] CHIP:DMG: ], + [1706722915.344303][5404:5404] CHIP:DMG: }, + [1706722915.344317][5404:5404] CHIP:DMG: }, + [1706722915.344355][5404:5404] CHIP:DMG: + [1706722915.344368][5404:5404] CHIP:DMG: ], + [1706722915.344408][5404:5404] CHIP:DMG: + [1706722915.344422][5404:5404] CHIP:DMG: InteractionModelRevision = 11 + [1706722915.344436][5404:5404] CHIP:DMG: }, + disabled: true - label: "Step 2: DUT issues a C_VIEW_SCENE command to the Test Harness." @@ -96,36 +265,33 @@ tests: verification: | ./chip-tool scenesmanagement view-scene 0x0001 0x01 1 1 - Verify TH recieves "ViewScene" command with following parameters: + Verify TH recieves "ViewScene(0x1)" command with following parameters: - ID 0 (GroupID): the type is a group-id. - ID 1 (SceneID): the type is an uint8.on TH (all-cluster-app) log and below is the sample log provided for the raspi platform: - [1701766130.182823][9503:9503] CHIP:DMG: InvokeRequestMessage = - [1701766130.182837][9503:9503] CHIP:DMG: { - [1701766130.182848][9503:9503] CHIP:DMG: suppressResponse = false, - [1701766130.182859][9503:9503] CHIP:DMG: timedRequest = false, - [1701766130.182869][9503:9503] CHIP:DMG: InvokeRequests = - [1701766130.182889][9503:9503] CHIP:DMG: [ - [1701766130.182899][9503:9503] CHIP:DMG: CommandDataIB = - [1701766130.182911][9503:9503] CHIP:DMG: { - [1701766130.182919][9503:9503] CHIP:DMG: CommandPathIB = - [1701766130.182935][9503:9503] CHIP:DMG: { - [1701766130.182947][9503:9503] CHIP:DMG: EndpointId = 0x1, - [1701766130.182960][9503:9503] CHIP:DMG: ClusterId = 0x5, - [1701766130.182971][9503:9503] CHIP:DMG: CommandId = 0x1, - [1701766130.182982][9503:9503] CHIP:DMG: }, - [1701766130.182996][9503:9503] CHIP:DMG: - [1701766130.183007][9503:9503] CHIP:DMG: CommandFields = - [1701766130.183018][9503:9503] CHIP:DMG: { - [1701766130.183032][9503:9503] CHIP:DMG: 0x0 = 1, - [1701766130.183044][9503:9503] CHIP:DMG: 0x1 = 1, - [1701766130.183056][9503:9503] CHIP:DMG: }, - [1701766130.183066][9503:9503] CHIP:DMG: }, - [1701766130.183082][9503:9503] CHIP:DMG: - [1701766130.183091][9503:9503] CHIP:DMG: ], - [1701766130.183110][9503:9503] CHIP:DMG: - [1701766130.183120][9503:9503] CHIP:DMG: InteractionModelRevision = 11 - [1701766130.183129][9503:9503] CHIP:DMG: }, + [1706722945.925814][5404:5404] CHIP:DMG: InvokeRequestMessage = + [1706722945.925826][5404:5404] CHIP:DMG: { + [1706722945.925837][5404:5404] CHIP:DMG: suppressResponse = false, + [1706722945.925850][5404:5404] CHIP:DMG: timedRequest = false, + [1706722945.925860][5404:5404] CHIP:DMG: InvokeRequests = + [1706722945.925888][5404:5404] CHIP:DMG: [ + [1706722945.925903][5404:5404] CHIP:DMG: CommandDataIB = + [1706722945.925924][5404:5404] CHIP:DMG: { + [1706722945.925937][5404:5404] CHIP:DMG: CommandPathIB = + [1706722945.925950][5404:5404] CHIP:DMG: { + [1706722945.925965][5404:5404] CHIP:DMG: EndpointId = 0x1, + [1706722945.925980][5404:5404] CHIP:DMG: ClusterId = 0x62, + [1706722945.925998][5404:5404] CHIP:DMG: CommandId = 0x1, + [1706722945.926014][5404:5404] CHIP:DMG: }, + [1706722945.926035][5404:5404] CHIP:DMG: + [1706722945.926051][5404:5404] CHIP:DMG: CommandFields = + [1706722945.926070][5404:5404] CHIP:DMG: { + [1706722945.926090][5404:5404] CHIP:DMG: 0x0 = 1, + [1706722945.926110][5404:5404] CHIP:DMG: 0x1 = 1, + [1706722945.926126][5404:5404] CHIP:DMG: }, + [1706722945.926141][5404:5404] CHIP:DMG: }, + [1706722945.926165][5404:5404] CHIP:DMG: + [1706722945.926176][5404:5404] CHIP:DMG: ], disabled: true - label: "Step 3: DUT issues a C_REMOVE_SCENE command to the Test Harness." @@ -133,37 +299,37 @@ tests: verification: | ./chip-tool scenesmanagement remove-scene 0x0001 0x01 1 1 - Verify TH recieves "RemoveScene" command with following parameters: + Verify TH recieves "RemoveScene(0x2)" command with following parameters: - ID 0 (GroupID): the type is a group-id. - ID 1 (SceneID): the type is an uint8. on TH (all-cluster-app) log and below is the sample log provided for the raspi platform: - [1701766180.585251][9503:9503] CHIP:DMG: InvokeRequestMessage = - [1701766180.585255][9503:9503] CHIP:DMG: { - [1701766180.585259][9503:9503] CHIP:DMG: suppressResponse = false, - [1701766180.585263][9503:9503] CHIP:DMG: timedRequest = false, - [1701766180.585267][9503:9503] CHIP:DMG: InvokeRequests = - [1701766180.585273][9503:9503] CHIP:DMG: [ - [1701766180.585276][9503:9503] CHIP:DMG: CommandDataIB = - [1701766180.585279][9503:9503] CHIP:DMG: { - [1701766180.585282][9503:9503] CHIP:DMG: CommandPathIB = - [1701766180.585286][9503:9503] CHIP:DMG: { - [1701766180.585289][9503:9503] CHIP:DMG: EndpointId = 0x1, - [1701766180.585292][9503:9503] CHIP:DMG: ClusterId = 0x5, - [1701766180.585296][9503:9503] CHIP:DMG: CommandId = 0x2, - [1701766180.585298][9503:9503] CHIP:DMG: }, - [1701766180.585302][9503:9503] CHIP:DMG: - [1701766180.585305][9503:9503] CHIP:DMG: CommandFields = - [1701766180.585308][9503:9503] CHIP:DMG: { - [1701766180.585312][9503:9503] CHIP:DMG: 0x0 = 1, - [1701766180.585315][9503:9503] CHIP:DMG: 0x1 = 1, - [1701766180.585318][9503:9503] CHIP:DMG: }, - [1701766180.585320][9503:9503] CHIP:DMG: }, - [1701766180.585325][9503:9503] CHIP:DMG: - [1701766180.585327][9503:9503] CHIP:DMG: ], - [1701766180.585332][9503:9503] CHIP:DMG: - [1701766180.585334][9503:9503] CHIP:DMG: InteractionModelRevision = 11 - [1701766180.585337][9503:9503] CHIP:DMG: }, + [1706722967.651552][5404:5404] CHIP:DMG: InvokeRequestMessage = + [1706722967.651557][5404:5404] CHIP:DMG: { + [1706722967.651561][5404:5404] CHIP:DMG: suppressResponse = false, + [1706722967.651565][5404:5404] CHIP:DMG: timedRequest = false, + [1706722967.651570][5404:5404] CHIP:DMG: InvokeRequests = + [1706722967.651577][5404:5404] CHIP:DMG: [ + [1706722967.651580][5404:5404] CHIP:DMG: CommandDataIB = + [1706722967.651585][5404:5404] CHIP:DMG: { + [1706722967.651588][5404:5404] CHIP:DMG: CommandPathIB = + [1706722967.651593][5404:5404] CHIP:DMG: { + [1706722967.651598][5404:5404] CHIP:DMG: EndpointId = 0x1, + [1706722967.651602][5404:5404] CHIP:DMG: ClusterId = 0x62, + [1706722967.651606][5404:5404] CHIP:DMG: CommandId = 0x2, + [1706722967.651610][5404:5404] CHIP:DMG: }, + [1706722967.651615][5404:5404] CHIP:DMG: + [1706722967.651619][5404:5404] CHIP:DMG: CommandFields = + [1706722967.651623][5404:5404] CHIP:DMG: { + [1706722967.651628][5404:5404] CHIP:DMG: 0x0 = 1, + [1706722967.651633][5404:5404] CHIP:DMG: 0x1 = 1, + [1706722967.651636][5404:5404] CHIP:DMG: }, + [1706722967.651640][5404:5404] CHIP:DMG: }, + [1706722967.651646][5404:5404] CHIP:DMG: + [1706722967.651649][5404:5404] CHIP:DMG: ], + [1706722967.651655][5404:5404] CHIP:DMG: + [1706722967.651658][5404:5404] CHIP:DMG: InteractionModelRevision = 11 + [1706722967.651661][5404:5404] CHIP:DMG: }, disabled: true - label: @@ -172,35 +338,35 @@ tests: verification: | ./chip-tool scenesmanagement remove-all-scenes 0x0001 1 1 - Verify TH recieves "RemoveAllScenes" command with following parameters: + Verify TH recieves "RemoveAllScenes(0x3)" command with following parameters: - ID 0 (GroupID): the type is a group-id. on TH (all-cluster-app) log and below is the sample log provided for the raspi platform: - [1701766227.694588][9503:9503] CHIP:DMG: InvokeRequestMessage = - [1701766227.694600][9503:9503] CHIP:DMG: { - [1701766227.694608][9503:9503] CHIP:DMG: suppressResponse = false, - [1701766227.694618][9503:9503] CHIP:DMG: timedRequest = false, - [1701766227.694625][9503:9503] CHIP:DMG: InvokeRequests = - [1701766227.694641][9503:9503] CHIP:DMG: [ - [1701766227.694648][9503:9503] CHIP:DMG: CommandDataIB = - [1701766227.694669][9503:9503] CHIP:DMG: { - [1701766227.694680][9503:9503] CHIP:DMG: CommandPathIB = - [1701766227.694692][9503:9503] CHIP:DMG: { - [1701766227.694704][9503:9503] CHIP:DMG: EndpointId = 0x1, - [1701766227.694717][9503:9503] CHIP:DMG: ClusterId = 0x5, - [1701766227.694729][9503:9503] CHIP:DMG: CommandId = 0x3, - [1701766227.694739][9503:9503] CHIP:DMG: }, - [1701766227.694753][9503:9503] CHIP:DMG: - [1701766227.694763][9503:9503] CHIP:DMG: CommandFields = - [1701766227.694775][9503:9503] CHIP:DMG: { - [1701766227.694788][9503:9503] CHIP:DMG: 0x0 = 1, - [1701766227.694800][9503:9503] CHIP:DMG: }, - [1701766227.694810][9503:9503] CHIP:DMG: }, - [1701766227.694826][9503:9503] CHIP:DMG: - [1701766227.694836][9503:9503] CHIP:DMG: ], - [1701766227.694853][9503:9503] CHIP:DMG: - [1701766227.694863][9503:9503] CHIP:DMG: InteractionModelRevision = 11 - [1701766227.694872][9503:9503] CHIP:DMG: }, + [1706722986.792332][5404:5404] CHIP:DMG: InvokeRequestMessage = + [1706722986.792353][5404:5404] CHIP:DMG: { + [1706722986.792374][5404:5404] CHIP:DMG: suppressResponse = false, + [1706722986.792388][5404:5404] CHIP:DMG: timedRequest = false, + [1706722986.792395][5404:5404] CHIP:DMG: InvokeRequests = + [1706722986.792415][5404:5404] CHIP:DMG: [ + [1706722986.792425][5404:5404] CHIP:DMG: CommandDataIB = + [1706722986.792446][5404:5404] CHIP:DMG: { + [1706722986.792460][5404:5404] CHIP:DMG: CommandPathIB = + [1706722986.792475][5404:5404] CHIP:DMG: { + [1706722986.792490][5404:5404] CHIP:DMG: EndpointId = 0x1, + [1706722986.792508][5404:5404] CHIP:DMG: ClusterId = 0x62, + [1706722986.792522][5404:5404] CHIP:DMG: CommandId = 0x3, + [1706722986.792535][5404:5404] CHIP:DMG: }, + [1706722986.792553][5404:5404] CHIP:DMG: + [1706722986.792568][5404:5404] CHIP:DMG: CommandFields = + [1706722986.792585][5404:5404] CHIP:DMG: { + [1706722986.792600][5404:5404] CHIP:DMG: 0x0 = 1, + [1706722986.792612][5404:5404] CHIP:DMG: }, + [1706722986.792621][5404:5404] CHIP:DMG: }, + [1706722986.792638][5404:5404] CHIP:DMG: + [1706722986.792647][5404:5404] CHIP:DMG: ], + [1706722986.792669][5404:5404] CHIP:DMG: + [1706722986.792679][5404:5404] CHIP:DMG: InteractionModelRevision = 11 + [1706722986.792689][5404:5404] CHIP:DMG: }, disabled: true - label: "Step 5: DUT issues a C_STORE_SCENE command to the Test Harness." @@ -208,74 +374,76 @@ tests: verification: | ./chip-tool scenesmanagement store-scene 0x0001 0x01 1 1 - Verify TH recieves "StoreScene" command with following parameters: + Verify TH recieves "StoreScene(0x4)" command with following parameters: - ID 0 (GroupID): the type is a group-id. - ID 1 (SceneID): the type is an uint8. on TH (all-cluster-app) log and below is the sample log provided for the raspi platform: - [1701766289.958764][9503:9503] CHIP:DMG: InvokeRequestMessage = - [1701766289.958776][9503:9503] CHIP:DMG: { - [1701766289.958784][9503:9503] CHIP:DMG: suppressResponse = false, - [1701766289.958794][9503:9503] CHIP:DMG: timedRequest = false, - [1701766289.958801][9503:9503] CHIP:DMG: InvokeRequests = - [1701766289.958818][9503:9503] CHIP:DMG: [ - [1701766289.958825][9503:9503] CHIP:DMG: CommandDataIB = - [1701766289.958845][9503:9503] CHIP:DMG: { - [1701766289.958855][9503:9503] CHIP:DMG: CommandPathIB = - [1701766289.958868][9503:9503] CHIP:DMG: { - [1701766289.958879][9503:9503] CHIP:DMG: EndpointId = 0x1, - [1701766289.958892][9503:9503] CHIP:DMG: ClusterId = 0x5, - [1701766289.958911][9503:9503] CHIP:DMG: CommandId = 0x4, - [1701766289.958924][9503:9503] CHIP:DMG: }, - [1701766289.958937][9503:9503] CHIP:DMG: - [1701766289.958948][9503:9503] CHIP:DMG: CommandFields = - [1701766289.958960][9503:9503] CHIP:DMG: { - [1701766289.958973][9503:9503] CHIP:DMG: 0x0 = 1, - [1701766289.958986][9503:9503] CHIP:DMG: 0x1 = 1, - [1701766289.958997][9503:9503] CHIP:DMG: }, - [1701766289.959007][9503:9503] CHIP:DMG: }, - [1701766289.959024][9503:9503] CHIP:DMG: - [1701766289.959033][9503:9503] CHIP:DMG: ], - [1701766289.959051][9503:9503] CHIP:DMG: - [1701766289.959061][9503:9503] CHIP:DMG: InteractionModelRevision = 11 - [1701766289.959070][9503:9503] CHIP:DMG: }, + [1706723006.082174][5404:5404] CHIP:DMG: InvokeRequestMessage = + [1706723006.082187][5404:5404] CHIP:DMG: { + [1706723006.082196][5404:5404] CHIP:DMG: suppressResponse = false, + [1706723006.082208][5404:5404] CHIP:DMG: timedRequest = false, + [1706723006.082218][5404:5404] CHIP:DMG: InvokeRequests = + [1706723006.082237][5404:5404] CHIP:DMG: [ + [1706723006.082247][5404:5404] CHIP:DMG: CommandDataIB = + [1706723006.082258][5404:5404] CHIP:DMG: { + [1706723006.082268][5404:5404] CHIP:DMG: CommandPathIB = + [1706723006.082280][5404:5404] CHIP:DMG: { + [1706723006.082292][5404:5404] CHIP:DMG: EndpointId = 0x1, + [1706723006.082304][5404:5404] CHIP:DMG: ClusterId = 0x62, + [1706723006.082316][5404:5404] CHIP:DMG: CommandId = 0x4, + [1706723006.082326][5404:5404] CHIP:DMG: }, + [1706723006.082341][5404:5404] CHIP:DMG: + [1706723006.082351][5404:5404] CHIP:DMG: CommandFields = + [1706723006.082362][5404:5404] CHIP:DMG: { + [1706723006.082376][5404:5404] CHIP:DMG: 0x0 = 1, + [1706723006.082388][5404:5404] CHIP:DMG: 0x1 = 1, + [1706723006.082399][5404:5404] CHIP:DMG: }, + [1706723006.082409][5404:5404] CHIP:DMG: }, + [1706723006.082425][5404:5404] CHIP:DMG: + [1706723006.082434][5404:5404] CHIP:DMG: ], + [1706723006.082451][5404:5404] CHIP:DMG: + [1706723006.082461][5404:5404] CHIP:DMG: InteractionModelRevision = 11 + [1706723006.082471][5404:5404] CHIP:DMG: }, disabled: true - label: "Step 6: DUT issues a C_RECALL_SCENE command to the Test Harness." PICS: S.C.C05.Tx verification: | - ./chip-tool scenesmanagement recall-scene 0x0001 0x01 1 1 + ./chip-tool scenesmanagement recall-scene 0x0001 0x01 1 1 --TransitionTime 10 - Verify TH recieves "RecallScene" command with following parameters: + Verify TH recieves "RecallScene(0x5)" command with following parameters: - ID 0 (GroupID): the type is a group-id. - - ID 1 (SceneID): the type is an uint8 on TH (all-cluster-app) log and below is the sample log provided for the raspi platform: - - [1701766368.793204][9503:9503] CHIP:DMG: InvokeRequestMessage = - [1701766368.793216][9503:9503] CHIP:DMG: { - [1701766368.793226][9503:9503] CHIP:DMG: suppressResponse = false, - [1701766368.793238][9503:9503] CHIP:DMG: timedRequest = false, - [1701766368.793248][9503:9503] CHIP:DMG: InvokeRequests = - [1701766368.793267][9503:9503] CHIP:DMG: [ - [1701766368.793276][9503:9503] CHIP:DMG: CommandDataIB = - [1701766368.793288][9503:9503] CHIP:DMG: { - [1701766368.793298][9503:9503] CHIP:DMG: CommandPathIB = - [1701766368.793309][9503:9503] CHIP:DMG: { - [1701766368.793321][9503:9503] CHIP:DMG: EndpointId = 0x1, - [1701766368.793334][9503:9503] CHIP:DMG: ClusterId = 0x5, - [1701766368.793346][9503:9503] CHIP:DMG: CommandId = 0x5, - [1701766368.793355][9503:9503] CHIP:DMG: }, - [1701766368.793369][9503:9503] CHIP:DMG: - [1701766368.793380][9503:9503] CHIP:DMG: CommandFields = - [1701766368.793392][9503:9503] CHIP:DMG: { - [1701766368.793405][9503:9503] CHIP:DMG: 0x0 = 1, - [1701766368.793417][9503:9503] CHIP:DMG: 0x1 = 1, - [1701766368.793429][9503:9503] CHIP:DMG: }, - [1701766368.793439][9503:9503] CHIP:DMG: }, - [1701766368.793456][9503:9503] CHIP:DMG: - [1701766368.793465][9503:9503] CHIP:DMG: ], - [1701766368.793483][9503:9503] CHIP:DMG: - [1701766368.793493][9503:9503] CHIP:DMG: InteractionModelRevision = 11 - [1701766368.793502][9503:9503] CHIP:DMG: }, + - ID 1 (SceneID): the type is an uint8 + - Optional ID 2 (TransitionTime): the type is an uint32; max of 60000000 on TH (all-cluster-app) log and below is the sample log provided for the raspi platform: + + [1706723348.325563][5404:5404] CHIP:DMG: InvokeRequestMessage = + [1706723348.325580][5404:5404] CHIP:DMG: { + [1706723348.325596][5404:5404] CHIP:DMG: suppressResponse = false, + [1706723348.325613][5404:5404] CHIP:DMG: timedRequest = false, + [1706723348.325628][5404:5404] CHIP:DMG: InvokeRequests = + [1706723348.325657][5404:5404] CHIP:DMG: [ + [1706723348.325671][5404:5404] CHIP:DMG: CommandDataIB = + [1706723348.325689][5404:5404] CHIP:DMG: { + [1706723348.325703][5404:5404] CHIP:DMG: CommandPathIB = + [1706723348.325721][5404:5404] CHIP:DMG: { + [1706723348.325740][5404:5404] CHIP:DMG: EndpointId = 0x1, + [1706723348.325758][5404:5404] CHIP:DMG: ClusterId = 0x62, + [1706723348.325776][5404:5404] CHIP:DMG: CommandId = 0x5, + [1706723348.325792][5404:5404] CHIP:DMG: }, + [1706723348.325812][5404:5404] CHIP:DMG: + [1706723348.325829][5404:5404] CHIP:DMG: CommandFields = + [1706723348.325846][5404:5404] CHIP:DMG: { + [1706723348.325865][5404:5404] CHIP:DMG: 0x0 = 1, + [1706723348.325885][5404:5404] CHIP:DMG: 0x1 = 1, + [1706723348.325904][5404:5404] CHIP:DMG: 0x2 = 10, + [1706723348.325924][5404:5404] CHIP:DMG: }, + [1706723348.325938][5404:5404] CHIP:DMG: }, + [1706723348.325965][5404:5404] CHIP:DMG: + [1706723348.325979][5404:5404] CHIP:DMG: ], + [1706723348.326007][5404:5404] CHIP:DMG: + [1706723348.326022][5404:5404] CHIP:DMG: InteractionModelRevision = 11 + [1706723348.326035][5404:5404] CHIP:DMG: }, disabled: true - label: @@ -285,76 +453,76 @@ tests: verification: | ./chip-tool scenesmanagement get-scene-membership 0x00001 1 1 - Verify TH recieves "GetSceneMembership" command with following parameters: + Verify TH recieves "GetSceneMembership(0x6)" command with following parameters: - ID 0 (GroupID): the type is a group-id. on TH (all-cluster-app) log and below is the sample log provided for the raspi platform: - [1701766468.058659][9503:9503] CHIP:DMG: InvokeRequestMessage = - [1701766468.058673][9503:9503] CHIP:DMG: { - [1701766468.058684][9503:9503] CHIP:DMG: suppressResponse = false, - [1701766468.058695][9503:9503] CHIP:DMG: timedRequest = false, - [1701766468.058705][9503:9503] CHIP:DMG: InvokeRequests = - [1701766468.058724][9503:9503] CHIP:DMG: [ - [1701766468.058733][9503:9503] CHIP:DMG: CommandDataIB = - [1701766468.058745][9503:9503] CHIP:DMG: { - [1701766468.058754][9503:9503] CHIP:DMG: CommandPathIB = - [1701766468.058766][9503:9503] CHIP:DMG: { - [1701766468.058778][9503:9503] CHIP:DMG: EndpointId = 0x1, - [1701766468.058790][9503:9503] CHIP:DMG: ClusterId = 0x5, - [1701766468.058802][9503:9503] CHIP:DMG: CommandId = 0x6, - [1701766468.058813][9503:9503] CHIP:DMG: }, - [1701766468.058827][9503:9503] CHIP:DMG: - [1701766468.058837][9503:9503] CHIP:DMG: CommandFields = - [1701766468.058849][9503:9503] CHIP:DMG: { - [1701766468.058862][9503:9503] CHIP:DMG: 0x0 = 1, - [1701766468.058874][9503:9503] CHIP:DMG: }, - [1701766468.058883][9503:9503] CHIP:DMG: }, - [1701766468.058900][9503:9503] CHIP:DMG: - [1701766468.058909][9503:9503] CHIP:DMG: ], - [1701766468.058927][9503:9503] CHIP:DMG: - [1701766468.058937][9503:9503] CHIP:DMG: InteractionModelRevision = 11 - [1701766468.058946][9503:9503] CHIP:DMG: }, + [1706723042.993627][5404:5404] CHIP:DMG: InvokeRequestMessage = + [1706723042.993631][5404:5404] CHIP:DMG: { + [1706723042.993634][5404:5404] CHIP:DMG: suppressResponse = false, + [1706723042.993639][5404:5404] CHIP:DMG: timedRequest = false, + [1706723042.993644][5404:5404] CHIP:DMG: InvokeRequests = + [1706723042.993651][5404:5404] CHIP:DMG: [ + [1706723042.993655][5404:5404] CHIP:DMG: CommandDataIB = + [1706723042.993660][5404:5404] CHIP:DMG: { + [1706723042.993664][5404:5404] CHIP:DMG: CommandPathIB = + [1706723042.993669][5404:5404] CHIP:DMG: { + [1706723042.993674][5404:5404] CHIP:DMG: EndpointId = 0x1, + [1706723042.993685][5404:5404] CHIP:DMG: ClusterId = 0x62, + [1706723042.993690][5404:5404] CHIP:DMG: CommandId = 0x6, + [1706723042.993694][5404:5404] CHIP:DMG: }, + [1706723042.993699][5404:5404] CHIP:DMG: + [1706723042.993703][5404:5404] CHIP:DMG: CommandFields = + [1706723042.993708][5404:5404] CHIP:DMG: { + [1706723042.993713][5404:5404] CHIP:DMG: 0x0 = 1, + [1706723042.993718][5404:5404] CHIP:DMG: }, + [1706723042.993722][5404:5404] CHIP:DMG: }, + [1706723042.993728][5404:5404] CHIP:DMG: + [1706723042.993732][5404:5404] CHIP:DMG: ], + [1706723042.993739][5404:5404] CHIP:DMG: + [1706723042.993743][5404:5404] CHIP:DMG: InteractionModelRevision = 11 + [1706723042.993746][5404:5404] CHIP:DMG: }, disabled: true - label: "Step 8: DUT issues a C_COPY_SCENE command to the Test Harness." - PICS: S.C.C09.Tx + PICS: S.C.C40.Tx verification: | ./chip-tool scenesmanagement copy-scene 0x00 0x01 0x01 0x01 0x02 1 1 - Verify TH recieves "CopyScene" command with following parameters: + Verify TH recieves "CopyScene( 0x40)" command with following parameters: - ID 0 (Mode): the type is a CopyModeBitmap; If this value is set to 1, all scenes are to be copied. Otherwise this bit is set to 0 - ID 1 (GroupIdentifierFrom): the type is an group-id. - ID 2 (SceneIdentifierFrom): the type is an uint8. - ID 3 (GroupIdentifierTo): the type is an group-id. - ID 4 (SceneIdentifierTo): the type is an uint8. on TH (all-cluster-app) log and below is the sample log provided for the raspi platform: - [1701766693.900630][9503:9503] CHIP:DMG: InvokeRequestMessage = - [1701766693.900646][9503:9503] CHIP:DMG: { - [1701766693.900662][9503:9503] CHIP:DMG: suppressResponse = false, - [1701766693.900680][9503:9503] CHIP:DMG: timedRequest = false, - [1701766693.900694][9503:9503] CHIP:DMG: InvokeRequests = - [1701766693.900723][9503:9503] CHIP:DMG: [ - [1701766693.900735][9503:9503] CHIP:DMG: CommandDataIB = - [1701766693.900752][9503:9503] CHIP:DMG: { - [1701766693.900766][9503:9503] CHIP:DMG: CommandPathIB = - [1701766693.900784][9503:9503] CHIP:DMG: { - [1701766693.900801][9503:9503] CHIP:DMG: EndpointId = 0x1, - [1701766693.900819][9503:9503] CHIP:DMG: ClusterId = 0x5, - [1701766693.900836][9503:9503] CHIP:DMG: CommandId = 0x42, - [1701766693.900850][9503:9503] CHIP:DMG: }, - [1701766693.900870][9503:9503] CHIP:DMG: - [1701766693.900884][9503:9503] CHIP:DMG: CommandFields = - [1701766693.900902][9503:9503] CHIP:DMG: { - [1701766693.900921][9503:9503] CHIP:DMG: 0x0 = 0, - [1701766693.900938][9503:9503] CHIP:DMG: 0x1 = 1, - [1701766693.900955][9503:9503] CHIP:DMG: 0x2 = 1, - [1701766693.900973][9503:9503] CHIP:DMG: 0x3 = 1, - [1701766693.900990][9503:9503] CHIP:DMG: 0x4 = 2, - [1701766693.901006][9503:9503] CHIP:DMG: }, - [1701766693.901020][9503:9503] CHIP:DMG: }, - [1701766693.901047][9503:9503] CHIP:DMG: - [1701766693.901057][9503:9503] CHIP:DMG: ], - [1701766693.901085][9503:9503] CHIP:DMG: - [1701766693.901097][9503:9503] CHIP:DMG: InteractionModelRevision = 11 - [1701766693.901111][9503:9503] CHIP:DMG: }, + [1706723061.022072][5404:5404] CHIP:DMG: InvokeRequestMessage = + [1706723061.022075][5404:5404] CHIP:DMG: { + [1706723061.022077][5404:5404] CHIP:DMG: suppressResponse = false, + [1706723061.022081][5404:5404] CHIP:DMG: timedRequest = false, + [1706723061.022084][5404:5404] CHIP:DMG: InvokeRequests = + [1706723061.022089][5404:5404] CHIP:DMG: [ + [1706723061.022092][5404:5404] CHIP:DMG: CommandDataIB = + [1706723061.022095][5404:5404] CHIP:DMG: { + [1706723061.022098][5404:5404] CHIP:DMG: CommandPathIB = + [1706723061.022101][5404:5404] CHIP:DMG: { + [1706723061.022105][5404:5404] CHIP:DMG: EndpointId = 0x1, + [1706723061.022108][5404:5404] CHIP:DMG: ClusterId = 0x62, + [1706723061.022111][5404:5404] CHIP:DMG: CommandId = 0x40, + [1706723061.022114][5404:5404] CHIP:DMG: }, + [1706723061.022117][5404:5404] CHIP:DMG: + [1706723061.022120][5404:5404] CHIP:DMG: CommandFields = + [1706723061.022123][5404:5404] CHIP:DMG: { + [1706723061.022127][5404:5404] CHIP:DMG: 0x0 = 0, + [1706723061.022130][5404:5404] CHIP:DMG: 0x1 = 1, + [1706723061.022133][5404:5404] CHIP:DMG: 0x2 = 1, + [1706723061.022136][5404:5404] CHIP:DMG: 0x3 = 1, + [1706723061.022139][5404:5404] CHIP:DMG: 0x4 = 2, + [1706723061.022142][5404:5404] CHIP:DMG: }, + [1706723061.022145][5404:5404] CHIP:DMG: }, + [1706723061.022150][5404:5404] CHIP:DMG: + [1706723061.022152][5404:5404] CHIP:DMG: ], + [1706723061.022157][5404:5404] CHIP:DMG: + [1706723061.022160][5404:5404] CHIP:DMG: InteractionModelRevision = 11 + [1706723061.022162][5404:5404] CHIP:DMG: }, disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_TCCM_1_1.yaml b/src/app/tests/suites/certification/Test_TC_TCCM_1_1.yaml index c3cd45da41d4db..4ee0ba303a1c61 100644 --- a/src/app/tests/suites/certification/Test_TC_TCCM_1_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_TCCM_1_1.yaml @@ -41,6 +41,7 @@ tests: constraints: type: int16u + #Issue https://github.com/project-chip/connectedhomeip/issues/31551 - label: "Step 3: TH reads from the DUT the FeatureMap attribute." command: "readAttribute" attribute: "FeatureMap" @@ -52,7 +53,7 @@ tests: - label: "Step 3: TH reads from the DUT the FeatureMap attribute, bit 0: SHALL - be 1 if and only if TCCM.S.F00(DEPONOFF)" + be 1 if and only if TCCM.S.F00" command: "readAttribute" attribute: "FeatureMap" PICS: TCCM.S.F00 @@ -90,9 +91,10 @@ tests: type: list contains: [2] + #Issue https://github.com/project-chip/connectedhomeip/issues/31551 - label: "Step 4c: TH reads from the DUT the AttributeList attribute. 0x0003 - SHALL be included if and only if TCCM.S.F00(DEPONOFF)" + SHALL be included if and only if TCCM.S.F00" PICS: TCCM.S.F00 command: "readAttribute" attribute: "AttributeList" diff --git a/src/app/tests/suites/certification/Test_TC_TCCM_1_2.yaml b/src/app/tests/suites/certification/Test_TC_TCCM_1_2.yaml index ebeb15ee878c7c..8e3d3190ba249c 100644 --- a/src/app/tests/suites/certification/Test_TC_TCCM_1_2.yaml +++ b/src/app/tests/suites/certification/Test_TC_TCCM_1_2.yaml @@ -82,25 +82,3 @@ tests: [1690189682.782276][16162:16164] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0052 Attribute 0x0000_0001 DataVersion: 473867547 [1690189682.782314][16162:16164] CHIP:TOO: CurrentMode: 0 disabled: true - - - label: "Step 4: TH reads from the DUT the OnMode attribute." - PICS: TCCM.S.A0003 - verification: | - ./chip-tool refrigeratorandtemperaturecontrolledcabinetmode read on-mode 1 1 - - Verify on TH(chip-tool) logs, OnMode attribute value is an integer from supported_modes_dut or null, below is the sample log provided for the raspi platform, Here OnMode attribute value is Null - - [1690189699.711642][16169:16171] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0052 Attribute 0x0000_0003 DataVersion: 473867547 - [1690189699.711687][16169:16171] CHIP:TOO: OnMode: null - disabled: true - - - label: "Step 5: TH reads from the DUT the StartUpMode attribute." - PICS: TCCM.S.A0002 - verification: | - ./chip-tool refrigeratorandtemperaturecontrolledcabinetmode read start-up-mode 1 1 - - Verify on TH(chip-tool) logs, StartUpMode attribute value is an integer from supported_modes_dut or null, below is the sample log provided for the raspi platform, Here StartUpMode attribute value is Null - - [1690189713.973520][16173:16175] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0052 Attribute 0x0000_0002 DataVersion: 473867547 - [1690189713.973576][16173:16175] CHIP:TOO: StartUpMode: null - disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_TCCM_3_1.yaml b/src/app/tests/suites/certification/Test_TC_TCCM_3_1.yaml index d491fe62cb825d..178357027408c7 100644 --- a/src/app/tests/suites/certification/Test_TC_TCCM_3_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_TCCM_3_1.yaml @@ -16,7 +16,7 @@ name: 219.3.1. [TC-TCCM-3.1] On Mode functionality with DUT as Server PICS: - TCCM.S.A0003 - - TCCM.S.F00 + - MOD.S.F00 - OO.S.C00.Rsp - OO.S.C01.Rsp @@ -46,21 +46,21 @@ tests: - label: "Preconditions: The OnMode attribute is set to a non-NULL value from the mode values indicated by the SupportedModes attribute." - PICS: TCCM.S.A0003 && TCCM.S.F00 + PICS: TCCM.S.A0003 && MOD.S.F00 command: "writeAttribute" attribute: "OnMode" arguments: value: nonNull_OnMode_value - label: "Step 2: TH reads from the DUT the OnMode attribute." - PICS: TCCM.S.A0003 && TCCM.S.F00 + PICS: TCCM.S.A0003 && MOD.S.F00 command: "readAttribute" attribute: "OnMode" response: saveAs: on_mode_dut - label: "Step 3a: TH reads from the DUT the CurrentMode attribute." - PICS: TCCM.S.A0001 && TCCM.S.F00 + PICS: TCCM.S.A0001 && MOD.S.F00 command: "readAttribute" attribute: "CurrentMode" response: @@ -69,7 +69,7 @@ tests: - label: "Step 3b: If the OnMode and CurrentMode attributes have the same value, proceed to step 4, Otherwise proceed to step 6" - PICS: TCCM.S.A0003 && TCCM.S.A0001 && TCCM.S.F00 + PICS: TCCM.S.A0003 && TCCM.S.A0001 && MOD.S.F00 cluster: "EqualityCommands" command: "UnsignedNumberEquals" arguments: @@ -85,7 +85,7 @@ tests: - label: "Step 4:TH reads the SupportedModes attribute from the DUT" runIf: IsExpectedValue - PICS: TCCM.S.A0000 && TCCM.S.F00 + PICS: TCCM.S.A0000 && MOD.S.F00 command: "readAttribute" attribute: "SupportedModes" response: @@ -98,7 +98,7 @@ tests: on_mode_dut. Save the value as new_mode_th. TH sends a ChangeToMode command to the DUT with NewMode set to new_mode_th" runIf: IsExpectedValue - PICS: TCCM.S.C00.Rsp && TCCM.S.F00 + PICS: TCCM.S.C00.Rsp && MOD.S.F00 command: "ChangeToMode" arguments: values: @@ -110,17 +110,17 @@ tests: value: 0x00 - label: "Step 6: TH sends an Off command to the DUT" - PICS: OO.S.C00.Rsp && TCCM.S.F00 + PICS: OO.S.C00.Rsp && MOD.S.F00 cluster: "On/Off" command: "Off" - label: "Step 7: TH sends an On command to the DUT" - PICS: OO.S.C01.Rsp && TCCM.S.F00 + PICS: OO.S.C01.Rsp && MOD.S.F00 cluster: "On/Off" command: "On" - label: "Step 8: TH reads the CurrentMode attribute from the DUT" - PICS: TCCM.S.A0001 && TCCM.S.F00 + PICS: TCCM.S.A0001 && MOD.S.F00 command: "readAttribute" attribute: "CurrentMode" response: diff --git a/src/app/tests/suites/certification/Test_TC_TCCM_3_3.yaml b/src/app/tests/suites/certification/Test_TC_TCCM_3_3.yaml index ae92d1723cb6be..64d8b3f7d637e9 100644 --- a/src/app/tests/suites/certification/Test_TC_TCCM_3_3.yaml +++ b/src/app/tests/suites/certification/Test_TC_TCCM_3_3.yaml @@ -19,7 +19,7 @@ name: PICS: - TCCM.S.A0002 - TCCM.S.A0003 - - TCCM.S.F00 + - MOD.S.F00 - OO.S.A4003 config: @@ -140,7 +140,7 @@ tests: value: new_mode_th - label: "Step 8: TH reads from the DUT the OnMode attribute." - PICS: TCCM.S.A0003 && TCCM.S.F00 + PICS: TCCM.S.A0003 && MOD.S.F00 command: "readAttribute" attribute: "OnMode" response: diff --git a/src/app/tests/suites/certification/Test_TC_TSTAT_2_1.yaml b/src/app/tests/suites/certification/Test_TC_TSTAT_2_1.yaml index 63aba52fe3f3f6..faf34fdea43e92 100644 --- a/src/app/tests/suites/certification/Test_TC_TSTAT_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_TSTAT_2_1.yaml @@ -468,8 +468,12 @@ tests: response: constraints: type: enum8 - minValue: 0 - maxValue: 9 + anyOf: + [ + ThermostatRunningModeEnum.Off(0), + ThermostatRunningModeEnum.Cool(3), + ThermostatRunningModeEnum.Heat(4), + ] - label: "Step 27: TH reads the StartOfWeek attribute from the DUT" PICS: TSTAT.S.F03 diff --git a/src/app/tests/suites/certification/ci-pics-values b/src/app/tests/suites/certification/ci-pics-values index fd11f3ae2ac007..021f52e6547ec8 100644 --- a/src/app/tests/suites/certification/ci-pics-values +++ b/src/app/tests/suites/certification/ci-pics-values @@ -423,10 +423,10 @@ MEDIAPLAYBACK.S.A0003=1 MEDIAPLAYBACK.S.A0004=1 MEDIAPLAYBACK.S.A0005=1 MEDIAPLAYBACK.S.A0006=1 -MEDIAPLAYBACK.S.A0007=0 -MEDIAPLAYBACK.S.A0008=0 -MEDIAPLAYBACK.S.A0009=0 -MEDIAPLAYBACK.S.A000a=0 +MEDIAPLAYBACK.S.A0007=1 +MEDIAPLAYBACK.S.A0008=1 +MEDIAPLAYBACK.S.A0009=1 +MEDIAPLAYBACK.S.A000a=1 MEDIAPLAYBACK.S.C00.Rsp=1 MEDIAPLAYBACK.S.C01.Rsp=1 @@ -439,6 +439,9 @@ MEDIAPLAYBACK.S.C07.Rsp=1 MEDIAPLAYBACK.S.C08.Rsp=1 MEDIAPLAYBACK.S.C09.Rsp=1 MEDIAPLAYBACK.S.C0b.Rsp=1 +MEDIAPLAYBACK.S.C0c.Rsp=1 +MEDIAPLAYBACK.S.C0d.Rsp=1 +MEDIAPLAYBACK.S.C0e.Rsp=1 MEDIAPLAYBACK.S.F00=1 MEDIAPLAYBACK.S.F01=1 @@ -2474,97 +2477,132 @@ REFALM.S.E00=1 REFALM.S.C00.Rsp=1 REFALM.S.C01.Rsp=1 -# RVC CLEAN MODE CLUSTER - +# PICS for the RVC app +# These are required to be here because currently there isn't a way to select a different PICS +# file when running the yaml tests in CI RVCCLEANM.S=1 - -#Server RVCCLEANM.S.A0000=1 RVCCLEANM.S.A0001=1 - -#Feature -RVCCLEANM.S.F00=0 - -#commands RVCCLEANM.S.C00.Rsp=1 RVCCLEANM.S.C01.Tx=1 - +RVCCLEANM.S.F00=0 RVCCLEANM.S.M.CAN_TEST_MODE_FAILURE=1 -#PIXIT -PIXIT.RVCCLEANM.MODE_CHANGE_FAIL=1 -PIXIT.RVCCLEANM.MODE_CHANGE_OK=1 - -# RVC OPERATIONAL STATE CLUSTER RVCOPSTATE.S=1 -RVCOPSTATE.C=1 - -#ManuallyControlled -# These are the PICS supported by the all-clusters-app - -RVCOPSTATE.S.M.ST_STOPPED=1 -RVCOPSTATE.S.M.ST_RUNNING=1 -RVCOPSTATE.S.M.ST_PAUSED=1 -RVCOPSTATE.S.M.ST_ERROR=0 -RVCOPSTATE.S.M.ST_SEEKING_CHARGER=0 -RVCOPSTATE.S.M.ST_CHARGING=0 -RVCOPSTATE.S.M.ST_DOCKED=0 -RVCOPSTATE.S.M.ERR_NO_ERROR=1 -RVCOPSTATE.S.M.ERR_UNABLE_TO_START_OR_RESUME=0 -RVCOPSTATE.S.M.ERR_UNABLE_TO_COMPLETE_OPERATION=0 -RVCOPSTATE.S.M.ERR_COMMAND_INVALID_IN_STATE=0 -RVCOPSTATE.S.M.ERR_FAILED_TO_FIND_CHARGING_DOCK=0 -RVCOPSTATE.S.M.ERR_STUCK=0 -RVCOPSTATE.S.M.ERR_DUST_BIN_MISSING=0 -RVCOPSTATE.S.M.ERR_DUST_BIN_FULL=0 -RVCOPSTATE.S.M.ERR_WATER_TANK_EMPTY=0 -RVCOPSTATE.S.M.ERR_WATER_TANK_MISSING=0 -RVCOPSTATE.S.M.ERR_WATER_TANK_LID_OPEN=0 -RVCOPSTATE.S.M.ERR_MOP_CLEANING_PAD_MISSING=0 - -#Events -RVCOPSTATE.S.E00=1 -RVCOPSTATE.S.E01=1 - -#Server RVCOPSTATE.S.A0000=1 RVCOPSTATE.S.A0001=1 -RVCOPSTATE.S.A0002=1 +RVCOPSTATE.S.A0002=0 RVCOPSTATE.S.A0003=1 RVCOPSTATE.S.A0004=1 RVCOPSTATE.S.A0005=1 - -#Commands +RVCOPSTATE.S.E00=1 +RVCOPSTATE.S.E01=1 RVCOPSTATE.S.C00.Rsp=1 RVCOPSTATE.S.C01.Rsp=0 RVCOPSTATE.S.C02.Rsp=0 RVCOPSTATE.S.C03.Rsp=1 RVCOPSTATE.S.C04.Tx=1 RVCOPSTATE.S.C128.Rsp=1 -RVCOPSTATE.C.C00.Tx=1 -RVCOPSTATE.C.C01.Tx=1 -RVCOPSTATE.C.C02.Tx=1 -RVCOPSTATE.C.C04.Tx=1 - +RVCOPSTATE.S.M.ST_STOPPED=1 +RVCOPSTATE.S.M.ST_RUNNING=1 +RVCOPSTATE.S.M.ST_PAUSED=1 +RVCOPSTATE.S.M.ST_ERROR=1 +RVCOPSTATE.S.M.ST_SEEKING_CHARGER=1 +RVCOPSTATE.S.M.ST_CHARGING=1 +RVCOPSTATE.S.M.ST_DOCKED=1 +RVCOPSTATE.S.M.ERR_NO_ERROR=1 +RVCOPSTATE.S.M.ERR_UNABLE_TO_START_OR_RESUME=1 +RVCOPSTATE.S.M.ERR_UNABLE_TO_COMPLETE_OPERATION=1 +RVCOPSTATE.S.M.ERR_COMMAND_INVALID_IN_STATE=1 +RVCOPSTATE.S.M.ERR_FAILED_TO_FIND_CHARGING_DOCK=1 +RVCOPSTATE.S.M.ERR_STUCK=1 +RVCOPSTATE.S.M.ERR_DUST_BIN_MISSING=1 +RVCOPSTATE.S.M.ERR_DUST_BIN_FULL=1 +RVCOPSTATE.S.M.ERR_WATER_TANK_EMPTY=1 +RVCOPSTATE.S.M.ERR_WATER_TANK_MISSING=1 +RVCOPSTATE.S.M.ERR_WATER_TANK_LID_OPEN=1 +RVCOPSTATE.S.M.ERR_MOP_CLEANING_PAD_MISSING=1 +RVCOPSTATE.C=0 +RVCOPSTATE.C.C00.Tx=0 +RVCOPSTATE.C.C01.Tx=0 +RVCOPSTATE.C.C02.Tx=0 +RVCOPSTATE.C.C04.Tx=0 -# RVC RUN MODE CLUSTER RVCRUNM.S=1 -RVCRUNM.S.F00=0 - -#Server RVCRUNM.S.A0000=1 RVCRUNM.S.A0001=1 - -#Commands RVCRUNM.S.C00.Rsp=1 RVCRUNM.S.C01.Tx=1 - +RVCRUNM.S.F00=0 RVCRUNM.S.M.CAN_TEST_MODE_FAILURE=1 RVCRUNM.S.M.CAN_MANUALLY_CONTROLLED=1 -#PIXIT -PIXIT.RVCRUNM.MODE_CHANGE_FAIL=1 -PIXIT.RVCRUNM.MODE_CHANGE_OK=1 +# These are useless as these values are set where the python tests are run. +# They are only here because a list test wants then to be. +PIXIT.RVCCLEANM.MODE_CHANGE_FAIL=0 +PIXIT.RVCCLEANM.MODE_CHANGE_OK=0 +PIXIT.RVCRUNM.MODE_CHANGE_FAIL=0 +PIXIT.RVCRUNM.MODE_CHANGE_OK=0 + +# These are the RVC PICS for the all-clustrs-app. +# These PICS are commented out because the yaml tests are being run against the rvc-app. +# RVCCLEANM.S=1 +# RVCCLEANM.S.A0000=1 +# RVCCLEANM.S.A0001=1 +# RVCCLEANM.S.F00=0 +# RVCCLEANM.S.C00.Rsp=1 +# RVCCLEANM.S.C01.Tx=1 +# RVCCLEANM.S.M.CAN_TEST_MODE_FAILURE=1 + +# RVCOPSTATE.S=1 +# RVCOPSTATE.C=1 +# RVCOPSTATE.S.M.ST_STOPPED=1 +# RVCOPSTATE.S.M.ST_RUNNING=1 +# RVCOPSTATE.S.M.ST_PAUSED=1 +# RVCOPSTATE.S.M.ST_ERROR=0 +# RVCOPSTATE.S.M.ST_SEEKING_CHARGER=0 +# RVCOPSTATE.S.M.ST_CHARGING=0 +# RVCOPSTATE.S.M.ST_DOCKED=0 +# RVCOPSTATE.S.M.ERR_NO_ERROR=1 +# RVCOPSTATE.S.M.ERR_UNABLE_TO_START_OR_RESUME=0 +# RVCOPSTATE.S.M.ERR_UNABLE_TO_COMPLETE_OPERATION=0 +# RVCOPSTATE.S.M.ERR_COMMAND_INVALID_IN_STATE=0 +# RVCOPSTATE.S.M.ERR_FAILED_TO_FIND_CHARGING_DOCK=0 +# RVCOPSTATE.S.M.ERR_STUCK=0 +# RVCOPSTATE.S.M.ERR_DUST_BIN_MISSING=0 +# RVCOPSTATE.S.M.ERR_DUST_BIN_FULL=0 +# RVCOPSTATE.S.M.ERR_WATER_TANK_EMPTY=0 +# RVCOPSTATE.S.M.ERR_WATER_TANK_MISSING=0 +# RVCOPSTATE.S.M.ERR_WATER_TANK_LID_OPEN=0 +# RVCOPSTATE.S.M.ERR_MOP_CLEANING_PAD_MISSING=0 +# RVCOPSTATE.S.E00=1 +# RVCOPSTATE.S.E01=1 +# RVCOPSTATE.S.A0000=1 +# RVCOPSTATE.S.A0001=1 +# RVCOPSTATE.S.A0002=1 +# RVCOPSTATE.S.A0003=1 +# RVCOPSTATE.S.A0004=1 +# RVCOPSTATE.S.A0005=1 +# RVCOPSTATE.S.C00.Rsp=1 +# RVCOPSTATE.S.C01.Rsp=0 +# RVCOPSTATE.S.C02.Rsp=0 +# RVCOPSTATE.S.C03.Rsp=1 +# RVCOPSTATE.S.C04.Tx=1 +# RVCOPSTATE.S.C128.Rsp=1 +# RVCOPSTATE.C.C00.Tx=1 +# RVCOPSTATE.C.C01.Tx=1 +# RVCOPSTATE.C.C02.Tx=1 +# RVCOPSTATE.C.C04.Tx=1 + +# RVCRUNM.S=1 +# RVCRUNM.S.F00=0 +# RVCRUNM.S.A0000=1 +# RVCRUNM.S.A0001=1 +# RVCRUNM.S.C00.Rsp=1 +# RVCRUNM.S.C01.Tx=1 +# RVCRUNM.S.M.CAN_TEST_MODE_FAILURE=1 +# RVCRUNM.S.M.CAN_MANUALLY_CONTROLLED=1 + #Refrigerator and Temperature Controlled Cabinet Mode Cluster(TCCM) @@ -2839,59 +2877,112 @@ OTCCM.S.C01.Tx=0 #Manual controllable OTCCM.S.M.CAN_TEST_MODE_FAILURE=0 OTCCM.S.M.CAN_MANUALLY_CONTROLLED=0 +OTCCM.S.M.CAN_MANUALLY_CONTROLLED=0 #Energy EVSE Cluster EEVSE.S=0 -EEVSE.S.A0000=0 -EEVSE.S.A0001=0 -EEVSE.S.A0002=0 -EEVSE.S.A0003=0 -EEVSE.S.A0004=0 -EEVSE.S.A0005=0 -EEVSE.S.A0006=0 -EEVSE.S.A0007=0 -EEVSE.S.A0008=0 -EEVSE.S.A0009=0 -EEVSE.S.A000A=0 -EEVSE.S.A0023=0 -EEVSE.S.A0024=0 -EEVSE.S.A0025=0 -EEVSE.S.A0026=0 -EEVSE.S.A0027=0 -EEVSE.S.A0030=0 -EEVSE.S.A0031=0 -EEVSE.S.A0032=0 -EEVSE.S.A0040=0 -EEVSE.S.A0041=0 -EEVSE.S.A0042=0 -EEVSE.S.A0043=0 +EEVSE.S.A0000=1 +EEVSE.S.A0001=1 +EEVSE.S.A0002=1 +EEVSE.S.A0003=1 +EEVSE.S.A0004=1 +EEVSE.S.A0005=1 +EEVSE.S.A0006=1 +EEVSE.S.A0007=1 +EEVSE.S.A0008=1 +EEVSE.S.A0009=1 +EEVSE.S.A000A=1 +EEVSE.S.A0023=1 +EEVSE.S.A0024=1 +EEVSE.S.A0025=1 +EEVSE.S.A0026=1 +EEVSE.S.A0027=1 +EEVSE.S.A0030=1 +EEVSE.S.A0031=1 +EEVSE.S.A0032=1 +EEVSE.S.A0040=1 +EEVSE.S.A0041=1 +EEVSE.S.A0042=1 +EEVSE.S.A0043=1 #Commands received -EEVSE.S.C01.Rsp=0 -EEVSE.S.C02.Rsp=0 -EEVSE.S.C03.Rsp=0 -EEVSE.S.C04.Rsp=0 -EEVSE.S.C05.Rsp=0 -EEVSE.S.C06.Rsp=0 -EEVSE.S.C07.Rsp=0 +EEVSE.S.C01.Rsp=1 +EEVSE.S.C02.Rsp=1 +EEVSE.S.C03.Rsp=1 +EEVSE.S.C04.Rsp=1 +EEVSE.S.C05.Rsp=1 +EEVSE.S.C06.Rsp=1 +EEVSE.S.C07.Rsp=1 # Commands generated -EEVSE.S.C00.Tx=0 +EEVSE.S.C00.Tx=1 #Manual controllable -EEVSE.S.M.ManuallyControlledPluggedIn=0 +EEVSE.S.M.ManuallyControlledPluggedIn=1 #Features -EEVSE.S.F00=0 -EEVSE.S.F01=0 -EEVSE.S.F02=0 -EEVSE.S.F03=0 -EEVSE.S.F04=0 +EEVSE.S.F00=1 +EEVSE.S.F01=1 +EEVSE.S.F02=1 +EEVSE.S.F03=1 +EEVSE.S.F04=1 #Events -EEVSE.S.E00=0 -EEVSE.S.E01=0 -EEVSE.S.E02=0 -EEVSE.S.E03=0 -EEVSE.S.E04=0 -EEVSE.S.E05=0 +EEVSE.S.E00=1 +EEVSE.S.E01=1 +EEVSE.S.E02=1 +EEVSE.S.E03=1 +EEVSE.S.E04=1 +EEVSE.S.E05=1 + +# Energy EVSE Mode Cluster + +#Feature +EEVSEM.S.F00=1 +#Server +EEVSEM.S=1 +EEVSEM.S.A0000=1 +EEVSEM.S.A0001=1 +EEVSEM.S.A0002=0 +EEVSEM.S.A0003=0 + +#Commands received +EEVSEM.S.C00.Rsp=1 + +#Commands generated +EEVSEM.S.C01.Tx=1 + +#Manual controllable +EEVSEM.S.M.CAN_TEST_MODE_FAILURE=1 +EEVSEM.S.M.CAN_MANUALLY_CONTROLLED=1 + +# Device Energy Management Mode Cluster + +#Server +DEMM.S=1 +DEMM.S.A0000=1 +DEMM.S.A0001=1 +DEMM.S.A0002=0 +DEMM.S.A0003=1 + +#Commands received +DEMM.S.C00.Rsp=1 + +#Commands generated +DEMM.S.C01.Tx=1 + +#Manual controllable +DEMM.S.M.CAN_TEST_MODE_FAILURE=1 +DEMM.S.M.CAN_MANUALLY_CONTROLLED=1 + +#Power Topology Cluster +# Server +PWRTL.S=1 +PWRTL.S.A0000=1 +PWRTL.S.A0001=1 + +#Features +PWRTL.S.F00=0 +PWRTL.S.F01=0 +PWRTL.S.F02=1 +PWRTL.S.F03=1 \ No newline at end of file diff --git a/src/app/tests/suites/ciTests.json b/src/app/tests/suites/ciTests.json index cbd655299f8422..26efd799ad7efd 100644 --- a/src/app/tests/suites/ciTests.json +++ b/src/app/tests/suites/ciTests.json @@ -50,12 +50,21 @@ "Test_TC_CNET_1_3" ], "Descriptor": ["Test_TC_DESC_1_1"], + "DeviceEnergyManagementMode": ["Test_TC_DEMM_1_1", "Test_TC_DEMM_2_1"], "EthernetNetworkDiagnostics": [ "Test_TC_DGETH_1_1", "Test_TC_DGETH_2_1", "Test_TC_DGETH_2_2" ], "DiagnosticsLogs": ["Test_TC_DLOG_1_1"], + "EnergyEVSE": ["Test_TC_EEVSE_1_1", "Test_TC_EEVSE_2_1"], + "EnergyEVSEMode": [ + "Test_TC_EEVSEM_1_1", + "Test_TC_EEVSEM_2_1", + "Test_TC_EEVSEM_3_1", + "Test_TC_EEVSEM_3_2", + "Test_TC_EEVSEM_3_3" + ], "FlowMeasurement": ["Test_TC_FLW_1_1", "Test_TC_FLW_2_1"], "FixedLabel": ["Test_TC_FLABEL_1_1", "Test_TC_FLABEL_2_1"], "FanControl": [ @@ -69,7 +78,11 @@ "GeneralCommissioning": ["Test_TC_CGEN_1_1", "Test_TC_CGEN_2_1"], "GeneralDiagnostics": ["Test_TC_DGGEN_1_1"], "GroupKeyManagement": ["Test_TC_GRPKEY_1_1", "Test_TC_GRPKEY_2_2"], - "IcdManagement": ["TestIcdManagementCluster", "Test_TC_ICDM_1_1"], + "IcdManagement": [ + "TestIcdManagementCluster", + "Test_TC_ICDM_1_1", + "Test_TC_ICDM_3_4" + ], "Identify": [ "Test_TC_I_1_1", "Test_TC_I_2_1", @@ -178,6 +191,7 @@ "Test_TC_OO_2_4" ], "PowerSource": ["Test_TC_PS_1_1", "Test_TC_PS_2_1"], + "PowerTopology": ["Test_TC_PWRTL_1_1"], "PressureMeasurement": [ "Test_TC_PRS_1_1", "Test_TC_PRS_2_1", @@ -339,6 +353,7 @@ "TestScenesFabricRemoval", "TestScenesFabricSceneInfo", "TestScenesMultiFabric", + "TestScenesMaxCapacity", "Test_TC_S_1_1", "Test_TC_S_2_1", "Test_TC_S_2_2", @@ -388,9 +403,12 @@ "ConcentrationMeasurement", "ContentAppObserver", "DeviceManagement", + "DeviceEnergyManagementMode", "Descriptor", "DiagnosticsLogs", "EthernetNetworkDiagnostics", + "EnergyEVSE", + "EnergyEVSEMode", "FlowMeasurement", "FixedLabel", "FanControl", diff --git a/src/app/tests/suites/manualTests.json b/src/app/tests/suites/manualTests.json index 1c66bfccfbb9b0..d199a682492150 100644 --- a/src/app/tests/suites/manualTests.json +++ b/src/app/tests/suites/manualTests.json @@ -113,6 +113,8 @@ "Test_TC_DLOG_3_1" ], "Descriptor": ["Test_TC_DESC_2_1"], + "DeviceEnergyManagementMode": ["Test_TC_DEMM_1_2"], + "EnergyEVSEMode": ["Test_TC_EEVSEM_1_2"], "FanControl": [], "GeneralCommissioning": ["Test_TC_CGEN_2_2"], "GeneralDiagnostics": ["Test_TC_DGGEN_2_2"], @@ -122,7 +124,6 @@ "Test_TC_ICDM_3_1", "Test_TC_ICDM_3_2", "Test_TC_ICDM_3_3", - "Test_TC_ICDM_3_4", "Test_TC_ICDM_4_1", "Test_TC_ICDM_5_1" ], @@ -261,7 +262,7 @@ "FlowMeasurement": ["Test_TC_FLW_2_2"], "GroupKeyManagement": ["Test_TC_GRPKEY_5_4"], "OccupancySensing": ["Test_TC_OCC_3_1"], - "PowerSource": ["Test_TC_PS_2_2", "Test_TC_PS_3_1"], + "PowerSource": ["Test_TC_PS_2_2"], "BooleanState": ["Test_TC_BOOL_2_2"], "ColorControl": [ "Test_TC_CC_3_1", @@ -310,6 +311,7 @@ "AccessControlEnforcement": [], "OvenMode": ["Test_TC_OTCCM_1_1", "Test_TC_OTCCM_1_2"], "EnergyEVSE": ["Test_TC_EEVSE_1_1", "Test_TC_EEVSE_2_1"], + "PowerTopology": ["Test_TC_PWRTL_1_1"], "collection": [ "DeviceDiscovery", "Groups", @@ -321,9 +323,11 @@ "DishwasherAlarm", "DishwasherMode", "Descriptor", + "DeviceEnergyManagementMode", "FanControl", "EthernetNetworkDiagnostics", "EnergyEVSE", + "EnergyEVSEMode", "GeneralCommissioning", "GeneralDiagnostics", "IcdManagement", @@ -335,6 +339,7 @@ "ModeSelect", "OTASoftwareUpdate", "PowerSourceConfiguration", + "PowerTopology", "PressureMeasurement", "SecureChannel", "SoftwareDiagnostics", diff --git a/src/app/util/BUILD.gn b/src/app/util/BUILD.gn index 31d6b9e881956a..821ba51a9badcc 100644 --- a/src/app/util/BUILD.gn +++ b/src/app/util/BUILD.gn @@ -14,3 +14,11 @@ import("//build_overrides/chip.gni") import("${chip_root}/src/app/common_flags.gni") + +source_set("types") { + sources = [ + "attribute-metadata.h", + "basic-types.h", + "types_stub.h", + ] +} diff --git a/src/app/util/mock/BUILD.gn b/src/app/util/mock/BUILD.gn index 5918318107fd35..be56bc69032844 100644 --- a/src/app/util/mock/BUILD.gn +++ b/src/app/util/mock/BUILD.gn @@ -20,7 +20,10 @@ config("mock_include") { source_set("mock_ember") { sources = [ + "Constants.h", + "Functions.h", "MockNodeConfig.cpp", + "MockNodeConfig.h", "attribute-storage.cpp", ] diff --git a/src/app/util/util.cpp b/src/app/util/util.cpp index 267da8921574d8..e327673fc3cbf4 100644 --- a/src/app/util/util.cpp +++ b/src/app/util/util.cpp @@ -167,8 +167,10 @@ void MatterDishwasherAlarmPluginServerInitCallback() {} void MatterMicrowaveOvenModePluginServerInitCallback() {} void MatterDeviceEnergyManagementModePluginServerInitCallback() {} void MatterEnergyEvseModePluginServerInitCallback() {} +void MatterPowerTopologyPluginServerInitCallback() {} void MatterElectricalEnergyMeasurementPluginServerInitCallback() {} void MatterElectricalPowerMeasurementPluginServerInitCallback() {} + // **************************************** // Print out information about each cluster // **************************************** diff --git a/src/app/zap-templates/zcl/data-model/all.xml b/src/app/zap-templates/zcl/data-model/all.xml index 255be8b0328e1b..86d2085718291d 100644 --- a/src/app/zap-templates/zcl/data-model/all.xml +++ b/src/app/zap-templates/zcl/data-model/all.xml @@ -72,6 +72,7 @@ + diff --git a/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml index ad6279b2ef65e2..c2deff336eae46 100644 --- a/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml @@ -73,7 +73,7 @@ limitations under the License. - + Fan Control HVAC An interface for controlling a fan in a heating/cooling system. diff --git a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml index 037c660d1d6f8c..259a59dae3ead5 100644 --- a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml +++ b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml @@ -117,6 +117,7 @@ limitations under the License. Node + 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 2800e14197008c..5bae212dc6d50c 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -630,6 +630,7 @@ "NeutralCurrent", "FeatureMap" ], + "Power Topology": ["FeatureMap"], "Valve Configuration and Control": ["RemainingDuration"], "Boolean State Configuration": ["CurrentSensitivityLevel"] }, diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index b9e0142011022a..dcfbaf6986c23c 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -628,6 +628,7 @@ "NeutralCurrent", "FeatureMap" ], + "Power Topology": ["FeatureMap"], "Valve Configuration and Control": ["RemainingDuration"], "Boolean State Configuration": ["CurrentSensitivityLevel"] }, diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index db22d6c2ab5e77..56adf0a1126f95 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -68,7 +68,6 @@ "MESSAGES_CLUSTER": [], "MODE_SELECT_CLUSTER": [], "NETWORK_COMMISSIONING_CLUSTER": [], - "POWER_TOPOLOGY_CLUSTER": [], "SAMPLE_MEI_CLUSTER": [], "NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER": [], "OCCUPANCY_SENSING_CLUSTER": ["occupancy-sensor-server"], @@ -91,6 +90,7 @@ "POWER_PROFILE_CLUSTER": [], "POWER_SOURCE_CLUSTER": [], "POWER_SOURCE_CONFIGURATION_CLUSTER": [], + "POWER_TOPOLOGY_CLUSTER": [], "PRESSURE_MEASUREMENT_CLUSTER": [], "PROXY_CONFIGURATION_CLUSTER": [], "PROXY_DISCOVERY_CLUSTER": [], @@ -228,7 +228,7 @@ "SAMPLE_MEI_CLUSTER": ["sample-mei-server"], "OCCUPANCY_SENSING_CLUSTER": ["occupancy-sensor-server"], "ON_OFF_CLUSTER": ["on-off-server"], - "POWER_TOPOLOGY_CLUSTER": [], + "POWER_TOPOLOGY_CLUSTER": ["power-topology-server"], "ON_OFF_SWITCH_CONFIGURATION_CLUSTER": [], "OPERATIONAL_CREDENTIALS_CLUSTER": ["operational-credentials-server"], "OPERATIONAL_STATE_CLUSTER": ["operational-state-server"], diff --git a/src/ble/BLEEndPoint.cpp b/src/ble/BLEEndPoint.cpp index 8d68c68ec0b0d8..63708af678efbd 100644 --- a/src/ble/BLEEndPoint.cpp +++ b/src/ble/BLEEndPoint.cpp @@ -1040,6 +1040,7 @@ CHIP_ERROR BLEEndPoint::DriveSending() else { // Nothing to send! + mBle->mApplicationDelegate->CheckNonConcurrentBleClosing(); } } diff --git a/src/ble/BleApplicationDelegate.h b/src/ble/BleApplicationDelegate.h index 542e46b64c4888..2584aeb6b908fd 100644 --- a/src/ble/BleApplicationDelegate.h +++ b/src/ble/BleApplicationDelegate.h @@ -42,6 +42,10 @@ class DLL_EXPORT BleApplicationDelegate // The application can use this callback to e.g. close the underlying BLE connection if it is no longer needed, // decrement the connection's refcount if it has one, or perform any other sort of cleanup as desired. virtual void NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT connObj) = 0; + + // Called to determine whether the BLE connection should be closed when in Non-concurrent mode if sending + // ConnectNetworkResponse. The BTP will be in kState_Complete when all fragments have been sent. + virtual void CheckNonConcurrentBleClosing() {} }; } /* namespace Ble */ diff --git a/src/ble/BleLayer.cpp b/src/ble/BleLayer.cpp index 9109924ccd3754..eae49a0bfa8dd1 100644 --- a/src/ble/BleLayer.cpp +++ b/src/ble/BleLayer.cpp @@ -300,6 +300,11 @@ CHIP_ERROR BleLayer::Init(BlePlatformDelegate * platformDelegate, BleApplication return Init(platformDelegate, nullptr, appDelegate, systemLayer); } +void BleLayer::IndicateBleClosing() +{ + mState = kState_Disconnecting; +} + void BleLayer::Shutdown() { mState = kState_NotInitialized; diff --git a/src/ble/BleLayer.h b/src/ble/BleLayer.h index 5ded6c82cc2b46..f175334173ba7f 100644 --- a/src/ble/BleLayer.h +++ b/src/ble/BleLayer.h @@ -226,7 +226,8 @@ class DLL_EXPORT BleLayer enum { kState_NotInitialized = 0, - kState_Initialized = 1 + kState_Initialized = 1, + kState_Disconnecting = 2 } mState; ///< [READ-ONLY] Current state // This app state is not used by ble transport etc, it will be used by external ble implementation like Android @@ -243,6 +244,7 @@ class DLL_EXPORT BleLayer chip::System::Layer * systemLayer); CHIP_ERROR Init(BlePlatformDelegate * platformDelegate, BleConnectionDelegate * connDelegate, BleApplicationDelegate * appDelegate, chip::System::Layer * systemLayer); + void IndicateBleClosing(); void Shutdown(); CHIP_ERROR CancelBleIncompleteConnection(); diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 7cc2c86432f5f9..57c75cd0d813ae 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -1636,27 +1636,6 @@ void OnBasicFailure(void * context, CHIP_ERROR error) commissioner->CommissioningStageComplete(error); } -static void NonConcurrentTimeout(void * context, CHIP_ERROR error) -{ - if (error == CHIP_ERROR_TIMEOUT) - { - ChipLogProgress(Controller, "Non-concurrent mode: Expected NetworkResponse Timeout, do nothing"); - } - else - { - ChipLogProgress(Controller, "Non-concurrent mode: Received failure response %" CHIP_ERROR_FORMAT, error.Format()); - } -} - -static void NonConcurrentNetworkResponse(void * context, - const NetworkCommissioning::Commands::ConnectNetworkResponse::DecodableType & data) -{ - // In Non Concurrent mode the commissioning network should have been shut down and not sent the - // ConnectNetworkResponse. In case it does send it this handles the message - ChipLogError(Controller, "Non-concurrent Mode : Received Unexpected ConnectNetwork response, ignoring. Status=%u", - to_underlying(data.networkingStatus)); -} - void DeviceCommissioner::CleanupCommissioning(DeviceProxy * proxy, NodeId nodeId, const CompletionStatus & completionStatus) { commissioningCompletionStatus = completionStatus; @@ -3061,28 +3040,9 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio request.breadcrumb.Emplace(breadcrumb); CHIP_ERROR err = CHIP_NO_ERROR; - GeneralCommissioning::Attributes::SupportsConcurrentConnection::TypeInfo::Type supportsConcurrentConnection; - supportsConcurrentConnection = params.GetSupportsConcurrentConnection().Value(); ChipLogProgress(Controller, "SendCommand kWiFiNetworkEnable, supportsConcurrentConnection=%d", - supportsConcurrentConnection); - if (supportsConcurrentConnection) - { - err = SendCommand(proxy, request, OnConnectNetworkResponse, OnBasicFailure, endpoint, timeout); - } - else - { - // Concurrent Connections not allowed. Send the ConnectNetwork command but do not wait for the - // ConnectNetworkResponse on the Commissioning network as it will not be present. Log the expected timeout - // and run what would have been in the onConnectNetworkResponse callback. - err = SendCommand(proxy, request, NonConcurrentNetworkResponse, NonConcurrentTimeout, endpoint, NullOptional); - if (err == CHIP_NO_ERROR) - { - // As there will be no ConnectNetworkResponse, it is an implicit kSuccess so a default report is fine - CommissioningDelegate::CommissioningReport report; - CommissioningStageComplete(CHIP_NO_ERROR, report); - return; - } - } + params.GetSupportsConcurrentConnection().Value()); + err = SendCommand(proxy, request, OnConnectNetworkResponse, OnBasicFailure, endpoint, timeout); if (err != CHIP_NO_ERROR) { diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index b9ce299a283f57..89864630b8e85e 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -6474,7 +6474,7 @@ cluster Thermostat = 513 { } /** An interface for controlling a fan in a heating/cooling system. */ -provisional cluster FanControl = 514 { +cluster FanControl = 514 { revision 4; enum AirflowDirectionEnum : enum8 { diff --git a/src/controller/data_model/controller-clusters.zap b/src/controller/data_model/controller-clusters.zap index 02a58c61ee3c09..42753ed88f84b4 100644 --- a/src/controller/data_model/controller-clusters.zap +++ b/src/controller/data_model/controller-clusters.zap @@ -3314,6 +3314,48 @@ } ] }, + { + "name": "Power Topology", + "code": 156, + "mfgCode": null, + "define": "POWER_TOPOLOGY_CLUSTER", + "side": "client", + "enabled": 1, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Energy EVSE Mode", "code": 157, diff --git a/src/controller/java/AndroidCallbacks-JNI.cpp b/src/controller/java/AndroidCallbacks-JNI.cpp index f0da85a3c6d29e..c87b669f9b521f 100644 --- a/src/controller/java/AndroidCallbacks-JNI.cpp +++ b/src/controller/java/AndroidCallbacks-JNI.cpp @@ -28,66 +28,44 @@ using namespace chip::Controller; JNI_METHOD(jlong, GetConnectedDeviceCallbackJni, newCallback)(JNIEnv * env, jobject self, jobject callback) { - chip::DeviceLayer::StackLock lock; - GetConnectedDeviceCallback * connectedDeviceCallback = chip::Platform::New(self, callback); - return reinterpret_cast(connectedDeviceCallback); + return newConnectedDeviceCallback(env, self, callback); } JNI_METHOD(void, GetConnectedDeviceCallbackJni, deleteCallback)(JNIEnv * env, jobject self, jlong callbackHandle) { - chip::DeviceLayer::StackLock lock; - GetConnectedDeviceCallback * connectedDeviceCallback = reinterpret_cast(callbackHandle); - VerifyOrReturn(connectedDeviceCallback != nullptr, ChipLogError(Controller, "GetConnectedDeviceCallback handle is nullptr")); - chip::Platform::Delete(connectedDeviceCallback); + deleteConnectedDeviceCallback(env, self, callbackHandle); } JNI_METHOD(jlong, ReportCallbackJni, newCallback) -(JNIEnv * env, jobject self, jobject subscriptionEstablishedCallbackJava, jobject reportCallbackJava, - jobject resubscriptionAttemptCallbackJava) +(JNIEnv * env, jobject self, jobject subscriptionEstablishedCallbackJava, jobject resubscriptionAttemptCallbackJava) { - chip::DeviceLayer::StackLock lock; - ReportCallback * reportCallback = chip::Platform::New(self, subscriptionEstablishedCallbackJava, - reportCallbackJava, resubscriptionAttemptCallbackJava); - return reinterpret_cast(reportCallback); + return newReportCallback(env, self, subscriptionEstablishedCallbackJava, resubscriptionAttemptCallbackJava, + "()Lchip/devicecontroller/model/NodeState;"); } JNI_METHOD(void, ReportCallbackJni, deleteCallback)(JNIEnv * env, jobject self, jlong callbackHandle) { - chip::DeviceLayer::StackLock lock; - ReportCallback * reportCallback = reinterpret_cast(callbackHandle); - VerifyOrReturn(reportCallback != nullptr, ChipLogError(Controller, "ReportCallback handle is nullptr")); - chip::Platform::Delete(reportCallback); + deleteReportCallback(env, self, callbackHandle); } JNI_METHOD(jlong, WriteAttributesCallbackJni, newCallback) -(JNIEnv * env, jobject self, jobject writeAttributesCallbackJava) +(JNIEnv * env, jobject self) { - chip::DeviceLayer::StackLock lock; - WriteAttributesCallback * writeAttributesCallback = - chip::Platform::New(self, writeAttributesCallbackJava); - return reinterpret_cast(writeAttributesCallback); + return newWriteAttributesCallback(env, self); } JNI_METHOD(void, WriteAttributesCallbackJni, deleteCallback)(JNIEnv * env, jobject self, jlong callbackHandle) { - chip::DeviceLayer::StackLock lock; - WriteAttributesCallback * writeAttributesCallback = reinterpret_cast(callbackHandle); - VerifyOrReturn(writeAttributesCallback != nullptr, ChipLogError(Controller, "WriteAttributesCallback handle is nullptr")); - chip::Platform::Delete(writeAttributesCallback); + deleteWriteAttributesCallback(env, self, callbackHandle); } JNI_METHOD(jlong, InvokeCallbackJni, newCallback) -(JNIEnv * env, jobject self, jobject invokeCallbackJava) +(JNIEnv * env, jobject self) { - chip::DeviceLayer::StackLock lock; - InvokeCallback * invokeCallback = chip::Platform::New(self, invokeCallbackJava); - return reinterpret_cast(invokeCallback); + return newInvokeCallback(env, self); } JNI_METHOD(void, InvokeCallbackJni, deleteCallback)(JNIEnv * env, jobject self, jlong callbackHandle) { - chip::DeviceLayer::StackLock lock; - InvokeCallback * invokeCallback = reinterpret_cast(callbackHandle); - VerifyOrReturn(invokeCallback != nullptr, ChipLogError(Controller, "InvokeCallback handle is nullptr")); - chip::Platform::Delete(invokeCallback); + deleteInvokeCallback(env, self, callbackHandle); } diff --git a/src/controller/java/AndroidCallbacks.cpp b/src/controller/java/AndroidCallbacks.cpp index 9e3e3e966c20d3..01ef820f82c6ed 100644 --- a/src/controller/java/AndroidCallbacks.cpp +++ b/src/controller/java/AndroidCallbacks.cpp @@ -41,22 +41,10 @@ static const int MILLIS_SINCE_EPOCH = 1; // Add the bytes for attribute tag(1:control + 8:tag + 8:length) and structure(1:struct + 1:close container) static const int EXTRA_SPACE_FOR_ATTRIBUTE_TAG = 19; -CHIP_ERROR CreateChipAttributePath(JNIEnv * env, const app::ConcreteDataAttributePath & aPath, jobject & outObj) -{ - jclass attributePathCls = nullptr; - ReturnErrorOnFailure( - JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/model/ChipAttributePath", attributePathCls)); - jmethodID attributePathCtor = - env->GetStaticMethodID(attributePathCls, "newInstance", "(IJJ)Lchip/devicecontroller/model/ChipAttributePath;"); - VerifyOrReturnError(attributePathCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); - outObj = env->CallStaticObjectMethod(attributePathCls, attributePathCtor, static_cast(aPath.mEndpointId), - static_cast(aPath.mClusterId), static_cast(aPath.mAttributeId)); - VerifyOrReturnError(outObj != nullptr, CHIP_JNI_ERROR_NULL_OBJECT); - return CHIP_NO_ERROR; -} - -GetConnectedDeviceCallback::GetConnectedDeviceCallback(jobject wrapperCallback, jobject javaCallback) : - mOnSuccess(OnDeviceConnectedFn, this), mOnFailure(OnDeviceConnectionFailureFn, this) +GetConnectedDeviceCallback::GetConnectedDeviceCallback(jobject wrapperCallback, jobject javaCallback, + const char * callbackClassSignature) : + mOnSuccess(OnDeviceConnectedFn, this), + mOnFailure(OnDeviceConnectionFailureFn, this), mCallbackClassSignature(callbackClassSignature) { VerifyOrReturn(mWrapperCallbackRef.Init(wrapperCallback) == CHIP_NO_ERROR, ChipLogError(Controller, "Could not init mWrapperCallbackRef in %s", __func__)); @@ -82,13 +70,15 @@ void GetConnectedDeviceCallback::OnDeviceConnectedFn(void * context, Messaging:: JniGlobalReference globalRef(std::move(self->mWrapperCallbackRef)); jclass getConnectedDeviceCallbackCls = nullptr; - JniReferences::GetInstance().GetLocalClassRef( - env, "chip/devicecontroller/GetConnectedDeviceCallbackJni$GetConnectedDeviceCallback", getConnectedDeviceCallbackCls); + CHIP_ERROR err = + JniReferences::GetInstance().GetLocalClassRef(env, self->mCallbackClassSignature, getConnectedDeviceCallbackCls); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "GetLocalClassRef Error! : %" CHIP_ERROR_FORMAT, err.Format())); VerifyOrReturn(getConnectedDeviceCallbackCls != nullptr, ChipLogError(Controller, "Could not find GetConnectedDeviceCallback class")); jmethodID successMethod; - JniReferences::GetInstance().FindMethod(env, javaCallback, "onDeviceConnected", "(J)V", &successMethod); + err = JniReferences::GetInstance().FindMethod(env, javaCallback, "onDeviceConnected", "(J)V", &successMethod); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "FindMethod Error! : %" CHIP_ERROR_FORMAT, err.Format())); VerifyOrReturn(successMethod != nullptr, ChipLogError(Controller, "Could not find onDeviceConnected method")); static_assert(sizeof(jlong) >= sizeof(void *), "Need to store a pointer in a Java handle"); @@ -111,17 +101,20 @@ void GetConnectedDeviceCallback::OnDeviceConnectionFailureFn(void * context, JniLocalReferenceScope scope(env); jclass getConnectedDeviceCallbackCls = nullptr; - JniReferences::GetInstance().GetLocalClassRef( - env, "chip/devicecontroller/GetConnectedDeviceCallbackJni$GetConnectedDeviceCallback", getConnectedDeviceCallbackCls); + CHIP_ERROR err = + JniReferences::GetInstance().GetLocalClassRef(env, self->mCallbackClassSignature, getConnectedDeviceCallbackCls); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "GetLocalClassRef Error! : %" CHIP_ERROR_FORMAT, err.Format())); VerifyOrReturn(getConnectedDeviceCallbackCls != nullptr, ChipLogError(Controller, "Could not find GetConnectedDeviceCallback class")); jmethodID failureMethod; - JniReferences::GetInstance().FindMethod(env, javaCallback, "onConnectionFailure", "(JLjava/lang/Exception;)V", &failureMethod); + err = JniReferences::GetInstance().FindMethod(env, javaCallback, "onConnectionFailure", "(JLjava/lang/Exception;)V", + &failureMethod); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "FindMethod Error! : %" CHIP_ERROR_FORMAT, err.Format())); VerifyOrReturn(failureMethod != nullptr, ChipLogError(Controller, "Could not find onConnectionFailure method")); jthrowable exception; - CHIP_ERROR err = AndroidConnectionFailureExceptions::GetInstance().CreateAndroidConnectionFailureException( + err = AndroidConnectionFailureExceptions::GetInstance().CreateAndroidConnectionFailureException( env, failureInfo.error.Format(), failureInfo.error.AsInteger(), failureInfo.sessionStage, exception); VerifyOrReturn( err == CHIP_NO_ERROR, @@ -133,9 +126,28 @@ void GetConnectedDeviceCallback::OnDeviceConnectionFailureFn(void * context, VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } -ReportCallback::ReportCallback(jobject wrapperCallback, jobject subscriptionEstablishedCallback, jobject reportCallback, - jobject resubscriptionAttemptCallback) : - mClusterCacheAdapter(*this, Optional::Missing(), false /*cacheData*/) +CHIP_ERROR CreateOptional(chip::Optional value, jobject & outObj) +{ + + return CHIP_NO_ERROR; +} +jobject GetNodeStateObj(JNIEnv * env, const char * nodeStateClassSignature, jobject wrapperCallback) +{ + jmethodID getNodeStateMethod; + CHIP_ERROR err = + JniReferences::GetInstance().FindMethod(env, wrapperCallback, "getNodeState", nodeStateClassSignature, &getNodeStateMethod); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, ChipLogError(Controller, "Could not find getNodeState method")); + + jobject ret = env->CallObjectMethod(wrapperCallback, getNodeStateMethod); + VerifyOrReturnValue(!env->ExceptionCheck(), nullptr, env->ExceptionDescribe()); + + return ret; +} + +ReportCallback::ReportCallback(jobject wrapperCallback, jobject subscriptionEstablishedCallback, + jobject resubscriptionAttemptCallback, const char * nodeStateClassSignature) : + mClusterCacheAdapter(*this, Optional::Missing(), false /*cacheData*/), + mNodeStateClassSignature(nodeStateClassSignature) { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); @@ -145,8 +157,6 @@ ReportCallback::ReportCallback(jobject wrapperCallback, jobject subscriptionEsta ChipLogError(Controller, "Could not init mSubscriptionEstablishedCallbackRef in %s", __func__)); } - VerifyOrReturn(mReportCallbackRef.Init(reportCallback) == CHIP_NO_ERROR, - ChipLogError(Controller, "Could not init mReportCallbackRef in %s", __func__)); VerifyOrReturn(mWrapperCallbackRef.Init(wrapperCallback) == CHIP_NO_ERROR, ChipLogError(Controller, "Could not init mWrapperCallbackRef in %s", __func__)); @@ -169,16 +179,19 @@ void ReportCallback::OnReportBegin() { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); + JniLocalReferenceScope scope(env); - jclass nodeStateCls = nullptr; - CHIP_ERROR err = JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/model/NodeState", nodeStateCls); - VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not get NodeState class")); - jmethodID nodeStateCtor = env->GetMethodID(nodeStateCls, "", "()V"); - VerifyOrReturn(nodeStateCtor != nullptr, ChipLogError(Controller, "Could not find NodeState constructor")); - jobject nodeState = env->NewObject(nodeStateCls, nodeStateCtor); - VerifyOrReturn(nodeState != nullptr, ChipLogError(Controller, "Could not create local object for nodeState")); - VerifyOrReturn(mNodeStateObj.Init(nodeState) == CHIP_NO_ERROR, - ChipLogError(Controller, "Could not init mNodeStateObj in %s", __func__)); + + VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), + ChipLogError(Controller, "mReportCallbackRef is not valid in %s", __func__)); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); + jmethodID onReportBeginMethod; + CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onReportBegin", "()V", &onReportBeginMethod); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find onReportBegin method")); + + DeviceLayer::StackUnlock unlock; + env->CallVoidMethod(wrapperCallback, onReportBeginMethod); + VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } void ReportCallback::OnDeallocatePaths(app::ReadPrepareParams && aReadPrepareParams) @@ -213,18 +226,17 @@ void ReportCallback::OnReportEnd() CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); + JniLocalReferenceScope scope(env); - VerifyOrReturn(mReportCallbackRef.HasValidObjectRef(), - ChipLogError(Controller, "mReportCallbackRef is not valid in %s", __func__)); - jobject reportCallback = mReportCallbackRef.ObjectRef(); - JniGlobalReference globalRef(std::move(mNodeStateObj)); - jmethodID onReportMethod; - err = JniReferences::GetInstance().FindMethod(env, reportCallback, "onReport", "(Lchip/devicecontroller/model/NodeState;)V", - &onReportMethod); - VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find onReport method")); + VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), + ChipLogError(Controller, "mWrapperCallbackRef is not valid in %s", __func__)); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); + jmethodID onReportEndMethod; + err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onReportEnd", "()V", &onReportEndMethod); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find onReportEnd method")); DeviceLayer::StackUnlock unlock; - env->CallVoidMethod(reportCallback, onReportMethod, globalRef.ObjectRef()); + env->CallVoidMethod(wrapperCallback, onReportEndMethod); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } @@ -254,59 +266,48 @@ CHIP_ERROR ConvertReportTlvToJson(const uint32_t id, TLV::TLVReader & data, std: return TlvToJson(readerForJson, json); } -static CHIP_ERROR CreateStatus(JNIEnv * env, const app::StatusIB & aStatus, jobject & outObj) -{ - jclass statusCls = nullptr; - ReturnErrorOnFailure(JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/model/Status", statusCls)); - jmethodID statusCtor = nullptr; - if (aStatus.mClusterStatus.HasValue()) - { - statusCtor = env->GetStaticMethodID(statusCls, "newInstance", "(II)Lchip/devicecontroller/model/Status;"); - VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrReturnError(statusCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); - outObj = env->CallStaticObjectMethod(statusCls, statusCtor, static_cast(aStatus.mStatus), - static_cast(aStatus.mClusterStatus.Value())); - } - else - { - statusCtor = env->GetStaticMethodID(statusCls, "newInstance", "(I)Lchip/devicecontroller/model/Status;"); - VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrReturnError(statusCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); - outObj = env->CallStaticObjectMethod(statusCls, statusCtor, static_cast(aStatus.mStatus)); - } - VerifyOrReturnError(outObj != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); - return CHIP_NO_ERROR; -} - void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const app::StatusIB & aStatus) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); JniLocalReferenceScope scope(env); VerifyOrReturn(!aPath.IsListItemOperation(), ChipLogError(Controller, "Expect non-list item operation"); aPath.LogPath()); - jobject nodeState = mNodeStateObj.ObjectRef(); - if (aStatus.IsFailure()) + VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), + ChipLogError(Controller, "mReportCallbackRef is not valid in %s", __func__)); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); + + jobject nodeState = GetNodeStateObj(env, mNodeStateClassSignature, wrapperCallback); + { - ChipLogError(Controller, "Receive bad status %s", ErrorStr(aStatus.ToChipError())); - jobject statusObj = nullptr; - err = CreateStatus(env, aStatus, statusObj); - VerifyOrReturn(err == CHIP_NO_ERROR, - ChipLogError(Controller, "Fail to create status with error %" CHIP_ERROR_FORMAT, err.Format())); - // Add Attribute Status to NodeState + // Add Attribute Status to wrapperCallback jmethodID addAttributeStatusMethod = nullptr; - err = JniReferences::GetInstance().FindMethod(env, nodeState, "addAttributeStatus", - "(IJJLchip/devicecontroller/model/Status;)V", &addAttributeStatusMethod); + err = JniReferences::GetInstance().FindMethod(env, nodeState, "addAttributeStatus", "(IJJILjava/lang/Integer;)V", + &addAttributeStatusMethod); VerifyOrReturn( err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find addAttributeStatus method with error %" CHIP_ERROR_FORMAT, err.Format())); + + jobject jClusterState = nullptr; + if (aStatus.mClusterStatus.HasValue()) + { + err = JniReferences::GetInstance().CreateBoxedObject( + "java/lang/Integer", "(I)V", static_cast(aStatus.mClusterStatus.Value()), jClusterState); + VerifyOrReturn(err == CHIP_NO_ERROR, + ChipLogError(Controller, "Could not CreateBoxedObject with error %" CHIP_ERROR_FORMAT, err.Format())); + } + env->CallVoidMethod(nodeState, addAttributeStatusMethod, static_cast(aPath.mEndpointId), - static_cast(aPath.mClusterId), static_cast(aPath.mAttributeId), statusObj); + static_cast(aPath.mClusterId), static_cast(aPath.mAttributeId), + static_cast(aStatus.mStatus), jClusterState); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); - return; } + + VerifyOrReturn(aStatus.IsSuccess(), ChipLogError(Controller, "Receive bad status %s", ErrorStr(aStatus.ToChipError())); + aPath.LogPath()); VerifyOrReturn(apData != nullptr, ChipLogError(Controller, "Receive empty apData"); aPath.LogPath()); TLV::TLVReader readerForJavaTLV; @@ -352,29 +353,14 @@ void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPat aPath.LogPath()); UtfString jsonString(env, json.c_str()); - // Create AttributeState object - jclass attributeStateCls; - err = JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/model/AttributeState", attributeStateCls); - VerifyOrReturn(err == CHIP_NO_ERROR, - ChipLogError(Controller, "Could not find AttributeState class with error %s", ErrorStr(err)); - aPath.LogPath()); - VerifyOrReturn(attributeStateCls != nullptr, ChipLogError(Controller, "Could not find AttributeState class"); aPath.LogPath()); - jmethodID attributeStateCtor = env->GetMethodID(attributeStateCls, "", "(Ljava/lang/Object;[BLjava/lang/String;)V"); - VerifyOrReturn(attributeStateCtor != nullptr, ChipLogError(Controller, "Could not find AttributeState constructor"); - aPath.LogPath()); - jobject attributeStateObj = - env->NewObject(attributeStateCls, attributeStateCtor, value, jniByteArray.jniValue(), jsonString.jniValue()); - VerifyOrReturn(attributeStateObj != nullptr, ChipLogError(Controller, "Could not create AttributeState object"); - aPath.LogPath()); - - // Add AttributeState to NodeState + // Add AttributeState to wrapperCallback jmethodID addAttributeMethod; - err = JniReferences::GetInstance().FindMethod(env, nodeState, "addAttribute", - "(IJJLchip/devicecontroller/model/AttributeState;)V", &addAttributeMethod); + err = JniReferences::GetInstance().FindMethod(env, nodeState, "addAttribute", "(IJJLjava/lang/Object;[BLjava/lang/String;)V", + &addAttributeMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find addAttribute method with error %s", ErrorStr(err))); env->CallVoidMethod(nodeState, addAttributeMethod, static_cast(aPath.mEndpointId), static_cast(aPath.mClusterId), - static_cast(aPath.mAttributeId), attributeStateObj); + static_cast(aPath.mAttributeId), value, jniByteArray.jniValue(), jsonString.jniValue()); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); UpdateClusterDataVersion(); @@ -406,7 +392,10 @@ void ReportCallback::UpdateClusterDataVersion() return; } - jobject nodeState = mNodeStateObj.ObjectRef(); + VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), + ChipLogError(Controller, "mReportCallbackRef is not valid in %s", __func__)); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); + jobject nodeState = GetNodeStateObj(env, mNodeStateClassSignature, wrapperCallback); // SetDataVersion to NodeState jmethodID setDataVersionMethod; @@ -419,28 +408,37 @@ void ReportCallback::UpdateClusterDataVersion() void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLVReader * apData, const app::StatusIB * apStatus) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); - jobject nodeState = mNodeStateObj.ObjectRef(); - if (apStatus != nullptr && apStatus->IsFailure()) + VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), + ChipLogError(Controller, "mReportCallbackRef is not valid in %s", __func__)); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); + jobject nodeState = GetNodeStateObj(env, mNodeStateClassSignature, wrapperCallback); + if (apStatus != nullptr) { - ChipLogError(Controller, "Receive bad status %s", ErrorStr(apStatus->ToChipError())); - jobject statusObj = nullptr; - err = CreateStatus(env, *apStatus, statusObj); - VerifyOrReturn(err == CHIP_NO_ERROR, - ChipLogError(Controller, "Fail to create status with error %" CHIP_ERROR_FORMAT, err.Format())); // Add Event Status to NodeState jmethodID addEventStatusMethod; - err = JniReferences::GetInstance().FindMethod(env, nodeState, "addEventStatus", - "(IJJLchip/devicecontroller/model/Status;)V", &addEventStatusMethod); + err = JniReferences::GetInstance().FindMethod(env, nodeState, "addEventStatus", "(IJJILjava/lang/Integer;)V", + &addEventStatusMethod); VerifyOrReturn( err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find addEventStatus method with error %" CHIP_ERROR_FORMAT, err.Format())); + + jobject jClusterState = nullptr; + if (apStatus->mClusterStatus.HasValue()) + { + err = JniReferences::GetInstance().CreateBoxedObject( + "java/lang/Integer", "(I)V", static_cast(apStatus->mClusterStatus.Value()), jClusterState); + VerifyOrReturn(err == CHIP_NO_ERROR, + ChipLogError(Controller, "Could not CreateBoxedObject with error %" CHIP_ERROR_FORMAT, err.Format())); + } + env->CallVoidMethod(nodeState, addEventStatusMethod, static_cast(aEventHeader.mPath.mEndpointId), static_cast(aEventHeader.mPath.mClusterId), static_cast(aEventHeader.mPath.mEventId), - statusObj); + static_cast(apStatus->mStatus), jClusterState); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); return; } @@ -508,86 +506,18 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV aEventHeader.LogPath()); UtfString jsonString(env, json.c_str()); - // Create EventState object - jclass eventStateCls; - err = JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/model/EventState", eventStateCls); - VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Failed to find EventState class"); aEventHeader.LogPath()); - VerifyOrReturn(eventStateCls != nullptr, ChipLogError(Controller, "Could not find EventState class"); aEventHeader.LogPath()); - jmethodID eventStateCtor = env->GetMethodID(eventStateCls, "", "(JIIJLjava/lang/Object;[BLjava/lang/String;)V"); - VerifyOrReturn(eventStateCtor != nullptr, ChipLogError(Controller, "Could not find EventState constructor"); - aEventHeader.LogPath()); - jobject eventStateObj = env->NewObject(eventStateCls, eventStateCtor, eventNumber, priorityLevel, timestampType, timestampValue, - value, jniByteArray.jniValue(), jsonString.jniValue()); - VerifyOrReturn(eventStateObj != nullptr, ChipLogError(Controller, "Could not create EventState object"); - aEventHeader.LogPath()); - - // Add EventState to NodeState jmethodID addEventMethod; - - err = JniReferences::GetInstance().FindMethod(env, nodeState, "addEvent", "(IJJLchip/devicecontroller/model/EventState;)V", + err = JniReferences::GetInstance().FindMethod(env, nodeState, "addEvent", "(IJJJIIJLjava/lang/Object;[BLjava/lang/String;)V", &addEventMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find addEvent method with error %s", ErrorStr(err)); aEventHeader.LogPath()); env->CallVoidMethod(nodeState, addEventMethod, static_cast(aEventHeader.mPath.mEndpointId), static_cast(aEventHeader.mPath.mClusterId), static_cast(aEventHeader.mPath.mEventId), - eventStateObj); + eventNumber, priorityLevel, timestampType, timestampValue, value, jniByteArray.jniValue(), + jsonString.jniValue()); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe(); aEventHeader.LogPath()); } -CHIP_ERROR InvokeCallback::CreateInvokeElement(JNIEnv * env, const app::ConcreteCommandPath & aPath, TLV::TLVReader * apData, - jobject & outObj) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - jclass invokeElementCls = nullptr; - err = JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/model/InvokeElement", invokeElementCls); - ReturnErrorOnFailure(err); - - jmethodID invokeElementCtor = env->GetStaticMethodID(invokeElementCls, "newInstance", - "(IJJ[BLjava/lang/String;)Lchip/devicecontroller/model/InvokeElement;"); - VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrReturnError(invokeElementCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); - - if (apData != nullptr) - { - TLV::TLVReader readerForJavaTLV; - TLV::TLVReader readerForJson; - readerForJavaTLV.Init(*apData); - - // Create TLV byte array to pass to Java layer - size_t bufferLen = readerForJavaTLV.GetRemainingLength() + readerForJavaTLV.GetLengthRead(); - - std::unique_ptr buffer = std::unique_ptr(new uint8_t[bufferLen]); - uint32_t size = 0; - - TLV::TLVWriter writer; - writer.Init(buffer.get(), bufferLen); - err = writer.CopyElement(TLV::AnonymousTag(), readerForJavaTLV); - ReturnErrorOnFailure(err); - size = writer.GetLengthWritten(); - chip::ByteArray jniByteArray(env, reinterpret_cast(buffer.get()), static_cast(size)); - - // Convert TLV to JSON - std::string json; - readerForJson.Init(buffer.get(), size); - err = readerForJson.Next(); - ReturnErrorOnFailure(err); - err = TlvToJson(readerForJson, json); - ReturnErrorOnFailure(err); - UtfString jsonString(env, json.c_str()); - outObj = env->CallStaticObjectMethod(invokeElementCls, invokeElementCtor, static_cast(aPath.mEndpointId), - static_cast(aPath.mClusterId), static_cast(aPath.mCommandId), - jniByteArray.jniValue(), jsonString.jniValue()); - } - else - { - outObj = env->CallStaticObjectMethod(invokeElementCls, invokeElementCtor, static_cast(aPath.mEndpointId), - static_cast(aPath.mClusterId), static_cast(aPath.mCommandId), nullptr, - nullptr); - } - VerifyOrReturnError(outObj != nullptr, CHIP_JNI_ERROR_NULL_OBJECT); - return CHIP_NO_ERROR; -} - void ReportCallback::OnError(CHIP_ERROR aError) { ReportError(nullptr, nullptr, aError); @@ -601,12 +531,11 @@ void ReportCallback::OnDone(app::ReadClient *) JniLocalReferenceScope scope(env); VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), ChipLogError(Controller, "mWrapperCallbackRef is not valid in %s", __func__)); - JniGlobalReference globalRef(std::move(mWrapperCallbackRef)); jmethodID onDoneMethod; - VerifyOrReturn(mReportCallbackRef.HasValidObjectRef(), - ChipLogError(Controller, "mReportCallbackRef is not valid in %s", __func__)); - jobject reportCallback = mReportCallbackRef.ObjectRef(); - err = JniReferences::GetInstance().FindMethod(env, reportCallback, "onDone", "()V", &onDoneMethod); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); + JniGlobalReference globalRef(std::move(mWrapperCallbackRef)); + + err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onDone", "()V", &onDoneMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find onDone method")); if (mReadClient != nullptr) @@ -616,7 +545,7 @@ void ReportCallback::OnDone(app::ReadClient *) mReadClient = nullptr; DeviceLayer::StackUnlock unlock; - env->CallVoidMethod(reportCallback, onDoneMethod); + env->CallVoidMethod(wrapperCallback, onDoneMethod); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } @@ -628,7 +557,10 @@ void ReportCallback::OnSubscriptionEstablished(SubscriptionId aSubscriptionId) DeviceLayer::StackUnlock unlock; VerifyOrReturn(mSubscriptionEstablishedCallbackRef.HasValidObjectRef(), ChipLogError(Controller, " mSubscriptionEstablishedCallbackRef is not valid in %s", __func__)); - JniReferences::GetInstance().CallSubscriptionEstablished(mSubscriptionEstablishedCallbackRef.ObjectRef(), aSubscriptionId); + CHIP_ERROR err = + JniReferences::GetInstance().CallSubscriptionEstablished(mSubscriptionEstablishedCallbackRef.ObjectRef(), aSubscriptionId); + VerifyOrReturn(err == CHIP_NO_ERROR, + ChipLogError(Controller, "CallSubscriptionEstablished error! : %" CHIP_ERROR_FORMAT, err.Format())); } CHIP_ERROR ReportCallback::OnResubscriptionNeeded(app::ReadClient * apReadClient, CHIP_ERROR aTerminationCause) @@ -651,49 +583,75 @@ CHIP_ERROR ReportCallback::OnResubscriptionNeeded(app::ReadClient * apReadClient return CHIP_NO_ERROR; } -void ReportCallback::ReportError(jobject attributePath, jobject eventPath, CHIP_ERROR err) +void ReportCallback::ReportError(const app::ConcreteAttributePath * attributePath, const app::ConcreteEventPath * eventPath, + CHIP_ERROR err) { ReportError(attributePath, eventPath, ErrorStr(err), err.AsInteger()); } -void ReportCallback::ReportError(jobject attributePath, jobject eventPath, Protocols::InteractionModel::Status status) +void ReportCallback::ReportError(const app::ConcreteAttributePath * attributePath, const app::ConcreteEventPath * eventPath, + Protocols::InteractionModel::Status status) { ReportError(attributePath, eventPath, "IM Status", static_cast>(status)); } -void ReportCallback::ReportError(jobject attributePath, jobject eventPath, const char * message, ChipError::StorageType errorCode) +void ReportCallback::ReportError(const app::ConcreteAttributePath * attributePath, const app::ConcreteEventPath * eventPath, + const char * message, ChipError::StorageType errorCode) { CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); JniLocalReferenceScope scope(env); - VerifyOrReturn(mReportCallbackRef.HasValidObjectRef(), - ChipLogError(Controller, "mReportCallbackRef is not valid in %s", __func__)); - jobject reportCallback = mReportCallbackRef.ObjectRef(); + VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), + ChipLogError(Controller, "mWrapperCallbackRef is not valid in %s", __func__)); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); jthrowable exception; err = AndroidControllerExceptions::GetInstance().CreateAndroidControllerException(env, message, errorCode, exception); VerifyOrReturn( err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to create AndroidControllerException on ReportCallback::ReportError: %s", ErrorStr(err))); jmethodID onErrorMethod; - err = JniReferences::GetInstance().FindMethod( - env, reportCallback, "onError", - "(Lchip/devicecontroller/model/ChipAttributePath;Lchip/devicecontroller/model/ChipEventPath;Ljava/lang/Exception;)V", - &onErrorMethod); + err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onError", "(ZIJJZIJJLjava/lang/Exception;)V", + &onErrorMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to find onError method: %s", ErrorStr(err))); DeviceLayer::StackUnlock unlock; - env->CallVoidMethod(reportCallback, onErrorMethod, attributePath, eventPath, exception); + + jboolean isAttributePath = JNI_FALSE; + jint attributeEndpointId = static_cast(kInvalidEndpointId); + jlong attributeClusterId = static_cast(kInvalidClusterId); + jlong attributeId = static_cast(kInvalidAttributeId); + + jboolean isEventPath = JNI_FALSE; + jint eventEndpointId = static_cast(kInvalidEndpointId); + jlong eventClusterId = static_cast(kInvalidClusterId); + jlong eventId = static_cast(kInvalidAttributeId); + + if (attributePath != nullptr) + { + isAttributePath = JNI_TRUE; + attributeEndpointId = static_cast(attributePath->mEndpointId); + attributeClusterId = static_cast(attributePath->mClusterId); + attributeId = static_cast(attributePath->mAttributeId); + } + + if (eventPath != nullptr) + { + isEventPath = JNI_TRUE; + eventEndpointId = static_cast(eventPath->mEndpointId); + eventClusterId = static_cast(eventPath->mClusterId); + eventId = static_cast(eventPath->mEventId); + } + env->CallVoidMethod(wrapperCallback, onErrorMethod, isAttributePath, attributeEndpointId, attributeClusterId, attributeId, + isEventPath, eventEndpointId, eventClusterId, eventId, exception); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } -WriteAttributesCallback::WriteAttributesCallback(jobject wrapperCallback, jobject javaCallback) : mChunkedWriteCallback(this) +WriteAttributesCallback::WriteAttributesCallback(jobject wrapperCallback) : mChunkedWriteCallback(this) { VerifyOrReturn(mWrapperCallbackRef.Init(wrapperCallback) == CHIP_NO_ERROR, ChipLogError(Controller, "Could not init mWrapperCallbackRef for WriteAttributesCallback")); - VerifyOrReturn(mJavaCallbackRef.Init(javaCallback) == CHIP_NO_ERROR, - ChipLogError(Controller, "Could not init mJavaCallbackRef in %s", __func__)); } WriteAttributesCallback::~WriteAttributesCallback() @@ -711,26 +669,27 @@ void WriteAttributesCallback::OnResponse(const app::WriteClient * apWriteClient, JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); JniLocalReferenceScope scope(env); + jmethodID onResponseMethod; + VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), + ChipLogError(Controller, "mWrapperCallbackRef is not valid in %s", __func__)); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); + err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onResponse", "(IJJILjava/lang/Integer;)V", + &onResponseMethod); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to find onError method: %s", ErrorStr(err))); - jobject attributePathObj = nullptr; - err = CreateChipAttributePath(env, aPath, attributePathObj); - VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to create Java ChipAttributePath: %s", ErrorStr(err))); - - if (aStatus.mStatus != Protocols::InteractionModel::Status::Success) + jobject jClusterState = nullptr; + if (aStatus.mClusterStatus.HasValue()) { - ReportError(attributePathObj, aStatus.mStatus); - return; + err = JniReferences::GetInstance().CreateBoxedObject( + "java/lang/Integer", "(I)V", static_cast(aStatus.mClusterStatus.Value()), jClusterState); + VerifyOrReturn(err == CHIP_NO_ERROR, + ChipLogError(Controller, "Could not CreateBoxedObject with error %" CHIP_ERROR_FORMAT, err.Format())); } - jmethodID onResponseMethod; - VerifyOrReturn(mJavaCallbackRef.HasValidObjectRef(), ChipLogError(Controller, "mJavaCallbackRef is not valid in %s", __func__)); - jobject javaCallback = mJavaCallbackRef.ObjectRef(); - err = JniReferences::GetInstance().FindMethod(env, javaCallback, "onResponse", - "(Lchip/devicecontroller/model/ChipAttributePath;)V", &onResponseMethod); - VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to find onError method: %s", ErrorStr(err))); - DeviceLayer::StackUnlock unlock; - env->CallVoidMethod(javaCallback, onResponseMethod, attributePathObj); + env->CallVoidMethod(wrapperCallback, onResponseMethod, static_cast(aPath.mEndpointId), + static_cast(aPath.mClusterId), static_cast(aPath.mAttributeId), aStatus.mStatus, + jClusterState); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } @@ -747,29 +706,31 @@ void WriteAttributesCallback::OnDone(app::WriteClient *) JniLocalReferenceScope scope(env); VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), ChipLogError(Controller, "mWrapperCallbackRef is not valid in %s", __func__)); - JniGlobalReference globalRef(std::move(mWrapperCallbackRef)); jmethodID onDoneMethod; - VerifyOrReturn(mJavaCallbackRef.HasValidObjectRef(), ChipLogError(Controller, "mJavaCallbackRef is not valid in %s", __func__)); - jobject javaCallback = mJavaCallbackRef.ObjectRef(); - err = JniReferences::GetInstance().FindMethod(env, javaCallback, "onDone", "()V", &onDoneMethod); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); + JniGlobalReference globalRef(std::move(mWrapperCallbackRef)); + + err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onDone", "()V", &onDoneMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find onDone method")); DeviceLayer::StackUnlock unlock; - env->CallVoidMethod(javaCallback, onDoneMethod); + env->CallVoidMethod(wrapperCallback, onDoneMethod); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } -void WriteAttributesCallback::ReportError(jobject attributePath, CHIP_ERROR err) +void WriteAttributesCallback::ReportError(const app::ConcreteAttributePath * attributePath, CHIP_ERROR err) { ReportError(attributePath, ErrorStr(err), err.AsInteger()); } -void WriteAttributesCallback::ReportError(jobject attributePath, Protocols::InteractionModel::Status status) +void WriteAttributesCallback::ReportError(const app::ConcreteAttributePath * attributePath, + Protocols::InteractionModel::Status status) { ReportError(attributePath, "IM Status", static_cast>(status)); } -void WriteAttributesCallback::ReportError(jobject attributePath, const char * message, ChipError::StorageType errorCode) +void WriteAttributesCallback::ReportError(const app::ConcreteAttributePath * attributePath, const char * message, + ChipError::StorageType errorCode) { CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -783,23 +744,35 @@ void WriteAttributesCallback::ReportError(jobject attributePath, const char * me "Unable to create AndroidControllerException on WriteAttributesCallback::ReportError: %s", ErrorStr(err))); jmethodID onErrorMethod; - VerifyOrReturn(mJavaCallbackRef.HasValidObjectRef(), ChipLogError(Controller, "mJavaCallbackRef is not valid in %s", __func__)); - jobject javaCallback = mJavaCallbackRef.ObjectRef(); - err = JniReferences::GetInstance().FindMethod( - env, javaCallback, "onError", "(Lchip/devicecontroller/model/ChipAttributePath;Ljava/lang/Exception;)V", &onErrorMethod); + VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), + ChipLogError(Controller, "mWrapperCallbackRef is not valid in %s", __func__)); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); + err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onError", "(ZIJJLjava/lang/Exception;)V", &onErrorMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to find onError method: %s", ErrorStr(err))); + jboolean isAttributePath = JNI_FALSE; + jint attributeEndpointId = static_cast(kInvalidEndpointId); + jlong attributeClusterId = static_cast(kInvalidClusterId); + jlong attributeId = static_cast(kInvalidAttributeId); + + if (attributePath != nullptr) + { + isAttributePath = JNI_TRUE; + attributeEndpointId = static_cast(attributePath->mEndpointId); + attributeClusterId = static_cast(attributePath->mClusterId); + attributeId = static_cast(attributePath->mAttributeId); + } + DeviceLayer::StackUnlock unlock; - env->CallVoidMethod(javaCallback, onErrorMethod, attributePath, exception); + env->CallVoidMethod(wrapperCallback, onErrorMethod, isAttributePath, attributeEndpointId, attributeClusterId, attributeId, + exception); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } -InvokeCallback::InvokeCallback(jobject wrapperCallback, jobject javaCallback) +InvokeCallback::InvokeCallback(jobject wrapperCallback) { VerifyOrReturn(mWrapperCallbackRef.Init(wrapperCallback) == CHIP_NO_ERROR, ChipLogError(Controller, "Could not init mWrapperCallbackRef for InvokeCallback")); - VerifyOrReturn(mJavaCallbackRef.Init(javaCallback) == CHIP_NO_ERROR, - ChipLogError(Controller, "Could not init mJavaCallbackRef in %s", __func__)); } InvokeCallback::~InvokeCallback() @@ -816,27 +789,61 @@ void InvokeCallback::OnResponse(app::CommandSender * apCommandSender, const app: CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); - jobject invokeElementObj = nullptr; jmethodID onResponseMethod; JniLocalReferenceScope scope(env); - err = CreateInvokeElement(env, aPath, apData, invokeElementObj); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to create Java InvokeElement: %s", ErrorStr(err))); - VerifyOrReturn(mJavaCallbackRef.HasValidObjectRef(), ChipLogError(Controller, "mJavaCallbackRef is not valid in %s", __func__)); - jobject javaCallback = mJavaCallbackRef.ObjectRef(); - err = JniReferences::GetInstance().FindMethod(env, javaCallback, "onResponse", - "(Lchip/devicecontroller/model/InvokeElement;J)V", &onResponseMethod); + VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), + ChipLogError(Controller, "mWrapperCallbackRef is not valid in %s", __func__)); + jobject wrapperCallbackRef = mWrapperCallbackRef.ObjectRef(); + err = JniReferences::GetInstance().FindMethod(env, wrapperCallbackRef, "onResponse", "(IJJ[BLjava/lang/String;J)V", + &onResponseMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to find onResponse method: %s", ErrorStr(err))); DeviceLayer::StackUnlock unlock; - if (aStatusIB.mClusterStatus.HasValue()) + + if (apData != nullptr) { - env->CallVoidMethod(javaCallback, onResponseMethod, invokeElementObj, static_cast(aStatusIB.mClusterStatus.Value())); + TLV::TLVReader readerForJavaTLV; + TLV::TLVReader readerForJson; + readerForJavaTLV.Init(*apData); + + // Create TLV byte array to pass to Java layer + size_t bufferLen = readerForJavaTLV.GetRemainingLength() + readerForJavaTLV.GetLengthRead(); + std::unique_ptr buffer = std::unique_ptr(new uint8_t[bufferLen]); + uint32_t size = 0; + + TLV::TLVWriter writer; + writer.Init(buffer.get(), bufferLen); + err = writer.CopyElement(TLV::AnonymousTag(), readerForJavaTLV); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Failed CopyElement: %" CHIP_ERROR_FORMAT, err.Format())); + size = writer.GetLengthWritten(); + + chip::ByteArray jniByteArray(env, reinterpret_cast(buffer.get()), static_cast(size)); + + // Convert TLV to JSON + std::string json; + readerForJson.Init(buffer.get(), size); + err = readerForJson.Next(); + VerifyOrReturn(err == CHIP_NO_ERROR, + ChipLogError(Controller, "Failed readerForJson next: %" CHIP_ERROR_FORMAT, err.Format())); + err = TlvToJson(readerForJson, json); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Failed TlvToJson: %" CHIP_ERROR_FORMAT, err.Format())); + UtfString jsonString(env, json.c_str()); + + env->CallVoidMethod(wrapperCallbackRef, onResponseMethod, static_cast(aPath.mEndpointId), + static_cast(aPath.mClusterId), static_cast(aPath.mCommandId), jniByteArray.jniValue(), + jsonString.jniValue(), + aStatusIB.mClusterStatus.HasValue() ? static_cast(aStatusIB.mClusterStatus.Value()) + : static_cast(Protocols::InteractionModel::Status::Success)); } else { - env->CallVoidMethod(javaCallback, onResponseMethod, invokeElementObj, - static_cast(Protocols::InteractionModel::Status::Success)); + env->CallVoidMethod(wrapperCallbackRef, onResponseMethod, static_cast(aPath.mEndpointId), + static_cast(aPath.mClusterId), static_cast(aPath.mCommandId), nullptr, nullptr, + aStatusIB.mClusterStatus.HasValue() ? static_cast(aStatusIB.mClusterStatus.Value()) + : static_cast(Protocols::InteractionModel::Status::Success)); } + VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } @@ -851,17 +858,17 @@ void InvokeCallback::OnDone(app::CommandSender * apCommandSender) JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); JniLocalReferenceScope scope(env); + jmethodID onDoneMethod; VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), ChipLogError(Controller, "mWrapperCallbackRef is not valid in %s", __func__)); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); JniGlobalReference globalRef(std::move(mWrapperCallbackRef)); - jmethodID onDoneMethod; - VerifyOrReturn(mJavaCallbackRef.HasValidObjectRef(), ChipLogError(Controller, "mJavaCallbackRef is not valid in %s", __func__)); - jobject javaCallback = mJavaCallbackRef.ObjectRef(); - err = JniReferences::GetInstance().FindMethod(env, javaCallback, "onDone", "()V", &onDoneMethod); + + err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onDone", "()V", &onDoneMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find onDone method")); DeviceLayer::StackUnlock unlock; - env->CallVoidMethod(javaCallback, onDoneMethod); + env->CallVoidMethod(wrapperCallback, onDoneMethod); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } @@ -889,15 +896,78 @@ void InvokeCallback::ReportError(const char * message, ChipError::StorageType er ChipLogError(Controller, "Unable to create AndroidControllerException: %s on InvokeCallback::ReportError", ErrorStr(err))); jmethodID onErrorMethod; - VerifyOrReturn(mJavaCallbackRef.HasValidObjectRef(), ChipLogError(Controller, "mJavaCallbackRef is not valid in %s", __func__)); - jobject javaCallback = mJavaCallbackRef.ObjectRef(); - err = JniReferences::GetInstance().FindMethod(env, javaCallback, "onError", "(Ljava/lang/Exception;)V", &onErrorMethod); + VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(), + ChipLogError(Controller, "mWrapperCallbackRef is not valid in %s", __func__)); + jobject wrapperCallback = mWrapperCallbackRef.ObjectRef(); + err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onError", "(Ljava/lang/Exception;)V", &onErrorMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to find onError method: %s", ErrorStr(err))); DeviceLayer::StackUnlock unlock; - env->CallVoidMethod(javaCallback, onErrorMethod, exception); + env->CallVoidMethod(wrapperCallback, onErrorMethod, exception); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } +jlong newConnectedDeviceCallback(JNIEnv * env, jobject self, jobject callback) +{ + chip::DeviceLayer::StackLock lock; + GetConnectedDeviceCallback * connectedDeviceCallback = chip::Platform::New(self, callback); + return reinterpret_cast(connectedDeviceCallback); +} + +void deleteConnectedDeviceCallback(JNIEnv * env, jobject self, jlong callbackHandle) +{ + chip::DeviceLayer::StackLock lock; + GetConnectedDeviceCallback * connectedDeviceCallback = reinterpret_cast(callbackHandle); + VerifyOrReturn(connectedDeviceCallback != nullptr, ChipLogError(Controller, "GetConnectedDeviceCallback handle is nullptr")); + chip::Platform::Delete(connectedDeviceCallback); +} + +jlong newReportCallback(JNIEnv * env, jobject self, jobject subscriptionEstablishedCallbackJava, + jobject resubscriptionAttemptCallbackJava, const char * nodeStateClassSignature) +{ + chip::DeviceLayer::StackLock lock; + ReportCallback * reportCallback = chip::Platform::New( + self, subscriptionEstablishedCallbackJava, resubscriptionAttemptCallbackJava, nodeStateClassSignature); + return reinterpret_cast(reportCallback); +} + +void deleteReportCallback(JNIEnv * env, jobject self, jlong callbackHandle) +{ + chip::DeviceLayer::StackLock lock; + ReportCallback * reportCallback = reinterpret_cast(callbackHandle); + VerifyOrReturn(reportCallback != nullptr, ChipLogError(Controller, "ReportCallback handle is nullptr")); + chip::Platform::Delete(reportCallback); +} + +jlong newWriteAttributesCallback(JNIEnv * env, jobject self) +{ + chip::DeviceLayer::StackLock lock; + WriteAttributesCallback * writeAttributesCallback = chip::Platform::New(self); + return reinterpret_cast(writeAttributesCallback); +} + +void deleteWriteAttributesCallback(JNIEnv * env, jobject self, jlong callbackHandle) +{ + chip::DeviceLayer::StackLock lock; + WriteAttributesCallback * writeAttributesCallback = reinterpret_cast(callbackHandle); + VerifyOrReturn(writeAttributesCallback != nullptr, ChipLogError(Controller, "WriteAttributesCallback handle is nullptr")); + chip::Platform::Delete(writeAttributesCallback); +} + +jlong newInvokeCallback(JNIEnv * env, jobject self) +{ + chip::DeviceLayer::StackLock lock; + InvokeCallback * invokeCallback = chip::Platform::New(self); + return reinterpret_cast(invokeCallback); +} + +void deleteInvokeCallback(JNIEnv * env, jobject self, jlong callbackHandle) +{ + chip::DeviceLayer::StackLock lock; + InvokeCallback * invokeCallback = reinterpret_cast(callbackHandle); + VerifyOrReturn(invokeCallback != nullptr, ChipLogError(Controller, "InvokeCallback handle is nullptr")); + chip::Platform::Delete(invokeCallback); +} + } // namespace Controller } // namespace chip diff --git a/src/controller/java/AndroidCallbacks.h b/src/controller/java/AndroidCallbacks.h index f00075258bea8f..700a1fb467f13f 100644 --- a/src/controller/java/AndroidCallbacks.h +++ b/src/controller/java/AndroidCallbacks.h @@ -35,7 +35,9 @@ CHIP_ERROR CreateChipAttributePath(JNIEnv * env, const app::ConcreteDataAttribut // Callback for success and failure cases of GetConnectedDevice(). struct GetConnectedDeviceCallback { - GetConnectedDeviceCallback(jobject wrapperCallback, jobject javaCallback); + GetConnectedDeviceCallback( + jobject wrapperCallback, jobject javaCallback, + const char * callbackClassSignature = "chip/devicecontroller/GetConnectedDeviceCallbackJni$GetConnectedDeviceCallback"); ~GetConnectedDeviceCallback(); static void OnDeviceConnectedFn(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle); @@ -45,13 +47,16 @@ struct GetConnectedDeviceCallback Callback::Callback mOnFailure; JniGlobalReference mWrapperCallbackRef; JniGlobalReference mJavaCallbackRef; + +private: + const char * mCallbackClassSignature = nullptr; }; struct ReportCallback : public app::ClusterStateCache::Callback { /** Subscription established callback can be nullptr. */ - ReportCallback(jobject wrapperCallback, jobject subscriptionEstablishedCallback, jobject reportCallback, - jobject resubscriptionAttemptCallback); + ReportCallback(jobject wrapperCallback, jobject subscriptionEstablishedCallback, jobject resubscriptionAttemptCallback, + const char * nodeStateClassSignature); ~ReportCallback(); void OnReportBegin() override; @@ -73,11 +78,11 @@ struct ReportCallback : public app::ClusterStateCache::Callback void OnDeallocatePaths(app::ReadPrepareParams && aReadPrepareParams) override; /** Report errors back to Java layer. attributePath may be nullptr for general errors. */ - void ReportError(jobject attributePath, jobject eventPath, CHIP_ERROR err); - void ReportError(jobject attributePath, jobject eventPath, Protocols::InteractionModel::Status status); - void ReportError(jobject attributePath, jobject eventPath, const char * message, ChipError::StorageType errorCode); - - CHIP_ERROR CreateChipEventPath(JNIEnv * env, const app::ConcreteEventPath & aPath, jobject & outObj); + void ReportError(const app::ConcreteAttributePath * attributePath, const app::ConcreteEventPath * eventPath, CHIP_ERROR err); + void ReportError(const app::ConcreteAttributePath * attributePath, const app::ConcreteEventPath * eventPath, + Protocols::InteractionModel::Status status); + void ReportError(const app::ConcreteAttributePath * attributePath, const app::ConcreteEventPath * eventPath, + const char * message, ChipError::StorageType errorCode); void UpdateClusterDataVersion(); @@ -87,14 +92,13 @@ struct ReportCallback : public app::ClusterStateCache::Callback JniGlobalReference mWrapperCallbackRef; JniGlobalReference mSubscriptionEstablishedCallbackRef; JniGlobalReference mResubscriptionAttemptCallbackRef; - JniGlobalReference mReportCallbackRef; - // NodeState Java object that will be returned to the application. - JniGlobalReference mNodeStateObj; + + const char * mNodeStateClassSignature; }; struct WriteAttributesCallback : public app::WriteClient::Callback { - WriteAttributesCallback(jobject wrapperCallback, jobject javaCallback); + WriteAttributesCallback(jobject wrapperCallback); ~WriteAttributesCallback(); app::WriteClient::Callback * GetChunkedWriteCallback() { return &mChunkedWriteCallback; } @@ -105,19 +109,18 @@ struct WriteAttributesCallback : public app::WriteClient::Callback void OnDone(app::WriteClient * apWriteClient) override; - void ReportError(jobject attributePath, CHIP_ERROR err); - void ReportError(jobject attributePath, Protocols::InteractionModel::Status status); - void ReportError(jobject attributePath, const char * message, ChipError::StorageType errorCode); + void ReportError(const app::ConcreteAttributePath * attributePath, CHIP_ERROR err); + void ReportError(const app::ConcreteAttributePath * attributePath, Protocols::InteractionModel::Status status); + void ReportError(const app::ConcreteAttributePath * attributePath, const char * message, ChipError::StorageType errorCode); app::WriteClient * mWriteClient = nullptr; app::ChunkedWriteCallback mChunkedWriteCallback; JniGlobalReference mWrapperCallbackRef; - JniGlobalReference mJavaCallbackRef; }; struct InvokeCallback : public app::CommandSender::Callback { - InvokeCallback(jobject wrapperCallback, jobject javaCallback); + InvokeCallback(jobject wrapperCallback); ~InvokeCallback(); void OnResponse(app::CommandSender * apCommandSender, const app::ConcreteCommandPath & aPath, const app::StatusIB & aStatusIB, @@ -127,15 +130,23 @@ struct InvokeCallback : public app::CommandSender::Callback void OnDone(app::CommandSender * apCommandSender) override; - CHIP_ERROR CreateInvokeElement(JNIEnv * env, const app::ConcreteCommandPath & aPath, TLV::TLVReader * apData, jobject & outObj); void ReportError(CHIP_ERROR err); void ReportError(Protocols::InteractionModel::Status status); void ReportError(const char * message, ChipError::StorageType errorCode); app::CommandSender * mCommandSender = nullptr; JniGlobalReference mWrapperCallbackRef; - JniGlobalReference mJavaCallbackRef; }; +jlong newConnectedDeviceCallback(JNIEnv * env, jobject self, jobject callback); +void deleteConnectedDeviceCallback(JNIEnv * env, jobject self, jlong callbackHandle); +jlong newReportCallback(JNIEnv * env, jobject self, jobject subscriptionEstablishedCallbackJava, + jobject resubscriptionAttemptCallbackJava, const char * nodeStateClassSignature); +void deleteReportCallback(JNIEnv * env, jobject self, jlong callbackHandle); +jlong newWriteAttributesCallback(JNIEnv * env, jobject self); +void deleteWriteAttributesCallback(JNIEnv * env, jobject self, jlong callbackHandle); +jlong newInvokeCallback(JNIEnv * env, jobject self); +void deleteInvokeCallback(JNIEnv * env, jobject self, jlong callbackHandle); + } // namespace Controller } // namespace chip diff --git a/src/controller/java/AndroidInteractionClient.cpp b/src/controller/java/AndroidInteractionClient.cpp new file mode 100644 index 00000000000000..a0b22bfde530af --- /dev/null +++ b/src/controller/java/AndroidInteractionClient.cpp @@ -0,0 +1,745 @@ +/* + * 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. + * + */ + +/** + * @file + * Implementation of Interaction Client API for Android Platform + * + */ +#include "AndroidInteractionClient.h" + +#include "AndroidCallbacks.h" +#include "AndroidDeviceControllerWrapper.h" + +#include + +using namespace chip; +using namespace chip::Controller; + +static CHIP_ERROR ParseAttributePathList(jobject attributePathList, + std::vector & outAttributePathParamsList); +CHIP_ERROR ParseAttributePath(jobject attributePath, EndpointId & outEndpointId, ClusterId & outClusterId, + AttributeId & outAttributeId); +static CHIP_ERROR ParseEventPathList(jobject eventPathList, std::vector & outEventPathParamsList); +CHIP_ERROR ParseEventPath(jobject eventPath, EndpointId & outEndpointId, ClusterId & outClusterId, EventId & outEventId, + bool & outIsUrgent); +CHIP_ERROR ParseDataVersionFilter(jobject dataVersionFilter, EndpointId & outEndpointId, ClusterId & outClusterId, + DataVersion & outDataVersion); +static CHIP_ERROR ParseDataVersionFilterList(jobject dataVersionFilterList, + std::vector & outDataVersionFilterList); + +CHIP_ERROR subscribe(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, + jobject eventPathList, jobject dataVersionFilterList, jint minInterval, jint maxInterval, + jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin) +{ + chip::DeviceLayer::StackLock lock; + CHIP_ERROR err = CHIP_NO_ERROR; + app::ReadClient * readClient = nullptr; + size_t numAttributePaths = 0; + size_t numEventPaths = 0; + size_t numDataVersionFilters = 0; + auto callback = reinterpret_cast(callbackHandle); + DeviceProxy * device = reinterpret_cast(devicePtr); + if (device == nullptr) + { + ChipLogProgress(Controller, "Could not cast device pointer to Device object"); + return CHIP_ERROR_INCORRECT_STATE; + } + + app::ReadPrepareParams params(device->GetSecureSession().Value()); + + uint16_t aImTimeoutMs = static_cast(imTimeoutMs); + params.mMinIntervalFloorSeconds = static_cast(minInterval); + params.mMaxIntervalCeilingSeconds = static_cast(maxInterval); + params.mKeepSubscriptions = (keepSubscriptions != JNI_FALSE); + params.mIsFabricFiltered = (isFabricFiltered != JNI_FALSE); + params.mTimeout = aImTimeoutMs != 0 ? System::Clock::Milliseconds32(aImTimeoutMs) : System::Clock::kZero; + + if (attributePathList != nullptr) + { + jint jNumAttributePaths = 0; + SuccessOrExit(err = JniReferences::GetInstance().GetListSize(attributePathList, jNumAttributePaths)); + numAttributePaths = static_cast(jNumAttributePaths); + } + + if (numAttributePaths > 0) + { + std::unique_ptr attributePaths(new chip::app::AttributePathParams[numAttributePaths]); + for (uint8_t i = 0; i < numAttributePaths; i++) + { + jobject attributePathItem = nullptr; + SuccessOrExit(err = JniReferences::GetInstance().GetListItem(attributePathList, i, attributePathItem)); + + EndpointId endpointId; + ClusterId clusterId; + AttributeId attributeId; + SuccessOrExit(err = ParseAttributePath(attributePathItem, endpointId, clusterId, attributeId)); + attributePaths[i] = chip::app::AttributePathParams(endpointId, clusterId, attributeId); + } + params.mpAttributePathParamsList = attributePaths.get(); + params.mAttributePathParamsListSize = numAttributePaths; + attributePaths.release(); + } + + if (dataVersionFilterList != nullptr) + { + jint jNumDataVersionFilters = 0; + SuccessOrExit(err = JniReferences::GetInstance().GetListSize(dataVersionFilterList, jNumDataVersionFilters)); + numDataVersionFilters = static_cast(jNumDataVersionFilters); + } + + if (numDataVersionFilters > 0) + { + std::unique_ptr dataVersionFilters(new chip::app::DataVersionFilter[numDataVersionFilters]); + for (uint8_t i = 0; i < numDataVersionFilters; i++) + { + jobject dataVersionFilterItem = nullptr; + SuccessOrExit(err = JniReferences::GetInstance().GetListItem(dataVersionFilterList, i, dataVersionFilterItem)); + + EndpointId endpointId; + ClusterId clusterId; + DataVersion dataVersion; + SuccessOrExit(err = ParseDataVersionFilter(dataVersionFilterItem, endpointId, clusterId, dataVersion)); + dataVersionFilters[i] = chip::app::DataVersionFilter(endpointId, clusterId, dataVersion); + } + params.mpDataVersionFilterList = dataVersionFilters.get(); + params.mDataVersionFilterListSize = numDataVersionFilters; + dataVersionFilters.release(); + } + + if (eventMin != nullptr) + { + params.mEventNumber.SetValue(static_cast(JniReferences::GetInstance().LongToPrimitive(eventMin))); + } + + if (eventPathList != nullptr) + { + jint jNumEventPaths = 0; + SuccessOrExit(err = JniReferences::GetInstance().GetListSize(eventPathList, jNumEventPaths)); + numEventPaths = static_cast(jNumEventPaths); + } + + if (numEventPaths > 0) + { + std::unique_ptr eventPaths(new chip::app::EventPathParams[numEventPaths]); + for (uint8_t i = 0; i < numEventPaths; i++) + { + jobject eventPathItem = nullptr; + SuccessOrExit(err = JniReferences::GetInstance().GetListItem(eventPathList, i, eventPathItem)); + + EndpointId endpointId; + ClusterId clusterId; + EventId eventId; + bool isUrgent; + SuccessOrExit(err = ParseEventPath(eventPathItem, endpointId, clusterId, eventId, isUrgent)); + eventPaths[i] = chip::app::EventPathParams(endpointId, clusterId, eventId, isUrgent); + } + + params.mpEventPathParamsList = eventPaths.get(); + params.mEventPathParamsListSize = static_cast(numEventPaths); + eventPaths.release(); + } + + readClient = Platform::New(app::InteractionModelEngine::GetInstance(), device->GetExchangeManager(), + callback->mClusterCacheAdapter.GetBufferedCallback(), + app::ReadClient::InteractionType::Subscribe); + + SuccessOrExit(err = readClient->SendAutoResubscribeRequest(std::move(params))); + callback->mReadClient = readClient; + + return CHIP_NO_ERROR; +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "JNI IM Subscribe Error: %s", err.AsString()); + if (err == CHIP_JNI_ERROR_EXCEPTION_THROWN) + { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + callback->OnError(err); + if (readClient != nullptr) + { + Platform::Delete(readClient); + } + if (callback != nullptr) + { + Platform::Delete(callback); + } + } + return err; +} + +CHIP_ERROR read(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, jobject eventPathList, + jobject dataVersionFilterList, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin) +{ + chip::DeviceLayer::StackLock lock; + CHIP_ERROR err = CHIP_NO_ERROR; + + auto callback = reinterpret_cast(callbackHandle); + std::vector attributePathParamsList; + std::vector eventPathParamsList; + std::vector versionList; + app::ReadClient * readClient = nullptr; + DeviceProxy * device = reinterpret_cast(devicePtr); + if (device == nullptr) + { + ChipLogProgress(Controller, "Could not cast device pointer to Device object"); + return CHIP_ERROR_INCORRECT_STATE; + } + app::ReadPrepareParams params(device->GetSecureSession().Value()); + + SuccessOrExit(err = ParseAttributePathList(attributePathList, attributePathParamsList)); + SuccessOrExit(err = ParseEventPathList(eventPathList, eventPathParamsList)); + SuccessOrExit(err = ParseDataVersionFilterList(dataVersionFilterList, versionList)); + VerifyOrExit(attributePathParamsList.size() != 0 || eventPathParamsList.size() != 0, err = CHIP_ERROR_INVALID_ARGUMENT); + params.mpAttributePathParamsList = attributePathParamsList.data(); + params.mAttributePathParamsListSize = attributePathParamsList.size(); + params.mpEventPathParamsList = eventPathParamsList.data(); + params.mEventPathParamsListSize = eventPathParamsList.size(); + if (versionList.size() != 0) + { + params.mpDataVersionFilterList = versionList.data(); + params.mDataVersionFilterListSize = versionList.size(); + } + + params.mIsFabricFiltered = (isFabricFiltered != JNI_FALSE); + params.mTimeout = imTimeoutMs != 0 ? System::Clock::Milliseconds32(imTimeoutMs) : System::Clock::kZero; + + if (eventMin != nullptr) + { + params.mEventNumber.SetValue(static_cast(JniReferences::GetInstance().LongToPrimitive(eventMin))); + } + + readClient = Platform::New(app::InteractionModelEngine::GetInstance(), device->GetExchangeManager(), + callback->mClusterCacheAdapter.GetBufferedCallback(), + app::ReadClient::InteractionType::Read); + + SuccessOrExit(err = readClient->SendRequest(params)); + callback->mReadClient = readClient; +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "JNI IM Read Error: %s", err.AsString()); + if (err == CHIP_JNI_ERROR_EXCEPTION_THROWN) + { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + callback->OnError(err); + if (readClient != nullptr) + { + Platform::Delete(readClient); + readClient = nullptr; + } + if (callback != nullptr) + { + Platform::Delete(callback); + callback = nullptr; + } + } + + return err; +} + +// Convert Json to Tlv, and remove the outer structure +CHIP_ERROR ConvertJsonToTlvWithoutStruct(const std::string & json, MutableByteSpan & data) +{ + Platform::ScopedMemoryBufferWithSize buf; + VerifyOrReturnError(buf.Calloc(data.size()), CHIP_ERROR_NO_MEMORY); + MutableByteSpan dataWithStruct(buf.Get(), buf.AllocatedSize()); + ReturnErrorOnFailure(JsonToTlv(json, dataWithStruct)); + TLV::TLVReader tlvReader; + TLV::TLVType outerContainer = TLV::kTLVType_Structure; + tlvReader.Init(dataWithStruct); + ReturnErrorOnFailure(tlvReader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); + ReturnErrorOnFailure(tlvReader.EnterContainer(outerContainer)); + ReturnErrorOnFailure(tlvReader.Next()); + + TLV::TLVWriter tlvWrite; + tlvWrite.Init(data); + ReturnErrorOnFailure(tlvWrite.CopyElement(TLV::AnonymousTag(), tlvReader)); + ReturnErrorOnFailure(tlvWrite.Finalize()); + data.reduce_size(tlvWrite.GetLengthWritten()); + return CHIP_NO_ERROR; +} + +CHIP_ERROR PutPreencodedWriteAttribute(app::WriteClient & writeClient, app::ConcreteDataAttributePath & path, const ByteSpan & data) +{ + TLV::TLVReader reader; + reader.Init(data); + ReturnErrorOnFailure(reader.Next()); + return writeClient.PutPreencodedAttribute(path, reader); +} + +CHIP_ERROR write(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributeList, + jint timedRequestTimeoutMs, jint imTimeoutMs) +{ + chip::DeviceLayer::StackLock lock; + CHIP_ERROR err = CHIP_NO_ERROR; + jint listSize = 0; + auto callback = reinterpret_cast(callbackHandle); + app::WriteClient * writeClient = nullptr; + uint16_t convertedTimedRequestTimeoutMs = static_cast(timedRequestTimeoutMs); + + ChipLogDetail(Controller, "IM write() called"); + + DeviceProxy * device = reinterpret_cast(devicePtr); + VerifyOrExit(device != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(device->GetSecureSession().HasValue(), err = CHIP_ERROR_MISSING_SECURE_SESSION); + VerifyOrExit(attributeList != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + SuccessOrExit(err = JniReferences::GetInstance().GetListSize(attributeList, listSize)); + + writeClient = Platform::New( + device->GetExchangeManager(), callback->GetChunkedWriteCallback(), + convertedTimedRequestTimeoutMs != 0 ? Optional(convertedTimedRequestTimeoutMs) : Optional::Missing()); + + for (uint8_t i = 0; i < listSize; i++) + { + jobject attributeItem = nullptr; + jmethodID getEndpointIdMethod = nullptr; + jmethodID getClusterIdMethod = nullptr; + jmethodID getAttributeIdMethod = nullptr; + jmethodID hasDataVersionMethod = nullptr; + jmethodID getDataVersionMethod = nullptr; + jmethodID getTlvByteArrayMethod = nullptr; + jmethodID getJsonStringMethod = nullptr; + jlong endpointIdObj = 0; + jlong clusterIdObj = 0; + jlong attributeIdObj = 0; + jbyteArray tlvBytesObj = nullptr; + bool hasDataVersion = false; + Optional dataVersion = Optional(); + + bool isGroupSession = false; + + SuccessOrExit(err = JniReferences::GetInstance().GetListItem(attributeList, i, attributeItem)); + SuccessOrExit( + err = JniReferences::GetInstance().FindMethod(env, attributeItem, "getEndpointId", "(J)J", &getEndpointIdMethod)); + SuccessOrExit(err = + JniReferences::GetInstance().FindMethod(env, attributeItem, "getClusterId", "(J)J", &getClusterIdMethod)); + SuccessOrExit( + err = JniReferences::GetInstance().FindMethod(env, attributeItem, "getAttributeId", "(J)J", &getAttributeIdMethod)); + SuccessOrExit( + err = JniReferences::GetInstance().FindMethod(env, attributeItem, "hasDataVersion", "()Z", &hasDataVersionMethod)); + SuccessOrExit( + err = JniReferences::GetInstance().FindMethod(env, attributeItem, "getDataVersion", "()I", &getDataVersionMethod)); + SuccessOrExit( + err = JniReferences::GetInstance().FindMethod(env, attributeItem, "getTlvByteArray", "()[B", &getTlvByteArrayMethod)); + + isGroupSession = device->GetSecureSession().Value()->IsGroupSession(); + + if (isGroupSession) + { + endpointIdObj = static_cast(kInvalidEndpointId); + } + else + { + endpointIdObj = env->CallLongMethod(attributeItem, getEndpointIdMethod, static_cast(kInvalidEndpointId)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + } + + clusterIdObj = env->CallLongMethod(attributeItem, getClusterIdMethod, static_cast(kInvalidClusterId)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + + attributeIdObj = env->CallLongMethod(attributeItem, getAttributeIdMethod, static_cast(kInvalidAttributeId)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + + hasDataVersion = static_cast(env->CallBooleanMethod(attributeItem, hasDataVersionMethod)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + if (hasDataVersion) + { + DataVersion dataVersionVal = static_cast(env->CallIntMethod(attributeItem, getDataVersionMethod)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + dataVersion.SetValue(dataVersionVal); + } + + tlvBytesObj = static_cast(env->CallObjectMethod(attributeItem, getTlvByteArrayMethod)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + app::ConcreteDataAttributePath path(static_cast(endpointIdObj), static_cast(clusterIdObj), + static_cast(attributeIdObj), dataVersion); + if (tlvBytesObj != nullptr) + { + JniByteArray tlvByteArray(env, tlvBytesObj); + SuccessOrExit(err = PutPreencodedWriteAttribute(*writeClient, path, tlvByteArray.byteSpan())); + } + else + { + SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, attributeItem, "getJsonString", "()Ljava/lang/String;", + &getJsonStringMethod)); + jstring jsonJniString = static_cast(env->CallObjectMethod(attributeItem, getJsonStringMethod)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + VerifyOrExit(jsonJniString != nullptr, err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + JniUtfString jsonUtfJniString(env, jsonJniString); + std::string jsonString = std::string(jsonUtfJniString.c_str(), static_cast(jsonUtfJniString.size())); + + // Context: Chunk write is supported in sdk, oversized list could be chunked in multiple message. When transforming + // JSON to TLV, we need know the actual size for tlv blob when handling JsonToTlv + // TODO: Implement memory auto-grow to get the actual size needed for tlv blob when transforming tlv to json. + // Workaround: Allocate memory using json string's size, which is large enough to hold the corresponding tlv blob + Platform::ScopedMemoryBufferWithSize tlvBytes; + size_t length = static_cast(jsonUtfJniString.size()); + VerifyOrExit(tlvBytes.Calloc(length), err = CHIP_ERROR_NO_MEMORY); + MutableByteSpan data(tlvBytes.Get(), tlvBytes.AllocatedSize()); + SuccessOrExit(err = ConvertJsonToTlvWithoutStruct(jsonString, data)); + SuccessOrExit(err = PutPreencodedWriteAttribute(*writeClient, path, data)); + } + } + + err = writeClient->SendWriteRequest(device->GetSecureSession().Value(), + imTimeoutMs != 0 ? System::Clock::Milliseconds32(imTimeoutMs) : System::Clock::kZero); + SuccessOrExit(err); + callback->mWriteClient = writeClient; +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "JNI IM Write Error: %s", err.AsString()); + if (err == CHIP_JNI_ERROR_EXCEPTION_THROWN) + { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + callback->OnError(writeClient, err); + if (writeClient != nullptr) + { + Platform::Delete(writeClient); + writeClient = nullptr; + } + if (callback != nullptr) + { + Platform::Delete(callback); + callback = nullptr; + } + } + return err; +} + +CHIP_ERROR PutPreencodedInvokeRequest(app::CommandSender & commandSender, app::CommandPathParams & path, const ByteSpan & data) +{ + // PrepareCommand does nott create the struct container with kFields and copycontainer below sets the + // kFields container already + ReturnErrorOnFailure(commandSender.PrepareCommand(path, false /* aStartDataStruct */)); + TLV::TLVWriter * writer = commandSender.GetCommandDataIBTLVWriter(); + VerifyOrReturnError(writer != nullptr, CHIP_ERROR_INCORRECT_STATE); + TLV::TLVReader reader; + reader.Init(data); + ReturnErrorOnFailure(reader.Next()); + return writer->CopyContainer(TLV::ContextTag(app::CommandDataIB::Tag::kFields), reader); +} + +CHIP_ERROR invoke(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject invokeElement, + jint timedRequestTimeoutMs, jint imTimeoutMs) +{ + chip::DeviceLayer::StackLock lock; + CHIP_ERROR err = CHIP_NO_ERROR; + auto callback = reinterpret_cast(callbackHandle); + app::CommandSender * commandSender = nullptr; + uint16_t groupId = 0; + bool isEndpointIdValid = false; + bool isGroupIdValid = false; + jmethodID getEndpointIdMethod = nullptr; + jmethodID getClusterIdMethod = nullptr; + jmethodID getCommandIdMethod = nullptr; + jmethodID getGroupIdMethod = nullptr; + jmethodID getTlvByteArrayMethod = nullptr; + jmethodID getJsonStringMethod = nullptr; + jmethodID isEndpointIdValidMethod = nullptr; + jmethodID isGroupIdValidMethod = nullptr; + jlong endpointIdObj = 0; + jlong clusterIdObj = 0; + jlong commandIdObj = 0; + jobject groupIdObj = nullptr; + jbyteArray tlvBytesObj = nullptr; + uint16_t convertedTimedRequestTimeoutMs = static_cast(timedRequestTimeoutMs); + ChipLogDetail(Controller, "IM invoke() called"); + + DeviceProxy * device = reinterpret_cast(devicePtr); + VerifyOrExit(device != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(device->GetSecureSession().HasValue(), err = CHIP_ERROR_MISSING_SECURE_SESSION); + + commandSender = Platform::New(callback, device->GetExchangeManager(), timedRequestTimeoutMs != 0); + + SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getEndpointId", "(J)J", &getEndpointIdMethod)); + SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getClusterId", "(J)J", &getClusterIdMethod)); + SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getCommandId", "(J)J", &getCommandIdMethod)); + SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getGroupId", "()Ljava/util/Optional;", + &getGroupIdMethod)); + SuccessOrExit( + err = JniReferences::GetInstance().FindMethod(env, invokeElement, "isEndpointIdValid", "()Z", &isEndpointIdValidMethod)); + SuccessOrExit(err = + JniReferences::GetInstance().FindMethod(env, invokeElement, "isGroupIdValid", "()Z", &isGroupIdValidMethod)); + SuccessOrExit( + err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getTlvByteArray", "()[B", &getTlvByteArrayMethod)); + + isEndpointIdValid = (env->CallBooleanMethod(invokeElement, isEndpointIdValidMethod) == JNI_TRUE); + isGroupIdValid = (env->CallBooleanMethod(invokeElement, isGroupIdValidMethod) == JNI_TRUE); + + if (isEndpointIdValid) + { + endpointIdObj = env->CallLongMethod(invokeElement, getEndpointIdMethod, static_cast(kInvalidEndpointId)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + } + + if (isGroupIdValid) + { + VerifyOrExit(device->GetSecureSession().Value()->IsGroupSession(), err = CHIP_ERROR_INVALID_ARGUMENT); + groupIdObj = env->CallObjectMethod(invokeElement, getGroupIdMethod); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + VerifyOrExit(groupIdObj != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + + jobject boxedGroupId = nullptr; + + SuccessOrExit(err = JniReferences::GetInstance().GetOptionalValue(groupIdObj, boxedGroupId)); + VerifyOrExit(boxedGroupId != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + groupId = static_cast(JniReferences::GetInstance().IntegerToPrimitive(boxedGroupId)); + } + + clusterIdObj = env->CallLongMethod(invokeElement, getClusterIdMethod, static_cast(kInvalidClusterId)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + + commandIdObj = env->CallLongMethod(invokeElement, getCommandIdMethod, static_cast(kInvalidCommandId)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + + tlvBytesObj = static_cast(env->CallObjectMethod(invokeElement, getTlvByteArrayMethod)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + { + uint16_t id = isEndpointIdValid ? static_cast(endpointIdObj) : groupId; + app::CommandPathFlags flag = + isEndpointIdValid ? app::CommandPathFlags::kEndpointIdValid : app::CommandPathFlags::kGroupIdValid; + app::CommandPathParams path(id, static_cast(clusterIdObj), static_cast(commandIdObj), flag); + if (tlvBytesObj != nullptr) + { + JniByteArray tlvBytesObjBytes(env, tlvBytesObj); + SuccessOrExit(err = PutPreencodedInvokeRequest(*commandSender, path, tlvBytesObjBytes.byteSpan())); + } + else + { + SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getJsonString", "()Ljava/lang/String;", + &getJsonStringMethod)); + jstring jsonJniString = static_cast(env->CallObjectMethod(invokeElement, getJsonStringMethod)); + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); + VerifyOrExit(jsonJniString != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + JniUtfString jsonUtfJniString(env, jsonJniString); + // The invoke does not support chunk, kMaxSecureSduLengthBytes should be enough for command json blob + uint8_t tlvBytes[chip::app::kMaxSecureSduLengthBytes] = { 0 }; + MutableByteSpan tlvEncodingLocal{ tlvBytes }; + SuccessOrExit(err = JsonToTlv(std::string(jsonUtfJniString.c_str(), static_cast(jsonUtfJniString.size())), + tlvEncodingLocal)); + SuccessOrExit(err = PutPreencodedInvokeRequest(*commandSender, path, tlvEncodingLocal)); + } + } + SuccessOrExit(err = commandSender->FinishCommand(convertedTimedRequestTimeoutMs != 0 + ? Optional(convertedTimedRequestTimeoutMs) + : Optional::Missing())); + + SuccessOrExit(err = device->GetSecureSession().Value()->IsGroupSession() + ? commandSender->SendGroupCommandRequest(device->GetSecureSession().Value()) + : commandSender->SendCommandRequest(device->GetSecureSession().Value(), + imTimeoutMs != 0 + ? MakeOptional(System::Clock::Milliseconds32(imTimeoutMs)) + : Optional::Missing())); + + callback->mCommandSender = commandSender; +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "JNI IM Invoke Error: %s", err.AsString()); + if (err == CHIP_JNI_ERROR_EXCEPTION_THROWN) + { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + callback->OnError(nullptr, err); + if (commandSender != nullptr) + { + Platform::Delete(commandSender); + commandSender = nullptr; + } + if (callback != nullptr) + { + Platform::Delete(callback); + callback = nullptr; + } + } + return err; +} + +/** + * Takes objects in attributePathList, converts them to app:AttributePathParams, and appends them to outAttributePathParamsList. + */ +CHIP_ERROR ParseAttributePathList(jobject attributePathList, std::vector & outAttributePathParamsList) +{ + jint listSize; + + if (attributePathList == nullptr) + { + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(JniReferences::GetInstance().GetListSize(attributePathList, listSize)); + + for (uint8_t i = 0; i < listSize; i++) + { + jobject attributePathItem = nullptr; + ReturnErrorOnFailure(JniReferences::GetInstance().GetListItem(attributePathList, i, attributePathItem)); + + EndpointId endpointId; + ClusterId clusterId; + AttributeId attributeId; + ReturnErrorOnFailure(ParseAttributePath(attributePathItem, endpointId, clusterId, attributeId)); + outAttributePathParamsList.push_back(app::AttributePathParams(endpointId, clusterId, attributeId)); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ParseAttributePath(jobject attributePath, EndpointId & outEndpointId, ClusterId & outClusterId, + AttributeId & outAttributeId) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jmethodID getEndpointIdMethod = nullptr; + jmethodID getClusterIdMethod = nullptr; + jmethodID getAttributeIdMethod = nullptr; + ReturnErrorOnFailure( + JniReferences::GetInstance().FindMethod(env, attributePath, "getEndpointId", "(J)J", &getEndpointIdMethod)); + ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, attributePath, "getClusterId", "(J)J", &getClusterIdMethod)); + ReturnErrorOnFailure( + JniReferences::GetInstance().FindMethod(env, attributePath, "getAttributeId", "(J)J", &getAttributeIdMethod)); + + jlong endpointIdObj = env->CallLongMethod(attributePath, getEndpointIdMethod, static_cast(kInvalidEndpointId)); + jlong clusterIdObj = env->CallLongMethod(attributePath, getClusterIdMethod, static_cast(kInvalidClusterId)); + jlong attributeIdObj = env->CallLongMethod(attributePath, getAttributeIdMethod, static_cast(kInvalidAttributeId)); + + outEndpointId = static_cast(endpointIdObj); + outClusterId = static_cast(clusterIdObj); + outAttributeId = static_cast(attributeIdObj); + + return CHIP_NO_ERROR; +} + +/** + * Takes objects in eventPathList, converts them to app:EventPathParams, and appends them to outEventPathParamsList. + */ +CHIP_ERROR ParseEventPathList(jobject eventPathList, std::vector & outEventPathParamsList) +{ + jint listSize; + + if (eventPathList == nullptr) + { + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(JniReferences::GetInstance().GetListSize(eventPathList, listSize)); + + for (uint8_t i = 0; i < listSize; i++) + { + jobject eventPathItem = nullptr; + ReturnErrorOnFailure(JniReferences::GetInstance().GetListItem(eventPathList, i, eventPathItem)); + + EndpointId endpointId; + ClusterId clusterId; + EventId eventId; + bool isUrgent; + ReturnErrorOnFailure(ParseEventPath(eventPathItem, endpointId, clusterId, eventId, isUrgent)); + outEventPathParamsList.push_back(app::EventPathParams(endpointId, clusterId, eventId, isUrgent)); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ParseEventPath(jobject eventPath, EndpointId & outEndpointId, ClusterId & outClusterId, EventId & outEventId, + bool & outIsUrgent) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jmethodID getEndpointIdMethod = nullptr; + jmethodID getClusterIdMethod = nullptr; + jmethodID getEventIdMethod = nullptr; + jmethodID isUrgentMethod = nullptr; + + ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, eventPath, "getEndpointId", "(J)J", &getEndpointIdMethod)); + ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, eventPath, "getClusterId", "(J)J", &getClusterIdMethod)); + ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, eventPath, "getEventId", "(J)J", &getEventIdMethod)); + ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, eventPath, "isUrgent", "()Z", &isUrgentMethod)); + + jlong endpointIdObj = env->CallLongMethod(eventPath, getEndpointIdMethod, static_cast(kInvalidEndpointId)); + jlong clusterIdObj = env->CallLongMethod(eventPath, getClusterIdMethod, static_cast(kInvalidClusterId)); + jlong eventIdObj = env->CallLongMethod(eventPath, getEventIdMethod, static_cast(kInvalidEventId)); + jboolean isUrgent = env->CallBooleanMethod(eventPath, isUrgentMethod); + + outEndpointId = static_cast(endpointIdObj); + outClusterId = static_cast(clusterIdObj); + outEventId = static_cast(eventIdObj); + outIsUrgent = (isUrgent == JNI_TRUE); + + return CHIP_NO_ERROR; +} + +/** + * Takes objects in dataVersionFilterList, converts them to app:DataVersionFilter, and appends them to outDataVersionFilterList. + */ +CHIP_ERROR ParseDataVersionFilterList(jobject dataVersionFilterList, std::vector & outDataVersionFilterList) +{ + jint listSize; + + if (dataVersionFilterList == nullptr) + { + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(JniReferences::GetInstance().GetListSize(dataVersionFilterList, listSize)); + + for (uint8_t i = 0; i < listSize; i++) + { + jobject dataVersionFilterItem = nullptr; + ReturnErrorOnFailure(JniReferences::GetInstance().GetListItem(dataVersionFilterList, i, dataVersionFilterItem)); + + EndpointId endpointId; + ClusterId clusterId; + DataVersion dataVersion; + ReturnErrorOnFailure(ParseDataVersionFilter(dataVersionFilterItem, endpointId, clusterId, dataVersion)); + outDataVersionFilterList.push_back(app::DataVersionFilter(endpointId, clusterId, dataVersion)); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ParseDataVersionFilter(jobject versionFilter, EndpointId & outEndpointId, ClusterId & outClusterId, + DataVersion & outDataVersion) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jmethodID getEndpointIdMethod = nullptr; + jmethodID getClusterIdMethod = nullptr; + jmethodID getDataVersionMethod = nullptr; + + ReturnErrorOnFailure( + JniReferences::GetInstance().FindMethod(env, versionFilter, "getEndpointId", "(J)J", &getEndpointIdMethod)); + ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, versionFilter, "getClusterId", "(J)J", &getClusterIdMethod)); + ReturnErrorOnFailure( + JniReferences::GetInstance().FindMethod(env, versionFilter, "getDataVersion", "()J", &getDataVersionMethod)); + + jlong endpointIdObj = env->CallLongMethod(versionFilter, getEndpointIdMethod, static_cast(kInvalidEndpointId)); + outEndpointId = static_cast(endpointIdObj); + jlong clusterIdObj = env->CallLongMethod(versionFilter, getClusterIdMethod, static_cast(kInvalidClusterId)); + outClusterId = static_cast(clusterIdObj); + + outDataVersion = static_cast(env->CallLongMethod(versionFilter, getDataVersionMethod)); + return CHIP_NO_ERROR; +} diff --git a/src/controller/java/AndroidInteractionClient.h b/src/controller/java/AndroidInteractionClient.h new file mode 100644 index 00000000000000..095061f0c98172 --- /dev/null +++ b/src/controller/java/AndroidInteractionClient.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 + +CHIP_ERROR subscribe(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, + jobject eventPathList, jobject dataVersionFilterList, jint minInterval, jint maxInterval, + jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin); +CHIP_ERROR read(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, jobject eventPathList, + jobject dataVersionFilterList, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin); +CHIP_ERROR write(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributeList, + jint timedRequestTimeoutMs, jint imTimeoutMs); +CHIP_ERROR invoke(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject invokeElement, + jint timedRequestTimeoutMs, jint imTimeoutMs); diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index 0e5beda7115ae6..678a03a6bf63bc 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -53,6 +53,8 @@ shared_library("jni") { "AndroidCurrentFabricRemover.h", "AndroidDeviceControllerWrapper.cpp", "AndroidDeviceControllerWrapper.h", + "AndroidInteractionClient.cpp", + "AndroidInteractionClient.h", "AndroidOperationalCredentialsIssuer.cpp", "AndroidOperationalCredentialsIssuer.h", "AttestationTrustStoreBridge.cpp", @@ -64,6 +66,8 @@ shared_library("jni") { "DeviceAttestationDelegateBridge.cpp", "DeviceAttestationDelegateBridge.h", "GroupDeviceProxy.h", + "MatterCallbacks-JNI.cpp", + "MatterInteractionClient-JNI.cpp", ] deps = [ @@ -371,14 +375,23 @@ kotlin_library("kotlin_matter_controller") { "src/matter/controller/CompletionListenerAdapter.kt", "src/matter/controller/ControllerParams.kt", "src/matter/controller/InteractionClient.kt", + "src/matter/controller/InvokeCallback.kt", + "src/matter/controller/InvokeCallbackJni.kt", "src/matter/controller/MatterController.kt", "src/matter/controller/MatterControllerException.kt", "src/matter/controller/MatterControllerImpl.kt", "src/matter/controller/Messages.kt", "src/matter/controller/OperationalKeyConfig.kt", + "src/matter/controller/ReportCallback.kt", + "src/matter/controller/ReportCallbackJni.kt", + "src/matter/controller/ResubscriptionAttemptCallback.kt", + "src/matter/controller/SubscriptionEstablishedCallback.kt", "src/matter/controller/SubscriptionStates.kt", + "src/matter/controller/WriteAttributesCallback.kt", + "src/matter/controller/WriteAttributesCallbackJni.kt", "src/matter/controller/model/Paths.kt", "src/matter/controller/model/States.kt", + "src/matter/controller/model/Status.kt", ] sources += matter_structs_sources @@ -465,6 +478,7 @@ android_library("java") { "src/chip/devicecontroller/ReportCallback.java", "src/chip/devicecontroller/ReportCallbackJni.java", "src/chip/devicecontroller/ResubscriptionAttemptCallback.java", + "src/chip/devicecontroller/StatusException.java", "src/chip/devicecontroller/SubscriptionEstablishedCallback.java", "src/chip/devicecontroller/ThreadScanResult.java", "src/chip/devicecontroller/UnpairDeviceCallback.java", diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 85c37b87ae6691..206103ca82a311 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -25,6 +25,7 @@ #include "AndroidCommissioningWindowOpener.h" #include "AndroidCurrentFabricRemover.h" #include "AndroidDeviceControllerWrapper.h" +#include "AndroidInteractionClient.h" #include #include #include @@ -85,19 +86,6 @@ static void * IOThreadMain(void * arg); static CHIP_ERROR StopIOThread(); static CHIP_ERROR N2J_PaseVerifierParams(JNIEnv * env, jlong setupPincode, jbyteArray pakeVerifier, jobject & outParams); static CHIP_ERROR N2J_NetworkLocation(JNIEnv * env, jstring ipAddress, jint port, jint interfaceIndex, jobject & outLocation); -static CHIP_ERROR GetChipPathIdValue(jobject chipPathId, uint32_t wildcardValue, uint32_t & outValue); -static CHIP_ERROR ParseAttributePathList(jobject attributePathList, - std::vector & outAttributePathParamsList); -CHIP_ERROR ParseAttributePath(jobject attributePath, EndpointId & outEndpointId, ClusterId & outClusterId, - AttributeId & outAttributeId); -static CHIP_ERROR ParseEventPathList(jobject eventPathList, std::vector & outEventPathParamsList); -CHIP_ERROR ParseEventPath(jobject eventPath, EndpointId & outEndpointId, ClusterId & outClusterId, EventId & outEventId, - bool & outIsUrgent); -CHIP_ERROR ParseDataVersionFilter(jobject dataVersionFilter, EndpointId & outEndpointId, ClusterId & outClusterId, - DataVersion & outDataVersion); -static CHIP_ERROR ParseDataVersionFilterList(jobject dataVersionFilterList, - std::vector & outDataVersionFilterList); -static CHIP_ERROR IsWildcardChipPathId(jobject chipPathId, bool & isWildcard); namespace { JavaVM * sJVM = nullptr; @@ -2255,139 +2243,11 @@ JNI_METHOD(void, subscribe) jobject dataVersionFilterList, jint minInterval, jint maxInterval, jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin) { - chip::DeviceLayer::StackLock lock; - CHIP_ERROR err = CHIP_NO_ERROR; - app::ReadClient * readClient = nullptr; - size_t numAttributePaths = 0; - size_t numEventPaths = 0; - size_t numDataVersionFilters = 0; - auto callback = reinterpret_cast(callbackHandle); - DeviceProxy * device = reinterpret_cast(devicePtr); - if (device == nullptr) - { - ChipLogProgress(Controller, "Could not cast device pointer to Device object"); - JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, CHIP_ERROR_INCORRECT_STATE); - return; - } - app::ReadPrepareParams params(device->GetSecureSession().Value()); - - uint16_t aImTimeoutMs = static_cast(imTimeoutMs); - params.mMinIntervalFloorSeconds = static_cast(minInterval); - params.mMaxIntervalCeilingSeconds = static_cast(maxInterval); - params.mKeepSubscriptions = (keepSubscriptions != JNI_FALSE); - params.mIsFabricFiltered = (isFabricFiltered != JNI_FALSE); - params.mTimeout = aImTimeoutMs != 0 ? System::Clock::Milliseconds32(aImTimeoutMs) : System::Clock::kZero; - - if (attributePathList != nullptr) - { - jint jNumAttributePaths = 0; - SuccessOrExit(err = JniReferences::GetInstance().GetListSize(attributePathList, jNumAttributePaths)); - numAttributePaths = static_cast(jNumAttributePaths); - } - - if (numAttributePaths > 0) - { - std::unique_ptr attributePaths(new chip::app::AttributePathParams[numAttributePaths]); - for (uint8_t i = 0; i < numAttributePaths; i++) - { - jobject attributePathItem = nullptr; - SuccessOrExit(err = JniReferences::GetInstance().GetListItem(attributePathList, i, attributePathItem)); - - EndpointId endpointId; - ClusterId clusterId; - AttributeId attributeId; - SuccessOrExit(err = ParseAttributePath(attributePathItem, endpointId, clusterId, attributeId)); - attributePaths[i] = chip::app::AttributePathParams(endpointId, clusterId, attributeId); - } - params.mpAttributePathParamsList = attributePaths.get(); - params.mAttributePathParamsListSize = numAttributePaths; - attributePaths.release(); - } - - if (dataVersionFilterList != nullptr) - { - jint jNumDataVersionFilters = 0; - SuccessOrExit(err = JniReferences::GetInstance().GetListSize(dataVersionFilterList, jNumDataVersionFilters)); - numDataVersionFilters = static_cast(jNumDataVersionFilters); - } - - if (numDataVersionFilters > 0) - { - std::unique_ptr dataVersionFilters(new chip::app::DataVersionFilter[numDataVersionFilters]); - for (uint8_t i = 0; i < numDataVersionFilters; i++) - { - jobject dataVersionFilterItem = nullptr; - SuccessOrExit(err = JniReferences::GetInstance().GetListItem(dataVersionFilterList, i, dataVersionFilterItem)); - - EndpointId endpointId; - ClusterId clusterId; - DataVersion dataVersion; - SuccessOrExit(err = ParseDataVersionFilter(dataVersionFilterItem, endpointId, clusterId, dataVersion)); - dataVersionFilters[i] = chip::app::DataVersionFilter(endpointId, clusterId, dataVersion); - } - params.mpDataVersionFilterList = dataVersionFilters.get(); - params.mDataVersionFilterListSize = numDataVersionFilters; - dataVersionFilters.release(); - } - - if (eventMin != nullptr) - { - params.mEventNumber.SetValue(static_cast(JniReferences::GetInstance().LongToPrimitive(eventMin))); - } - - if (eventPathList != nullptr) - { - jint jNumEventPaths = 0; - SuccessOrExit(err = JniReferences::GetInstance().GetListSize(eventPathList, jNumEventPaths)); - numEventPaths = static_cast(jNumEventPaths); - } - - if (numEventPaths > 0) - { - std::unique_ptr eventPaths(new chip::app::EventPathParams[numEventPaths]); - for (uint8_t i = 0; i < numEventPaths; i++) - { - jobject eventPathItem = nullptr; - SuccessOrExit(err = JniReferences::GetInstance().GetListItem(eventPathList, i, eventPathItem)); - - EndpointId endpointId; - ClusterId clusterId; - EventId eventId; - bool isUrgent; - SuccessOrExit(err = ParseEventPath(eventPathItem, endpointId, clusterId, eventId, isUrgent)); - eventPaths[i] = chip::app::EventPathParams(endpointId, clusterId, eventId, isUrgent); - } - - params.mpEventPathParamsList = eventPaths.get(); - params.mEventPathParamsListSize = static_cast(numEventPaths); - eventPaths.release(); - } - - readClient = Platform::New(app::InteractionModelEngine::GetInstance(), device->GetExchangeManager(), - callback->mClusterCacheAdapter.GetBufferedCallback(), - app::ReadClient::InteractionType::Subscribe); - - SuccessOrExit(err = readClient->SendAutoResubscribeRequest(std::move(params))); - callback->mReadClient = readClient; - -exit: + CHIP_ERROR err = subscribe(env, handle, callbackHandle, devicePtr, attributePathList, eventPathList, dataVersionFilterList, + minInterval, maxInterval, keepSubscriptions, isFabricFiltered, imTimeoutMs, eventMin); if (err != CHIP_NO_ERROR) { - ChipLogError(Controller, "JNI IM Subscribe Error: %s", err.AsString()); - if (err == CHIP_JNI_ERROR_EXCEPTION_THROWN) - { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - callback->OnError(err); - if (readClient != nullptr) - { - Platform::Delete(readClient); - } - if (callback != nullptr) - { - Platform::Delete(callback); - } + ChipLogError(Controller, "JNI IM Subscribe Error: %" CHIP_ERROR_FORMAT, err.Format()); } } @@ -2395,659 +2255,34 @@ JNI_METHOD(void, read) (JNIEnv * env, jclass clz, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, jobject eventPathList, jobject dataVersionFilterList, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin) { - chip::DeviceLayer::StackLock lock; - CHIP_ERROR err = CHIP_NO_ERROR; - - auto callback = reinterpret_cast(callbackHandle); - std::vector attributePathParamsList; - std::vector eventPathParamsList; - std::vector versionList; - app::ReadClient * readClient = nullptr; - DeviceProxy * device = reinterpret_cast(devicePtr); - if (device == nullptr) - { - ChipLogProgress(Controller, "Could not cast device pointer to Device object"); - JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, CHIP_ERROR_INCORRECT_STATE); - return; - } - app::ReadPrepareParams params(device->GetSecureSession().Value()); - - SuccessOrExit(err = ParseAttributePathList(attributePathList, attributePathParamsList)); - SuccessOrExit(err = ParseEventPathList(eventPathList, eventPathParamsList)); - SuccessOrExit(err = ParseDataVersionFilterList(dataVersionFilterList, versionList)); - VerifyOrExit(attributePathParamsList.size() != 0 || eventPathParamsList.size() != 0, err = CHIP_ERROR_INVALID_ARGUMENT); - params.mpAttributePathParamsList = attributePathParamsList.data(); - params.mAttributePathParamsListSize = attributePathParamsList.size(); - params.mpEventPathParamsList = eventPathParamsList.data(); - params.mEventPathParamsListSize = eventPathParamsList.size(); - if (versionList.size() != 0) - { - params.mpDataVersionFilterList = versionList.data(); - params.mDataVersionFilterListSize = versionList.size(); - } - - params.mIsFabricFiltered = (isFabricFiltered != JNI_FALSE); - params.mTimeout = imTimeoutMs != 0 ? System::Clock::Milliseconds32(imTimeoutMs) : System::Clock::kZero; - - if (eventMin != nullptr) - { - params.mEventNumber.SetValue(static_cast(JniReferences::GetInstance().LongToPrimitive(eventMin))); - } - - readClient = Platform::New(app::InteractionModelEngine::GetInstance(), device->GetExchangeManager(), - callback->mClusterCacheAdapter.GetBufferedCallback(), - app::ReadClient::InteractionType::Read); - - SuccessOrExit(err = readClient->SendRequest(params)); - callback->mReadClient = readClient; - -exit: + CHIP_ERROR err = read(env, handle, callbackHandle, devicePtr, attributePathList, eventPathList, dataVersionFilterList, + isFabricFiltered, imTimeoutMs, eventMin); if (err != CHIP_NO_ERROR) { - ChipLogError(Controller, "JNI IM Read Error: %s", err.AsString()); - if (err == CHIP_JNI_ERROR_EXCEPTION_THROWN) - { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - callback->OnError(err); - if (readClient != nullptr) - { - Platform::Delete(readClient); - } - if (callback != nullptr) - { - Platform::Delete(callback); - } + ChipLogError(Controller, "JNI IM Read Error: %" CHIP_ERROR_FORMAT, err.Format()); } } -// Convert Json to Tlv, and remove the outer structure -CHIP_ERROR ConvertJsonToTlvWithoutStruct(const std::string & json, MutableByteSpan & data) -{ - Platform::ScopedMemoryBufferWithSize buf; - VerifyOrReturnError(buf.Calloc(data.size()), CHIP_ERROR_NO_MEMORY); - MutableByteSpan dataWithStruct(buf.Get(), buf.AllocatedSize()); - ReturnErrorOnFailure(JsonToTlv(json, dataWithStruct)); - TLV::TLVReader tlvReader; - TLV::TLVType outerContainer = TLV::kTLVType_Structure; - tlvReader.Init(dataWithStruct); - ReturnErrorOnFailure(tlvReader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); - ReturnErrorOnFailure(tlvReader.EnterContainer(outerContainer)); - ReturnErrorOnFailure(tlvReader.Next()); - - TLV::TLVWriter tlvWrite; - tlvWrite.Init(data); - ReturnErrorOnFailure(tlvWrite.CopyElement(TLV::AnonymousTag(), tlvReader)); - ReturnErrorOnFailure(tlvWrite.Finalize()); - data.reduce_size(tlvWrite.GetLengthWritten()); - return CHIP_NO_ERROR; -} - -CHIP_ERROR PutPreencodedWriteAttribute(app::WriteClient & writeClient, app::ConcreteDataAttributePath & path, const ByteSpan & data) -{ - TLV::TLVReader reader; - reader.Init(data); - ReturnErrorOnFailure(reader.Next()); - return writeClient.PutPreencodedAttribute(path, reader); -} - JNI_METHOD(void, write) (JNIEnv * env, jclass clz, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributeList, jint timedRequestTimeoutMs, jint imTimeoutMs) { - chip::DeviceLayer::StackLock lock; - CHIP_ERROR err = CHIP_NO_ERROR; - jint listSize = 0; - auto callback = reinterpret_cast(callbackHandle); - app::WriteClient * writeClient = nullptr; - uint16_t convertedTimedRequestTimeoutMs = static_cast(timedRequestTimeoutMs); - - ChipLogDetail(Controller, "IM write() called"); - - DeviceProxy * device = reinterpret_cast(devicePtr); - VerifyOrExit(device != nullptr, err = CHIP_ERROR_INCORRECT_STATE); - VerifyOrExit(device->GetSecureSession().HasValue(), err = CHIP_ERROR_MISSING_SECURE_SESSION); - VerifyOrExit(attributeList != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - SuccessOrExit(err = JniReferences::GetInstance().GetListSize(attributeList, listSize)); - - writeClient = Platform::New( - device->GetExchangeManager(), callback->GetChunkedWriteCallback(), - convertedTimedRequestTimeoutMs != 0 ? Optional(convertedTimedRequestTimeoutMs) : Optional::Missing()); - - for (uint8_t i = 0; i < listSize; i++) - { - jobject attributeItem = nullptr; - uint32_t endpointId = 0; - uint32_t clusterId = 0; - uint32_t attributeId = 0; - jmethodID getEndpointIdMethod = nullptr; - jmethodID getClusterIdMethod = nullptr; - jmethodID getAttributeIdMethod = nullptr; - jmethodID hasDataVersionMethod = nullptr; - jmethodID getDataVersionMethod = nullptr; - jmethodID getTlvByteArrayMethod = nullptr; - jmethodID getJsonStringMethod = nullptr; - jobject endpointIdObj = nullptr; - jobject clusterIdObj = nullptr; - jobject attributeIdObj = nullptr; - jbyteArray tlvBytesObj = nullptr; - bool hasDataVersion = false; - Optional dataVersion = Optional(); - - bool isGroupSession = false; - - SuccessOrExit(err = JniReferences::GetInstance().GetListItem(attributeList, i, attributeItem)); - SuccessOrExit(err = JniReferences::GetInstance().FindMethod( - env, attributeItem, "getEndpointId", "()Lchip/devicecontroller/model/ChipPathId;", &getEndpointIdMethod)); - SuccessOrExit(err = JniReferences::GetInstance().FindMethod( - env, attributeItem, "getClusterId", "()Lchip/devicecontroller/model/ChipPathId;", &getClusterIdMethod)); - SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, attributeItem, "getAttributeId", - "()Lchip/devicecontroller/model/ChipPathId;", - &getAttributeIdMethod)); - SuccessOrExit( - err = JniReferences::GetInstance().FindMethod(env, attributeItem, "hasDataVersion", "()Z", &hasDataVersionMethod)); - SuccessOrExit( - err = JniReferences::GetInstance().FindMethod(env, attributeItem, "getDataVersion", "()I", &getDataVersionMethod)); - SuccessOrExit( - err = JniReferences::GetInstance().FindMethod(env, attributeItem, "getTlvByteArray", "()[B", &getTlvByteArrayMethod)); - - isGroupSession = device->GetSecureSession().Value()->IsGroupSession(); - - if (isGroupSession) - { - endpointId = kInvalidEndpointId; - } - else - { - endpointIdObj = env->CallObjectMethod(attributeItem, getEndpointIdMethod); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrExit(endpointIdObj != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - - SuccessOrExit(err = GetChipPathIdValue(endpointIdObj, kInvalidEndpointId, endpointId)); - } - - clusterIdObj = env->CallObjectMethod(attributeItem, getClusterIdMethod); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrExit(clusterIdObj != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - - attributeIdObj = env->CallObjectMethod(attributeItem, getAttributeIdMethod); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrExit(attributeIdObj != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - - SuccessOrExit(err = GetChipPathIdValue(clusterIdObj, kInvalidClusterId, clusterId)); - SuccessOrExit(err = GetChipPathIdValue(attributeIdObj, kInvalidAttributeId, attributeId)); - - hasDataVersion = static_cast(env->CallBooleanMethod(attributeItem, hasDataVersionMethod)); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - if (hasDataVersion) - { - DataVersion dataVersionVal = static_cast(env->CallIntMethod(attributeItem, getDataVersionMethod)); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - dataVersion.SetValue(dataVersionVal); - } - - tlvBytesObj = static_cast(env->CallObjectMethod(attributeItem, getTlvByteArrayMethod)); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - app::ConcreteDataAttributePath path(static_cast(endpointId), static_cast(clusterId), - static_cast(attributeId), dataVersion); - if (tlvBytesObj != nullptr) - { - JniByteArray tlvByteArray(env, tlvBytesObj); - SuccessOrExit(err = PutPreencodedWriteAttribute(*writeClient, path, tlvByteArray.byteSpan())); - } - else - { - SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, attributeItem, "getJsonString", "()Ljava/lang/String;", - &getJsonStringMethod)); - jstring jsonJniString = static_cast(env->CallObjectMethod(attributeItem, getJsonStringMethod)); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrExit(jsonJniString != nullptr, err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - JniUtfString jsonUtfJniString(env, jsonJniString); - std::string jsonString = std::string(jsonUtfJniString.c_str(), static_cast(jsonUtfJniString.size())); - - // Context: Chunk write is supported in sdk, oversized list could be chunked in multiple message. When transforming - // JSON to TLV, we need know the actual size for tlv blob when handling JsonToTlv - // TODO: Implement memory auto-grow to get the actual size needed for tlv blob when transforming tlv to json. - // Workaround: Allocate memory using json string's size, which is large enough to hold the corresponding tlv blob - Platform::ScopedMemoryBufferWithSize tlvBytes; - size_t length = static_cast(jsonUtfJniString.size()); - VerifyOrExit(tlvBytes.Calloc(length), err = CHIP_ERROR_NO_MEMORY); - MutableByteSpan data(tlvBytes.Get(), tlvBytes.AllocatedSize()); - SuccessOrExit(err = ConvertJsonToTlvWithoutStruct(jsonString, data)); - SuccessOrExit(err = PutPreencodedWriteAttribute(*writeClient, path, data)); - } - } - - err = writeClient->SendWriteRequest(device->GetSecureSession().Value(), - imTimeoutMs != 0 ? System::Clock::Milliseconds32(imTimeoutMs) : System::Clock::kZero); - SuccessOrExit(err); - callback->mWriteClient = writeClient; - -exit: + CHIP_ERROR err = write(env, handle, callbackHandle, devicePtr, attributeList, timedRequestTimeoutMs, imTimeoutMs); if (err != CHIP_NO_ERROR) { - ChipLogError(Controller, "JNI IM Write Error: %s", err.AsString()); - if (err == CHIP_JNI_ERROR_EXCEPTION_THROWN) - { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - callback->OnError(writeClient, err); - if (writeClient != nullptr) - { - Platform::Delete(writeClient); - } - if (callback != nullptr) - { - Platform::Delete(callback); - } + ChipLogError(Controller, "JNI IM Write Error: %" CHIP_ERROR_FORMAT, err.Format()); } } -CHIP_ERROR PutPreencodedInvokeRequest(app::CommandSender & commandSender, app::CommandPathParams & path, const ByteSpan & data) -{ - // PrepareCommand does nott create the struct container with kFields and copycontainer below sets the - // kFields container already - ReturnErrorOnFailure(commandSender.PrepareCommand(path, false /* aStartDataStruct */)); - TLV::TLVWriter * writer = commandSender.GetCommandDataIBTLVWriter(); - VerifyOrReturnError(writer != nullptr, CHIP_ERROR_INCORRECT_STATE); - TLV::TLVReader reader; - reader.Init(data); - ReturnErrorOnFailure(reader.Next()); - return writer->CopyContainer(TLV::ContextTag(app::CommandDataIB::Tag::kFields), reader); -} - JNI_METHOD(void, invoke) (JNIEnv * env, jclass clz, jlong handle, jlong callbackHandle, jlong devicePtr, jobject invokeElement, jint timedRequestTimeoutMs, jint imTimeoutMs) { - chip::DeviceLayer::StackLock lock; - CHIP_ERROR err = CHIP_NO_ERROR; - auto callback = reinterpret_cast(callbackHandle); - app::CommandSender * commandSender = nullptr; - uint32_t endpointId = 0; - uint32_t clusterId = 0; - uint32_t commandId = 0; - uint16_t groupId = 0; - bool isEndpointIdValid = false; - bool isGroupIdValid = false; - jmethodID getEndpointIdMethod = nullptr; - jmethodID getClusterIdMethod = nullptr; - jmethodID getCommandIdMethod = nullptr; - jmethodID getGroupIdMethod = nullptr; - jmethodID getTlvByteArrayMethod = nullptr; - jmethodID getJsonStringMethod = nullptr; - jmethodID isEndpointIdValidMethod = nullptr; - jmethodID isGroupIdValidMethod = nullptr; - jobject endpointIdObj = nullptr; - jobject clusterIdObj = nullptr; - jobject commandIdObj = nullptr; - jobject groupIdObj = nullptr; - jbyteArray tlvBytesObj = nullptr; - uint16_t convertedTimedRequestTimeoutMs = static_cast(timedRequestTimeoutMs); - ChipLogDetail(Controller, "IM invoke() called"); - - DeviceProxy * device = reinterpret_cast(devicePtr); - VerifyOrExit(device != nullptr, err = CHIP_ERROR_INCORRECT_STATE); - VerifyOrExit(device->GetSecureSession().HasValue(), err = CHIP_ERROR_MISSING_SECURE_SESSION); - - commandSender = Platform::New(callback, device->GetExchangeManager(), timedRequestTimeoutMs != 0); - - SuccessOrExit(err = JniReferences::GetInstance().FindMethod( - env, invokeElement, "getEndpointId", "()Lchip/devicecontroller/model/ChipPathId;", &getEndpointIdMethod)); - SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getClusterId", - "()Lchip/devicecontroller/model/ChipPathId;", &getClusterIdMethod)); - SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getCommandId", - "()Lchip/devicecontroller/model/ChipPathId;", &getCommandIdMethod)); - SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getGroupId", "()Ljava/util/Optional;", - &getGroupIdMethod)); - SuccessOrExit( - err = JniReferences::GetInstance().FindMethod(env, invokeElement, "isEndpointIdValid", "()Z", &isEndpointIdValidMethod)); - SuccessOrExit(err = - JniReferences::GetInstance().FindMethod(env, invokeElement, "isGroupIdValid", "()Z", &isGroupIdValidMethod)); - SuccessOrExit( - err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getTlvByteArray", "()[B", &getTlvByteArrayMethod)); - - isEndpointIdValid = (env->CallBooleanMethod(invokeElement, isEndpointIdValidMethod) == JNI_TRUE); - isGroupIdValid = (env->CallBooleanMethod(invokeElement, isGroupIdValidMethod) == JNI_TRUE); - - if (isEndpointIdValid) - { - endpointIdObj = env->CallObjectMethod(invokeElement, getEndpointIdMethod); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrExit(endpointIdObj != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - - SuccessOrExit(err = GetChipPathIdValue(endpointIdObj, kInvalidEndpointId, endpointId)); - } - - if (isGroupIdValid) - { - VerifyOrExit(device->GetSecureSession().Value()->IsGroupSession(), err = CHIP_ERROR_INVALID_ARGUMENT); - groupIdObj = env->CallObjectMethod(invokeElement, getGroupIdMethod); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrExit(groupIdObj != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - - jobject boxedGroupId = nullptr; - - SuccessOrExit(err = JniReferences::GetInstance().GetOptionalValue(groupIdObj, boxedGroupId)); - VerifyOrExit(boxedGroupId != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - groupId = static_cast(JniReferences::GetInstance().IntegerToPrimitive(boxedGroupId)); - } - - clusterIdObj = env->CallObjectMethod(invokeElement, getClusterIdMethod); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrExit(clusterIdObj != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - - commandIdObj = env->CallObjectMethod(invokeElement, getCommandIdMethod); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrExit(commandIdObj != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - - SuccessOrExit(err = GetChipPathIdValue(clusterIdObj, kInvalidClusterId, clusterId)); - SuccessOrExit(err = GetChipPathIdValue(commandIdObj, kInvalidCommandId, commandId)); - - tlvBytesObj = static_cast(env->CallObjectMethod(invokeElement, getTlvByteArrayMethod)); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - { - uint16_t id = isEndpointIdValid ? static_cast(endpointId) : groupId; - app::CommandPathFlags flag = - isEndpointIdValid ? app::CommandPathFlags::kEndpointIdValid : app::CommandPathFlags::kGroupIdValid; - app::CommandPathParams path(id, static_cast(clusterId), static_cast(commandId), flag); - if (tlvBytesObj != nullptr) - { - JniByteArray tlvBytesObjBytes(env, tlvBytesObj); - SuccessOrExit(err = PutPreencodedInvokeRequest(*commandSender, path, tlvBytesObjBytes.byteSpan())); - } - else - { - SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getJsonString", "()Ljava/lang/String;", - &getJsonStringMethod)); - jstring jsonJniString = static_cast(env->CallObjectMethod(invokeElement, getJsonStringMethod)); - VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrExit(jsonJniString != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - JniUtfString jsonUtfJniString(env, jsonJniString); - // The invoke does not support chunk, kMaxSecureSduLengthBytes should be enough for command json blob - uint8_t tlvBytes[chip::app::kMaxSecureSduLengthBytes] = { 0 }; - MutableByteSpan tlvEncodingLocal{ tlvBytes }; - SuccessOrExit(err = JsonToTlv(std::string(jsonUtfJniString.c_str(), static_cast(jsonUtfJniString.size())), - tlvEncodingLocal)); - SuccessOrExit(err = PutPreencodedInvokeRequest(*commandSender, path, tlvEncodingLocal)); - } - } - SuccessOrExit(err = commandSender->FinishCommand(convertedTimedRequestTimeoutMs != 0 - ? Optional(convertedTimedRequestTimeoutMs) - : Optional::Missing())); - - SuccessOrExit(err = device->GetSecureSession().Value()->IsGroupSession() - ? commandSender->SendGroupCommandRequest(device->GetSecureSession().Value()) - : commandSender->SendCommandRequest(device->GetSecureSession().Value(), - imTimeoutMs != 0 - ? MakeOptional(System::Clock::Milliseconds32(imTimeoutMs)) - : Optional::Missing())); - - callback->mCommandSender = commandSender; - -exit: + CHIP_ERROR err = invoke(env, handle, callbackHandle, devicePtr, invokeElement, timedRequestTimeoutMs, imTimeoutMs); if (err != CHIP_NO_ERROR) { - ChipLogError(Controller, "JNI IM Invoke Error: %s", err.AsString()); - if (err == CHIP_JNI_ERROR_EXCEPTION_THROWN) - { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - callback->OnError(nullptr, err); - if (commandSender != nullptr) - { - Platform::Delete(commandSender); - } - if (callback != nullptr) - { - Platform::Delete(callback); - } - } -} - -/** - * Takes objects in attributePathList, converts them to app:AttributePathParams, and appends them to outAttributePathParamsList. - */ -CHIP_ERROR ParseAttributePathList(jobject attributePathList, std::vector & outAttributePathParamsList) -{ - jint listSize; - - if (attributePathList == nullptr) - { - return CHIP_NO_ERROR; - } - - ReturnErrorOnFailure(JniReferences::GetInstance().GetListSize(attributePathList, listSize)); - - for (uint8_t i = 0; i < listSize; i++) - { - jobject attributePathItem = nullptr; - ReturnErrorOnFailure(JniReferences::GetInstance().GetListItem(attributePathList, i, attributePathItem)); - - EndpointId endpointId; - ClusterId clusterId; - AttributeId attributeId; - ReturnErrorOnFailure(ParseAttributePath(attributePathItem, endpointId, clusterId, attributeId)); - outAttributePathParamsList.push_back(app::AttributePathParams(endpointId, clusterId, attributeId)); - } - - return CHIP_NO_ERROR; -} - -CHIP_ERROR ParseAttributePath(jobject attributePath, EndpointId & outEndpointId, ClusterId & outClusterId, - AttributeId & outAttributeId) -{ - JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); - - jmethodID getEndpointIdMethod = nullptr; - jmethodID getClusterIdMethod = nullptr; - jmethodID getAttributeIdMethod = nullptr; - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod( - env, attributePath, "getEndpointId", "()Lchip/devicecontroller/model/ChipPathId;", &getEndpointIdMethod)); - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod( - env, attributePath, "getClusterId", "()Lchip/devicecontroller/model/ChipPathId;", &getClusterIdMethod)); - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod( - env, attributePath, "getAttributeId", "()Lchip/devicecontroller/model/ChipPathId;", &getAttributeIdMethod)); - - jobject endpointIdObj = env->CallObjectMethod(attributePath, getEndpointIdMethod); - VerifyOrReturnError(endpointIdObj != nullptr, CHIP_ERROR_INCORRECT_STATE); - jobject clusterIdObj = env->CallObjectMethod(attributePath, getClusterIdMethod); - VerifyOrReturnError(clusterIdObj != nullptr, CHIP_ERROR_INCORRECT_STATE); - jobject attributeIdObj = env->CallObjectMethod(attributePath, getAttributeIdMethod); - VerifyOrReturnError(attributeIdObj != nullptr, CHIP_ERROR_INCORRECT_STATE); - - uint32_t endpointId = 0; - ReturnErrorOnFailure(GetChipPathIdValue(endpointIdObj, kInvalidEndpointId, endpointId)); - uint32_t clusterId = 0; - ReturnErrorOnFailure(GetChipPathIdValue(clusterIdObj, kInvalidClusterId, clusterId)); - uint32_t attributeId = 0; - ReturnErrorOnFailure(GetChipPathIdValue(attributeIdObj, kInvalidAttributeId, attributeId)); - - outEndpointId = static_cast(endpointId); - outClusterId = static_cast(clusterId); - outAttributeId = static_cast(attributeId); - - return CHIP_NO_ERROR; -} - -/** - * Takes objects in eventPathList, converts them to app:EventPathParams, and appends them to outEventPathParamsList. - */ -CHIP_ERROR ParseEventPathList(jobject eventPathList, std::vector & outEventPathParamsList) -{ - jint listSize; - - if (eventPathList == nullptr) - { - return CHIP_NO_ERROR; - } - - ReturnErrorOnFailure(JniReferences::GetInstance().GetListSize(eventPathList, listSize)); - - for (uint8_t i = 0; i < listSize; i++) - { - jobject eventPathItem = nullptr; - ReturnErrorOnFailure(JniReferences::GetInstance().GetListItem(eventPathList, i, eventPathItem)); - - EndpointId endpointId; - ClusterId clusterId; - EventId eventId; - bool isUrgent; - ReturnErrorOnFailure(ParseEventPath(eventPathItem, endpointId, clusterId, eventId, isUrgent)); - outEventPathParamsList.push_back(app::EventPathParams(endpointId, clusterId, eventId, isUrgent)); - } - - return CHIP_NO_ERROR; -} - -CHIP_ERROR ParseEventPath(jobject eventPath, EndpointId & outEndpointId, ClusterId & outClusterId, EventId & outEventId, - bool & outIsUrgent) -{ - JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); - - jmethodID getEndpointIdMethod = nullptr; - jmethodID getClusterIdMethod = nullptr; - jmethodID getEventIdMethod = nullptr; - jmethodID isUrgentMethod = nullptr; - - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod( - env, eventPath, "getEndpointId", "()Lchip/devicecontroller/model/ChipPathId;", &getEndpointIdMethod)); - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod( - env, eventPath, "getClusterId", "()Lchip/devicecontroller/model/ChipPathId;", &getClusterIdMethod)); - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, eventPath, "getEventId", - "()Lchip/devicecontroller/model/ChipPathId;", &getEventIdMethod)); - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, eventPath, "isUrgent", "()Z", &isUrgentMethod)); - - jobject endpointIdObj = env->CallObjectMethod(eventPath, getEndpointIdMethod); - VerifyOrReturnError(endpointIdObj != nullptr, CHIP_ERROR_INCORRECT_STATE); - jobject clusterIdObj = env->CallObjectMethod(eventPath, getClusterIdMethod); - VerifyOrReturnError(clusterIdObj != nullptr, CHIP_ERROR_INCORRECT_STATE); - jobject eventIdObj = env->CallObjectMethod(eventPath, getEventIdMethod); - VerifyOrReturnError(eventIdObj != nullptr, CHIP_ERROR_INCORRECT_STATE); - jboolean isUrgent = env->CallBooleanMethod(eventPath, isUrgentMethod); - - uint32_t endpointId = 0; - ReturnErrorOnFailure(GetChipPathIdValue(endpointIdObj, kInvalidEndpointId, endpointId)); - uint32_t clusterId = 0; - ReturnErrorOnFailure(GetChipPathIdValue(clusterIdObj, kInvalidClusterId, clusterId)); - uint32_t eventId = 0; - ReturnErrorOnFailure(GetChipPathIdValue(eventIdObj, kInvalidEventId, eventId)); - - outEndpointId = static_cast(endpointId); - outClusterId = static_cast(clusterId); - outEventId = static_cast(eventId); - outIsUrgent = (isUrgent == JNI_TRUE); - - return CHIP_NO_ERROR; -} - -/** - * Takes objects in dataVersionFilterList, converts them to app:DataVersionFilter, and appends them to outDataVersionFilterList. - */ -CHIP_ERROR ParseDataVersionFilterList(jobject dataVersionFilterList, std::vector & outDataVersionFilterList) -{ - jint listSize; - - if (dataVersionFilterList == nullptr) - { - return CHIP_NO_ERROR; - } - - ReturnErrorOnFailure(JniReferences::GetInstance().GetListSize(dataVersionFilterList, listSize)); - - for (uint8_t i = 0; i < listSize; i++) - { - jobject dataVersionFilterItem = nullptr; - ReturnErrorOnFailure(JniReferences::GetInstance().GetListItem(dataVersionFilterList, i, dataVersionFilterItem)); - - EndpointId endpointId; - ClusterId clusterId; - DataVersion dataVersion; - ReturnErrorOnFailure(ParseDataVersionFilter(dataVersionFilterItem, endpointId, clusterId, dataVersion)); - outDataVersionFilterList.push_back(app::DataVersionFilter(endpointId, clusterId, dataVersion)); + ChipLogError(Controller, "JNI IM Invoke Error: %" CHIP_ERROR_FORMAT, err.Format()); } - - return CHIP_NO_ERROR; -} - -CHIP_ERROR ParseDataVersionFilter(jobject versionFilter, EndpointId & outEndpointId, ClusterId & outClusterId, - DataVersion & outDataVersion) -{ - JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); - - jmethodID getEndpointIdMethod = nullptr; - jmethodID getClusterIdMethod = nullptr; - jmethodID getDataVersionMethod = nullptr; - - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod( - env, versionFilter, "getEndpointId", "()Lchip/devicecontroller/model/ChipPathId;", &getEndpointIdMethod)); - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod( - env, versionFilter, "getClusterId", "()Lchip/devicecontroller/model/ChipPathId;", &getClusterIdMethod)); - ReturnErrorOnFailure( - JniReferences::GetInstance().FindMethod(env, versionFilter, "getDataVersion", "()J", &getDataVersionMethod)); - - jobject endpointIdObj = env->CallObjectMethod(versionFilter, getEndpointIdMethod); - VerifyOrReturnError(endpointIdObj != nullptr, CHIP_ERROR_INCORRECT_STATE); - uint32_t endpointId = 0; - ReturnErrorOnFailure(GetChipPathIdValue(endpointIdObj, kInvalidEndpointId, endpointId)); - outEndpointId = static_cast(endpointId); - jobject clusterIdObj = env->CallObjectMethod(versionFilter, getClusterIdMethod); - VerifyOrReturnError(clusterIdObj != nullptr, CHIP_ERROR_INCORRECT_STATE); - uint32_t clusterId = 0; - ReturnErrorOnFailure(GetChipPathIdValue(clusterIdObj, kInvalidClusterId, clusterId)); - outClusterId = static_cast(clusterId); - - outDataVersion = static_cast(env->CallLongMethod(versionFilter, getDataVersionMethod)); - return CHIP_NO_ERROR; -} - -CHIP_ERROR GetChipPathIdValue(jobject chipPathId, uint32_t wildcardValue, uint32_t & outValue) -{ - JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); - - bool idIsWildcard = false; - ReturnErrorOnFailure(IsWildcardChipPathId(chipPathId, idIsWildcard)); - - if (idIsWildcard) - { - outValue = wildcardValue; - return CHIP_NO_ERROR; - } - - jmethodID getIdMethod = nullptr; - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, chipPathId, "getId", "()J", &getIdMethod)); - outValue = static_cast(env->CallLongMethod(chipPathId, getIdMethod)); - VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR IsWildcardChipPathId(jobject chipPathId, bool & isWildcard) -{ - JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); - jmethodID getTypeMethod = nullptr; - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod( - env, chipPathId, "getType", "()Lchip/devicecontroller/model/ChipPathId$IdType;", &getTypeMethod)); - - jobject idType = env->CallObjectMethod(chipPathId, getTypeMethod); - VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrReturnError(idType != nullptr, CHIP_JNI_ERROR_NULL_OBJECT); - - jmethodID nameMethod = nullptr; - ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, idType, "name", "()Ljava/lang/String;", &nameMethod)); - - jstring typeNameString = static_cast(env->CallObjectMethod(idType, nameMethod)); - VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); - VerifyOrReturnError(typeNameString != nullptr, CHIP_JNI_ERROR_NULL_OBJECT); - - JniUtfString typeNameJniString(env, typeNameString); - - isWildcard = strncmp(typeNameJniString.c_str(), "WILDCARD", 8) == 0; - - return CHIP_NO_ERROR; } void * IOThreadMain(void * arg) diff --git a/src/controller/java/MatterCallbacks-JNI.cpp b/src/controller/java/MatterCallbacks-JNI.cpp new file mode 100644 index 00000000000000..f20d9e47f093ff --- /dev/null +++ b/src/controller/java/MatterCallbacks-JNI.cpp @@ -0,0 +1,71 @@ +/* + * + * 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. + */ +#include "AndroidCallbacks.h" + +#include +#include +#include +#include + +#define JNI_METHOD(RETURN, CLASS_NAME, METHOD_NAME) \ + extern "C" JNIEXPORT RETURN JNICALL Java_matter_controller_##CLASS_NAME##_##METHOD_NAME + +using namespace chip::Controller; + +JNI_METHOD(jlong, GetConnectedDeviceCallbackJni, newCallback)(JNIEnv * env, jobject self, jobject callback) +{ + return newConnectedDeviceCallback(env, self, callback); +} + +JNI_METHOD(void, GetConnectedDeviceCallbackJni, deleteCallback)(JNIEnv * env, jobject self, jlong callbackHandle) +{ + deleteConnectedDeviceCallback(env, self, callbackHandle); +} + +JNI_METHOD(jlong, ReportCallbackJni, newCallback) +(JNIEnv * env, jobject self, jobject subscriptionEstablishedCallbackJava, jobject resubscriptionAttemptCallbackJava) +{ + return newReportCallback(env, self, subscriptionEstablishedCallbackJava, resubscriptionAttemptCallbackJava, + "()Lmatter/controller/model/NodeState;"); +} + +JNI_METHOD(void, ReportCallbackJni, deleteCallback)(JNIEnv * env, jobject self, jlong callbackHandle) +{ + deleteReportCallback(env, self, callbackHandle); +} + +JNI_METHOD(jlong, WriteAttributesCallbackJni, newCallback) +(JNIEnv * env, jobject self) +{ + return newWriteAttributesCallback(env, self); +} + +JNI_METHOD(void, WriteAttributesCallbackJni, deleteCallback)(JNIEnv * env, jobject self, jlong callbackHandle) +{ + deleteWriteAttributesCallback(env, self, callbackHandle); +} + +JNI_METHOD(jlong, InvokeCallbackJni, newCallback) +(JNIEnv * env, jobject self) +{ + return newInvokeCallback(env, self); +} + +JNI_METHOD(void, InvokeCallbackJni, deleteCallback)(JNIEnv * env, jobject self, jlong callbackHandle) +{ + deleteInvokeCallback(env, self, callbackHandle); +} diff --git a/src/controller/java/MatterInteractionClient-JNI.cpp b/src/controller/java/MatterInteractionClient-JNI.cpp new file mode 100644 index 00000000000000..6a541723d041ed --- /dev/null +++ b/src/controller/java/MatterInteractionClient-JNI.cpp @@ -0,0 +1,67 @@ +/* + * 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 "AndroidInteractionClient.h" + +#define JNI_METHOD(RETURN, METHOD_NAME) \ + extern "C" JNIEXPORT RETURN JNICALL Java_matter_controller_MatterControllerImpl_##METHOD_NAME + +JNI_METHOD(void, subscribe) +(JNIEnv * env, jobject self, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, jobject eventPathList, + jint minInterval, jint maxInterval, jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs) +{ + CHIP_ERROR err = subscribe(env, handle, callbackHandle, devicePtr, attributePathList, eventPathList, nullptr, minInterval, + maxInterval, keepSubscriptions, isFabricFiltered, imTimeoutMs, nullptr); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "JNI IM Subscribe Error: %" CHIP_ERROR_FORMAT, err.Format()); + } +} + +JNI_METHOD(void, read) +(JNIEnv * env, jobject self, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, jobject eventPathList, + jboolean isFabricFiltered, jint imTimeoutMs) +{ + CHIP_ERROR err = read(env, handle, callbackHandle, devicePtr, attributePathList, eventPathList, nullptr, isFabricFiltered, + imTimeoutMs, nullptr); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "JNI IM Read Error: %" CHIP_ERROR_FORMAT, err.Format()); + } +} + +JNI_METHOD(void, write) +(JNIEnv * env, jobject self, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributeList, jint timedRequestTimeoutMs, + jint imTimeoutMs) +{ + CHIP_ERROR err = write(env, handle, callbackHandle, devicePtr, attributeList, timedRequestTimeoutMs, imTimeoutMs); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "JNI IM Write Error: %" CHIP_ERROR_FORMAT, err.Format()); + } +} + +JNI_METHOD(void, invoke) +(JNIEnv * env, jobject self, jlong handle, jlong callbackHandle, jlong devicePtr, jobject invokeElement, jint timedRequestTimeoutMs, + jint imTimeoutMs) +{ + CHIP_ERROR err = invoke(env, handle, callbackHandle, devicePtr, invokeElement, timedRequestTimeoutMs, imTimeoutMs); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "JNI IM Invoke Error: %" CHIP_ERROR_FORMAT, err.Format()); + } +} diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index 6e479c5f37094c..fcc9154511d2b7 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -25,6 +25,7 @@ import chip.devicecontroller.model.EndpointState; import chip.devicecontroller.model.InvokeElement; import chip.devicecontroller.model.NodeState; +import chip.devicecontroller.model.Status; import javax.annotation.Nullable; import java.util.ArrayList; @@ -241,8 +242,15 @@ static class WriteAttributesCallbackImpl implements WriteAttributesCallback { } @Override - public void onResponse(ChipAttributePath attributePath) { - callback.onSuccess(); + public void onResponse(ChipAttributePath attributePath, Status status) { + if (status.getStatus() == Status.Code.Success) + { + callback.onSuccess(); + } + else + { + callback.onError(new StatusException(status.getStatus())); + } } @Override diff --git a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java index bbf247b09e5a9d..9e5c6e12f42520 100644 --- a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java +++ b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java @@ -51,6 +51,11 @@ public static void loadJni() { return; } + // temp, for kotlin_library + public long getDeviceControllerPtr() { + return deviceControllerPtr; + } + /** * Returns a new {@link ChipDeviceController} with the specified parameters. you must set a vendor * ID, ControllerParams.newBuilder().setControllerVendorId(0xFFF4).build() 0xFFF4 is a test vendor diff --git a/src/controller/java/src/chip/devicecontroller/InvokeCallbackJni.java b/src/controller/java/src/chip/devicecontroller/InvokeCallbackJni.java index 926aa0088c21bb..ceb35eccefd9b0 100644 --- a/src/controller/java/src/chip/devicecontroller/InvokeCallbackJni.java +++ b/src/controller/java/src/chip/devicecontroller/InvokeCallbackJni.java @@ -17,6 +17,8 @@ */ package chip.devicecontroller; +import chip.devicecontroller.model.InvokeElement; + /** JNI wrapper callback class for {@link InvokeCallback}. */ public final class InvokeCallbackJni { private final InvokeCallback wrappedInvokeCallback; @@ -24,17 +26,36 @@ public final class InvokeCallbackJni { public InvokeCallbackJni(InvokeCallback wrappedInvokeCallback) { this.wrappedInvokeCallback = wrappedInvokeCallback; - this.callbackHandle = newCallback(wrappedInvokeCallback); + this.callbackHandle = newCallback(); } long getCallbackHandle() { return callbackHandle; } - private native long newCallback(InvokeCallback wrappedCallback); + private native long newCallback(); private native void deleteCallback(long callbackHandle); + private void onError(Exception e) { + wrappedInvokeCallback.onError(e); + } + + private void onResponse( + int endpointId, + long clusterId, + long commandId, + byte[] tlv, + String jsonString, + long successCode) { + wrappedInvokeCallback.onResponse( + InvokeElement.newInstance(endpointId, clusterId, commandId, tlv, jsonString), successCode); + } + + private void onDone() { + wrappedInvokeCallback.onDone(); + } + // TODO(#8578): Replace finalizer with PhantomReference. @SuppressWarnings("deprecation") protected void finalize() throws Throwable { diff --git a/src/controller/java/src/chip/devicecontroller/ReportCallbackJni.java b/src/controller/java/src/chip/devicecontroller/ReportCallbackJni.java index b5a002508d5add..4f2529fa8d58b0 100644 --- a/src/controller/java/src/chip/devicecontroller/ReportCallbackJni.java +++ b/src/controller/java/src/chip/devicecontroller/ReportCallbackJni.java @@ -17,6 +17,9 @@ */ package chip.devicecontroller; +import chip.devicecontroller.model.ChipAttributePath; +import chip.devicecontroller.model.ChipEventPath; +import chip.devicecontroller.model.NodeState; import javax.annotation.Nullable; /** JNI wrapper callback class for {@link ReportCallback}. */ @@ -25,6 +28,7 @@ public class ReportCallbackJni { @Nullable private ResubscriptionAttemptCallback wrappedResubscriptionAttemptCallback; private ReportCallback wrappedReportCallback; private long callbackHandle; + @Nullable private NodeState nodeState; public ReportCallbackJni( @Nullable SubscriptionEstablishedCallback subscriptionEstablishedCallback, @@ -34,7 +38,7 @@ public ReportCallbackJni( this.wrappedReportCallback = reportCallback; this.wrappedResubscriptionAttemptCallback = resubscriptionAttemptCallback; this.callbackHandle = - newCallback(subscriptionEstablishedCallback, reportCallback, resubscriptionAttemptCallback); + newCallback(subscriptionEstablishedCallback, resubscriptionAttemptCallback); } long getCallbackHandle() { @@ -43,11 +47,48 @@ long getCallbackHandle() { private native long newCallback( @Nullable SubscriptionEstablishedCallback subscriptionEstablishedCallback, - ReportCallback wrappedCallback, @Nullable ResubscriptionAttemptCallback resubscriptionAttemptCallback); private native void deleteCallback(long callbackHandle); + // Called from native code only, which ignores access modifiers. + private void onReportBegin() { + nodeState = new NodeState(); + } + + private void onReportEnd() { + if (nodeState != null) { + wrappedReportCallback.onReport(nodeState); + } + nodeState = null; + } + + private NodeState getNodeState() { + return nodeState; + } + + private void onError( + boolean isAttributePath, + int attributeEndpointId, + long attributeClusterId, + long attributeId, + boolean isEventPath, + int eventEndpointId, + long eventClusterId, + long eventId, + Exception e) { + wrappedReportCallback.onError( + isAttributePath + ? ChipAttributePath.newInstance(attributeEndpointId, attributeClusterId, attributeId) + : null, + isEventPath ? ChipEventPath.newInstance(eventEndpointId, eventClusterId, eventId) : null, + e); + } + + private void onDone() { + wrappedReportCallback.onDone(); + } + // TODO(#8578): Replace finalizer with PhantomReference. @SuppressWarnings("deprecation") protected void finalize() throws Throwable { diff --git a/src/controller/java/src/chip/devicecontroller/StatusException.java b/src/controller/java/src/chip/devicecontroller/StatusException.java new file mode 100644 index 00000000000000..6a97e5b0e19aeb --- /dev/null +++ b/src/controller/java/src/chip/devicecontroller/StatusException.java @@ -0,0 +1,34 @@ +/* + * 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. + * + */ +package chip.devicecontroller; + +import chip.devicecontroller.model.Status; + +/** Exception class holding error codes defined by Interaction Model */ +public class StatusException extends Exception { + private static final long serialVersionUID = 1L; + + public Status.Code code = Status.Code.Success; + + public StatusException() {} + + public StatusException(Status.Code code) { + super(String.format("CHIP IM status error: %s", code.name())); + this.code = code; + } +} diff --git a/src/controller/java/src/chip/devicecontroller/WriteAttributesCallback.java b/src/controller/java/src/chip/devicecontroller/WriteAttributesCallback.java index 4e469ab0e58245..477f133c81a9c4 100644 --- a/src/controller/java/src/chip/devicecontroller/WriteAttributesCallback.java +++ b/src/controller/java/src/chip/devicecontroller/WriteAttributesCallback.java @@ -18,6 +18,7 @@ package chip.devicecontroller; import chip.devicecontroller.model.ChipAttributePath; +import chip.devicecontroller.model.Status; import javax.annotation.Nullable; /** An interface for receiving write response. */ @@ -40,8 +41,9 @@ public interface WriteAttributesCallback { * path. * * @param attributePath The attribute path field in write response. + * @param status The status field in write response. */ - void onResponse(ChipAttributePath attributePath); + void onResponse(ChipAttributePath attributePath, Status status); default void onDone() {} } diff --git a/src/controller/java/src/chip/devicecontroller/WriteAttributesCallbackJni.java b/src/controller/java/src/chip/devicecontroller/WriteAttributesCallbackJni.java index 38f98c3201103a..7b95b30759222f 100644 --- a/src/controller/java/src/chip/devicecontroller/WriteAttributesCallbackJni.java +++ b/src/controller/java/src/chip/devicecontroller/WriteAttributesCallbackJni.java @@ -17,6 +17,10 @@ */ package chip.devicecontroller; +import chip.devicecontroller.model.ChipAttributePath; +import chip.devicecontroller.model.Status; +import javax.annotation.Nullable; + /** JNI wrapper callback class for {@link WriteAttributesCallback}. */ public final class WriteAttributesCallbackJni { private final WriteAttributesCallback wrappedWriteAttributesCallback; @@ -24,17 +28,40 @@ public final class WriteAttributesCallbackJni { public WriteAttributesCallbackJni(WriteAttributesCallback wrappedWriteAttributesCallback) { this.wrappedWriteAttributesCallback = wrappedWriteAttributesCallback; - this.callbackHandle = newCallback(wrappedWriteAttributesCallback); + this.callbackHandle = newCallback(); } long getCallbackHandle() { return callbackHandle; } - private native long newCallback(WriteAttributesCallback wrappedCallback); + private native long newCallback(); private native void deleteCallback(long callbackHandle); + // Called from native code only, which ignores access modifiers. + private void onError( + boolean isAttributePath, int endpointId, long clusterId, long attributeId, Exception e) { + wrappedWriteAttributesCallback.onError( + isAttributePath ? ChipAttributePath.newInstance(endpointId, clusterId, attributeId) : null, + e); + } + + private void onResponse( + int endpointId, + long clusterId, + long attributeId, + int status, + @Nullable Integer clusterStatus) { + wrappedWriteAttributesCallback.onResponse( + ChipAttributePath.newInstance(endpointId, clusterId, attributeId), + Status.newInstance(status, clusterStatus)); + } + + private void onDone() { + wrappedWriteAttributesCallback.onDone(); + } + // TODO(#8578): Replace finalizer with PhantomReference. @SuppressWarnings("deprecation") protected void finalize() throws Throwable { diff --git a/src/controller/java/src/chip/devicecontroller/model/AttributeWriteRequest.java b/src/controller/java/src/chip/devicecontroller/model/AttributeWriteRequest.java index d19ad407b1f4db..2a3310890a9015 100644 --- a/src/controller/java/src/chip/devicecontroller/model/AttributeWriteRequest.java +++ b/src/controller/java/src/chip/devicecontroller/model/AttributeWriteRequest.java @@ -77,6 +77,19 @@ public ChipPathId getAttributeId() { return attributeId; } + // For use in JNI. + long getEndpointId(long wildcardValue) { + return endpointId.getId(wildcardValue); + } + + long getClusterId(long wildcardValue) { + return clusterId.getId(wildcardValue); + } + + long getAttributeId(long wildcardValue) { + return attributeId.getId(wildcardValue); + } + public int getDataVersion() { return dataVersion.orElse(0); } diff --git a/src/controller/java/src/chip/devicecontroller/model/ChipAttributePath.java b/src/controller/java/src/chip/devicecontroller/model/ChipAttributePath.java index f4b085f0350de4..0af1a87de5a523 100644 --- a/src/controller/java/src/chip/devicecontroller/model/ChipAttributePath.java +++ b/src/controller/java/src/chip/devicecontroller/model/ChipAttributePath.java @@ -30,6 +30,12 @@ private ChipAttributePath(ChipPathId endpointId, ChipPathId clusterId, ChipPathI this.attributeId = attributeId; } + ChipAttributePath(int endpointId, long clusterId, long attributeId) { + this.endpointId = ChipPathId.forId(endpointId); + this.clusterId = ChipPathId.forId(clusterId); + this.attributeId = ChipPathId.forId(attributeId); + } + public ChipPathId getEndpointId() { return endpointId; } @@ -42,6 +48,19 @@ public ChipPathId getAttributeId() { return attributeId; } + // For use in JNI. + private long getEndpointId(long wildcardValue) { + return endpointId.getId(wildcardValue); + } + + private long getClusterId(long wildcardValue) { + return clusterId.getId(wildcardValue); + } + + private long getAttributeId(long wildcardValue) { + return attributeId.getId(wildcardValue); + } + @Override public boolean equals(Object object) { if (object instanceof ChipAttributePath) { diff --git a/src/controller/java/src/chip/devicecontroller/model/ChipEventPath.java b/src/controller/java/src/chip/devicecontroller/model/ChipEventPath.java index 2f70a97f81d614..54ae737ca4d1a0 100644 --- a/src/controller/java/src/chip/devicecontroller/model/ChipEventPath.java +++ b/src/controller/java/src/chip/devicecontroller/model/ChipEventPath.java @@ -33,6 +33,13 @@ private ChipEventPath( this.isUrgent = isUrgent; } + ChipEventPath(int endpointId, long clusterId, long eventId, boolean isUrgent) { + this.endpointId = ChipPathId.forId(endpointId); + this.clusterId = ChipPathId.forId(clusterId); + this.eventId = ChipPathId.forId(eventId); + this.isUrgent = isUrgent; + } + public ChipPathId getEndpointId() { return endpointId; } @@ -45,6 +52,19 @@ public ChipPathId getEventId() { return eventId; } + // For use in JNI. + private long getEndpointId(long wildcardValue) { + return endpointId.getId(wildcardValue); + } + + private long getClusterId(long wildcardValue) { + return clusterId.getId(wildcardValue); + } + + private long getEventId(long wildcardValue) { + return eventId.getId(wildcardValue); + } + public boolean isUrgent() { return isUrgent; } diff --git a/src/controller/java/src/chip/devicecontroller/model/ChipPathId.java b/src/controller/java/src/chip/devicecontroller/model/ChipPathId.java index 31511d7eda462b..d7b44994553d47 100644 --- a/src/controller/java/src/chip/devicecontroller/model/ChipPathId.java +++ b/src/controller/java/src/chip/devicecontroller/model/ChipPathId.java @@ -43,6 +43,11 @@ public IdType getType() { return type; } + // For use in JNI. + long getId(long wildCardValue) { + return type == IdType.WILDCARD ? wildCardValue : id; + } + @Override public boolean equals(Object object) { if (object instanceof ChipPathId) { diff --git a/src/controller/java/src/chip/devicecontroller/model/DataVersionFilter.java b/src/controller/java/src/chip/devicecontroller/model/DataVersionFilter.java index 9eb9aa7b8e407a..e4e0d904873ec5 100644 --- a/src/controller/java/src/chip/devicecontroller/model/DataVersionFilter.java +++ b/src/controller/java/src/chip/devicecontroller/model/DataVersionFilter.java @@ -46,6 +46,15 @@ public long getDataVersion() { return dataVersion; } + // For use in JNI. + private long getEndpointId(long wildcardValue) { + return endpointId.getId(wildcardValue); + } + + private long getClusterId(long wildcardValue) { + return clusterId.getId(wildcardValue); + } + // check whether the current DataVersionFilter has same path as others. @Override public boolean equals(Object object) { diff --git a/src/controller/java/src/chip/devicecontroller/model/InvokeElement.java b/src/controller/java/src/chip/devicecontroller/model/InvokeElement.java index b56aae75c2c22f..71c68cb4d203f5 100644 --- a/src/controller/java/src/chip/devicecontroller/model/InvokeElement.java +++ b/src/controller/java/src/chip/devicecontroller/model/InvokeElement.java @@ -77,6 +77,19 @@ public ChipPathId getCommandId() { return commandId; } + // For use in JNI. + private long getEndpointId(long wildcardValue) { + return endpointId.getId(wildcardValue); + } + + private long getClusterId(long wildcardValue) { + return clusterId.getId(wildcardValue); + } + + private long getCommandId(long wildcardValue) { + return commandId.getId(wildcardValue); + } + public Optional getGroupId() { return groupId; } diff --git a/src/controller/java/src/chip/devicecontroller/model/NodeState.java b/src/controller/java/src/chip/devicecontroller/model/NodeState.java index f77097b5452f62..aaa90c3f1a1d93 100644 --- a/src/controller/java/src/chip/devicecontroller/model/NodeState.java +++ b/src/controller/java/src/chip/devicecontroller/model/NodeState.java @@ -35,6 +35,57 @@ public Map getEndpointStates() { } // Called from native code only, which ignores access modifiers. + private void addAttribute( + int endpointId, + long clusterId, + long attributeId, + Object valueObject, + byte[] tlv, + String jsonString) { + addAttribute( + endpointId, clusterId, attributeId, new AttributeState(valueObject, tlv, jsonString)); + } + + private void addEvent( + int endpointId, + long clusterId, + long eventId, + long eventNumber, + int priorityLevel, + int timestampType, + long timestampValue, + Object valueObject, + byte[] tlv, + String jsonString) { + addEvent( + endpointId, + clusterId, + eventId, + new EventState( + eventNumber, + priorityLevel, + timestampType, + timestampValue, + valueObject, + tlv, + jsonString)); + } + + private void addAttributeStatus( + int endpointId, + long clusterId, + long attributeId, + int status, + @Nullable Integer clusterStatus) { + addAttributeStatus( + endpointId, clusterId, attributeId, Status.newInstance(status, clusterStatus)); + } + + private void addEventStatus( + int endpointId, long clusterId, long eventId, int status, @Nullable Integer clusterStatus) { + addEventStatus(endpointId, clusterId, eventId, Status.newInstance(status, clusterStatus)); + } + private void setDataVersion(int endpointId, long clusterId, long dataVersion) { EndpointState endpointState = getEndpointState(endpointId); ClusterState clusterState = endpointState.getClusterState(clusterId); @@ -44,7 +95,6 @@ private void setDataVersion(int endpointId, long clusterId, long dataVersion) { } } - // Called from native code only, which ignores access modifiers. private void addAttribute( int endpointId, long clusterId, long attributeId, AttributeState attributeStateToAdd) { EndpointState endpointState = getEndpointState(endpointId); @@ -93,7 +143,6 @@ private void addEvent(int endpointId, long clusterId, long eventId, EventState e clusterState.getEventStates().get(eventId).add(eventStateToAdd); } - // Called from native code only, which ignores access modifiers. private void addAttributeStatus( int endpointId, long clusterId, long attributeId, Status statusToAdd) { EndpointState endpointState = getEndpointState(endpointId); @@ -112,7 +161,7 @@ private void addAttributeStatus( if (clusterState.getAttributeStates().containsKey(attributeId)) { clusterState.getAttributeStates().remove(attributeId); } - + System.out.println("put : " + attributeId + ", " + statusToAdd); clusterState.getAttributeStatuses().put(attributeId, statusToAdd); } diff --git a/src/controller/java/src/chip/devicecontroller/model/Status.java b/src/controller/java/src/chip/devicecontroller/model/Status.java index 7391f9a312f3f7..d859fae9f189e0 100644 --- a/src/controller/java/src/chip/devicecontroller/model/Status.java +++ b/src/controller/java/src/chip/devicecontroller/model/Status.java @@ -21,17 +21,87 @@ import java.util.Locale; import java.util.Optional; +/** Class for Interaction Model Status * */ public final class Status { - private Integer status; + public enum Code { + Success(0x0), + Failure(0x01), + InvalidSusbscription(0x7d), + UnsupportedAccess(0x7e), + UnsupportedEndPoint(0x7f), + InvalidAction(0x80), + UnsupportedCommand(0x81), + Deprecated82(0x82), + Deprecated83(0x83), + Deprecated84(0x84), + InvalidCommand(0x85), + UnsupportedAttribute(0x86), + ConstraintError(0x87), + UnsupportedWrite(0x88), + ResourceExhausted(0x89), + Deprecated8a(0x8a), + NotFound(0x8b), + UnreportableAttribute(0x8c), + InvalidDataType(0x8d), + Deprecated8e(0x8e), + UnsupportedRead(0x8f), + Deprecated90(0x90), + Deprecated91(0x91), + DataVersionMismatch(0x92), + Deprecated93(0x93), + Timeout(0x94), + Reserved95(0x95), + Reserved96(0x96), + Reserved97(0x97), + Reserved98(0x98), + Reserved99(0x99), + Reserved9a(0x9a), + Busy(0x9c), + Deprecatedc0(0xc0), + Deprecatedc1(0xc1), + Deprecatedc2(0xc2), + UnsupportedCluster(0xc3), + Deprecatedc4(0xc4), + NoUpstreamSubsricption(0xc5), + NeedTimedInteraction(0xc6), + UnsupportedEvent(0xc7), + PathExhausted(0xc8), + TimedRequestMismatch(0xc9), + FailsafeRequired(0xca), + InvalidInState(0xcb), + NoCommandResponse(0xcc), + WriteIgnored(0xf0); + + private int id = 0; + + Code(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public static Code fromId(int id) { + for (Code type : values()) { + if (type.getId() == id) { + return type; + } + } + return null; + } + } + + private Code status = Code.Success; private Optional clusterStatus; private Status(int status, Optional clusterStatus) { - this.status = status; + this.status = Code.fromId(status); this.clusterStatus = clusterStatus; } // Getters - public Integer getStatus() { + public Code getStatus() { return status; } @@ -43,15 +113,15 @@ public String toString() { return String.format( Locale.ENGLISH, "status %s, clusterStatus %s", - String.valueOf(status), + status.name(), clusterStatus.isPresent() ? String.valueOf(clusterStatus.get()) : "None"); } - public static Status newInstance(int status, int clusterStatus) { - return new Status(status, Optional.of(clusterStatus)); - } - public static Status newInstance(int status) { return new Status(status, Optional.empty()); } + + public static Status newInstance(int status, Integer clusterStatus) { + return new Status(status, Optional.ofNullable(clusterStatus)); + } } diff --git a/src/controller/java/src/matter/controller/InvokeCallback.kt b/src/controller/java/src/matter/controller/InvokeCallback.kt new file mode 100644 index 00000000000000..059a282dd654a6 --- /dev/null +++ b/src/controller/java/src/matter/controller/InvokeCallback.kt @@ -0,0 +1,48 @@ +/* + * 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. + * + */ +package matter.controller + +import java.lang.Exception + +/** An interface for receiving invoke response. */ +interface InvokeCallback { + /** + * OnError will be called when an error occurs after failing to call + * + * @param Exception The IllegalStateException which encapsulated the error message, the possible + * chip error could be - CHIP_ERROR_TIMEOUT: A response was not received within the expected + * response timeout. - CHIP_ERROR_*TLV*: A malformed, non-compliant response was received from + * the server. - CHIP_ERROR encapsulating the converted error from the StatusIB: If we got a + * non-path-specific status response from the server. - CHIP_ERROR*: All other cases. + */ + fun onError(ex: Exception) + + /** + * OnResponse will be called when a invoke response has been received and processed for the given + * path. + * + * @param invokeElement The invoke element in invoke response that could have null or nonNull tlv + * data + * @param successCode If data in InvokeElment is null, successCode can be any success status, + * including possibly a cluster-specific one. If data in InvokeElement is not null, successCode + * will always be a generic SUCCESS(0) with no-cluster specific information + */ + fun onResponse(invokeResponse: InvokeResponse?, successCode: Long) + + fun onDone() {} +} diff --git a/src/controller/java/src/matter/controller/InvokeCallbackJni.kt b/src/controller/java/src/matter/controller/InvokeCallbackJni.kt new file mode 100644 index 00000000000000..ac0e5e3ecd4209 --- /dev/null +++ b/src/controller/java/src/matter/controller/InvokeCallbackJni.kt @@ -0,0 +1,73 @@ +/* + * 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. + * + */ +package matter.controller + +import matter.controller.model.CommandPath + +/** JNI wrapper callback class for [InvokeCallback]. */ +class InvokeCallbackJni(val wrappedInvokeCallback: InvokeCallback) { + private var callbackHandle: Long + + init { + this.callbackHandle = newCallback() + } + + private external fun newCallback(): Long + + private external fun deleteCallback(callbackHandle: Long) + + fun getJniHandle(): Long { + return callbackHandle + } + + private fun onError(e: Exception) { + wrappedInvokeCallback.onError(e) + } + + private fun onResponse( + endpointId: Int, + clusterId: Long, + commandId: Long, + tlv: ByteArray, + jsonString: String, + successCode: Long + ) { + wrappedInvokeCallback.onResponse( + InvokeResponse( + tlv, + CommandPath(endpointId.toUShort(), clusterId.toUInt(), commandId.toUInt()), + jsonString + ), + successCode + ) + } + + private fun onDone() { + wrappedInvokeCallback.onDone() + } + + // TODO(#8578): Replace finalizer with PhantomReference. + @Suppress("deprecation") + @Throws(Throwable::class) + protected fun finalize() { + if (callbackHandle != 0L) { + deleteCallback(callbackHandle) + callbackHandle = 0 + } + } +} diff --git a/src/controller/java/src/matter/controller/MatterControllerImpl.kt b/src/controller/java/src/matter/controller/MatterControllerImpl.kt index fdc1a4c769deeb..6ae71f33a0faac 100644 --- a/src/controller/java/src/matter/controller/MatterControllerImpl.kt +++ b/src/controller/java/src/matter/controller/MatterControllerImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,16 +20,6 @@ package matter.controller import chip.devicecontroller.ChipDeviceController import chip.devicecontroller.ChipDeviceControllerException import chip.devicecontroller.GetConnectedDeviceCallbackJni.GetConnectedDeviceCallback -import chip.devicecontroller.InvokeCallback -import chip.devicecontroller.ReportCallback -import chip.devicecontroller.ResubscriptionAttemptCallback -import chip.devicecontroller.SubscriptionEstablishedCallback -import chip.devicecontroller.WriteAttributesCallback -import chip.devicecontroller.model.AttributeWriteRequest -import chip.devicecontroller.model.ChipAttributePath -import chip.devicecontroller.model.ChipEventPath -import chip.devicecontroller.model.ChipPathId -import chip.devicecontroller.model.InvokeElement import java.util.logging.Level import java.util.logging.Logger import kotlin.coroutines.resume @@ -43,17 +33,16 @@ import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.suspendCancellableCoroutine import matter.controller.model.AttributePath -import matter.controller.model.AttributeState -import matter.controller.model.ClusterState -import matter.controller.model.EndpointState import matter.controller.model.EventPath import matter.controller.model.EventState import matter.controller.model.NodeState +import matter.controller.model.Status /** Controller to interact with the CHIP device. */ class MatterControllerImpl(params: ControllerParams) : MatterController { private val deviceController: ChipDeviceController private var nodeId: Long? = null + private val deviceControllerPtr: Long override fun setCompletionListener(listener: MatterController.CompletionListener?) = deviceController.setCompletionListener(CompletionListenerAdapter.from(listener)) @@ -89,8 +78,8 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { val nodeId = this.nodeId check(nodeId != null) { "nodeId has not been initialized yet" } - val attributePaths = generateAttributePaths(request) - val eventPaths = generateEventPaths(request) + val attributePaths = request.attributePaths + val eventPaths = request.eventPaths val successes = mutableListOf() val failures = mutableListOf() @@ -130,31 +119,23 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { val reportHandler = object : ReportCallback { - override fun onReport(nodeState: chip.devicecontroller.model.NodeState) { - logger.log(Level.INFO, "Received subscribe update report") - - val tmpNodeState: NodeState = nodeState.wrap() - - for (endpoint in tmpNodeState.endpoints) { + override fun onReport(nodeState: NodeState) { + logger.log(Level.FINE, "Received subscribe report") + for (endpoint in nodeState.endpoints) { for (cluster in endpoint.value.clusters) { for (attribute in cluster.value.attributes) { - val attributePath = - AttributePath( - endpointId = endpoint.key.toUShort(), - clusterId = cluster.key.toUInt(), - attributeId = attribute.key.toUInt() - ) - val readData = ReadData.Attribute(attributePath, attribute.value.tlvValue) + val readData = + ReadData.Attribute(attribute.value.path, attribute.value.tlvValue) successes.add(readData) } for (eventList in cluster.value.events) { for (event in eventList.value) { val timestamp: Timestamp = - when (event.timestampType) { - chip.devicecontroller.model.EventState.MILLIS_SINCE_BOOT -> + when (event.getTimestampType()) { + EventState.TypeStampTypeEnum.MILLIS_SINCE_BOOT -> Timestamp.MillisSinceBoot(event.timestampValue) - chip.devicecontroller.model.EventState.MILLIS_SINCE_EPOCH -> + EventState.TypeStampTypeEnum.MILLIS_SINCE_EPOCH -> Timestamp.MillisSinceEpoch(event.timestampValue) else -> { logger.log(Level.SEVERE, "Unsupported event timestamp type - ignoring") @@ -162,16 +143,9 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { } } - val eventPath = - EventPath( - endpointId = endpoint.key.toUShort(), - clusterId = cluster.key.toUInt(), - eventId = eventList.key.toUInt() - ) - val readData = ReadData.Event( - path = eventPath, + path = event.path, eventNumber = event.eventNumber.toULong(), priorityLevel = event.priorityLevel.toUByte(), timeStamp = timestamp, @@ -182,7 +156,6 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { } } } - trySendBlocking(SubscriptionState.NodeStateUpdate(ReadResponse(successes, failures))) .onFailure { ex -> logger.log(Level.SEVERE, "Error sending NodeStateUpdate to subscriber: %s", ex) @@ -190,25 +163,20 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { } override fun onError( - attributePath: ChipAttributePath?, - eventPath: ChipEventPath?, - ex: Exception + attributePath: AttributePath?, + eventPath: EventPath?, + e: Exception ) { attributePath?.let { logger.log(Level.INFO, "Report error for attributePath:%s", it.toString()) - val tmpAttributePath: AttributePath = attributePath.wrap() - val attributeFailure = ReadFailure.Attribute(path = tmpAttributePath, error = ex) + val attributeFailure = ReadFailure.Attribute(path = it, error = e) failures.add(attributeFailure) } eventPath?.let { logger.log(Level.INFO, "Report error for eventPath:%s", it.toString()) - val tmpEventPath: EventPath = eventPath.wrap() - val eventFailure = ReadFailure.Event(path = tmpEventPath, error = ex) + val eventFailure = ReadFailure.Event(path = it, error = e) failures.add(eventFailure) } - - // The underlying subscription is terminated if both attributePath & eventPath are - // null if (attributePath == null && eventPath == null) { logger.log(Level.SEVERE, "The underlying subscription is terminated") @@ -226,14 +194,19 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { } override fun onDone() { - logger.log(Level.INFO, "Subscription update completed") + logger.log(Level.FINE, "subscribe command completed") } } - deviceController.subscribeToPath( - subscriptionEstablishedHandler, - resubscriptionAttemptHandler, - reportHandler, + val reportCallbackJni = + ReportCallbackJni( + subscriptionEstablishedHandler, + reportHandler, + resubscriptionAttemptHandler + ) + subscribe( + deviceControllerPtr, + reportCallbackJni.getJniHandle(), devicePtr, attributePaths, eventPaths, @@ -249,6 +222,19 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { .buffer(capacity = UNLIMITED) } + private external fun subscribe( + handle: Long, + callbackHandle: Long, + devicePtr: Long, + attributePathList: List, + eventPathList: List, + minInterval: Int, + maxInterval: Int, + keepSubscriptions: Boolean, + isFabricFiltered: Boolean, + imTimeoutMs: Int + ) + override suspend fun read(request: ReadRequest): ReadResponse { // To prevent potential issues related to concurrent modification, assign // the value of the mutable property 'nodeId' to a temporary variable. @@ -257,69 +243,38 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { val devicePtr: Long = getConnectedDevicePointer(nodeId) - val chipAttributePaths = - request.attributePaths.map { attributePath -> - val endpointId = attributePath.endpointId.toInt() - val clusterId = attributePath.clusterId.toLong() - val attributeId = attributePath.attributeId.toLong() - ChipAttributePath.newInstance(endpointId, clusterId, attributeId) - } - - val chipEventPaths = - request.eventPaths.map { eventPath -> - val endpointId = eventPath.endpointId.toInt() - val clusterId = eventPath.clusterId.toLong() - val eventId = eventPath.eventId.toLong() - ChipEventPath.newInstance(endpointId, clusterId, eventId) - } - val successes = mutableListOf() val failures = mutableListOf() return suspendCancellableCoroutine { continuation -> val reportCallback = object : ReportCallback { - override fun onReport(nodeState: chip.devicecontroller.model.NodeState) { + override fun onReport(nodeState: NodeState) { logger.log(Level.FINE, "Received read report") - - val tmpNodeState: NodeState = nodeState.wrap() - - for (endpoint in tmpNodeState.endpoints) { + for (endpoint in nodeState.endpoints) { for (cluster in endpoint.value.clusters) { for (attribute in cluster.value.attributes) { - val attributePath = - AttributePath( - endpointId = endpoint.key.toUShort(), - clusterId = cluster.key.toUInt(), - attributeId = attribute.key.toUInt() - ) - val readData = ReadData.Attribute(attributePath, attribute.value.tlvValue) + val readData = ReadData.Attribute(attribute.value.path, attribute.value.tlvValue) successes.add(readData) } for (eventList in cluster.value.events) { for (event in eventList.value) { val timestamp: Timestamp = - when (event.timestampType) { - chip.devicecontroller.model.EventState.MILLIS_SINCE_BOOT -> + when (event.getTimestampType()) { + EventState.TypeStampTypeEnum.MILLIS_SINCE_BOOT -> Timestamp.MillisSinceBoot(event.timestampValue) - chip.devicecontroller.model.EventState.MILLIS_SINCE_EPOCH -> + EventState.TypeStampTypeEnum.MILLIS_SINCE_EPOCH -> Timestamp.MillisSinceEpoch(event.timestampValue) else -> { logger.log(Level.SEVERE, "Unsupported event timestamp type - ignoring") break } } - val eventPath = - EventPath( - endpointId = endpoint.key.toUShort(), - clusterId = cluster.key.toUInt(), - eventId = eventList.key.toUInt() - ) val readData = ReadData.Event( - path = eventPath, + path = event.path, eventNumber = event.eventNumber.toULong(), priorityLevel = event.priorityLevel.toUByte(), timeStamp = timestamp, @@ -332,30 +287,17 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { } } - override fun onError( - attributePath: ChipAttributePath?, - eventPath: ChipEventPath?, - ex: Exception - ) { + override fun onError(attributePath: AttributePath?, eventPath: EventPath?, e: Exception) { attributePath?.let { logger.log(Level.INFO, "Report error for attributePath:%s", it.toString()) - val tmpAttributePath: AttributePath = attributePath.wrap() - val attributeFailure = ReadFailure.Attribute(path = tmpAttributePath, error = ex) + val attributeFailure = ReadFailure.Attribute(path = it, error = e) failures.add(attributeFailure) } eventPath?.let { logger.log(Level.INFO, "Report error for eventPath:%s", it.toString()) - val tmpEventPath: EventPath = eventPath.wrap() - val eventFailure = ReadFailure.Event(path = tmpEventPath, error = ex) + val eventFailure = ReadFailure.Event(path = it, error = e) failures.add(eventFailure) } - - // The underlying subscription is terminated if both attributePath & eventPath are null - if (attributePath == null && eventPath == null) { - continuation.resumeWithException( - Exception("Read command failed with error ${ex.message}") - ) - } } override fun onDone() { @@ -363,18 +305,29 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { continuation.resume(ReadResponse(successes, failures)) } } - - deviceController.readPath( - reportCallback, + val reportCallbackJni = ReportCallbackJni(null, reportCallback, null) + read( + deviceControllerPtr, + reportCallbackJni.getJniHandle(), devicePtr, - chipAttributePaths, - chipEventPaths, + request.attributePaths, + request.eventPaths, false, - CHIP_IM_TIMEOUT_MS, + CHIP_IM_TIMEOUT_MS ) } } + private external fun read( + handle: Long, + callbackHandle: Long, + devicePtr: Long, + attributePathList: List, + eventPathList: List, + isFabricFiltered: Boolean, + imTimeoutMs: Int + ) + override suspend fun write(writeRequests: WriteRequests): WriteResponse { // To prevent potential issues related to concurrent modification, assign // the value of the mutable property 'nodeId' to a temporary variable. @@ -383,26 +336,19 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { val devicePtr: Long = getConnectedDevicePointer(nodeId) - val attributeWriteRequests = - writeRequests.requests.map { request -> - AttributeWriteRequest.newInstance( - ChipPathId.forId(request.attributePath.endpointId.toLong()), - ChipPathId.forId(request.attributePath.clusterId.toLong()), - ChipPathId.forId(request.attributePath.attributeId.toLong()), - request.tlvPayload - ) - } - val failures = mutableListOf() return suspendCancellableCoroutine { continuation -> val writeCallback = object : WriteAttributesCallback { - override fun onResponse(attributePath: ChipAttributePath) { - logger.log(Level.INFO, "write success for attributePath:%s", attributePath.toString()) + override fun onResponse(attributePath: AttributePath, status: Status) { + logger.log( + Level.INFO, + "Receive write response for attributePath: ${attributePath} and status ${status}" + ) } - override fun onError(attributePath: ChipAttributePath?, ex: Exception) { + override fun onError(attributePath: AttributePath?, ex: Exception) { logger.log( Level.SEVERE, "Failed to write attribute at path: %s", @@ -418,7 +364,7 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { continuation.resumeWithException(ex) } } else { - failures.add(AttributeWriteError(attributePath.wrap(), ex)) + failures.add(AttributeWriteError(attributePath, ex)) } } @@ -432,17 +378,27 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { } } } - - deviceController.write( - writeCallback, + val writeAttributeCallbackJni = WriteAttributesCallbackJni(writeCallback) + write( + deviceControllerPtr, + writeAttributeCallbackJni.getCallbackHandle(), devicePtr, - attributeWriteRequests.toList(), + writeRequests.requests, writeRequests.timedRequest?.toMillis()?.toInt() ?: 0, CHIP_IM_TIMEOUT_MS, ) } } + private external fun write( + handle: Long, + callbackHandle: Long, + devicePtr: Long, + writeRequestList: List, + timedRequestTimeoutMs: Int, + imTimeoutMs: Int + ) + override suspend fun invoke(request: InvokeRequest): InvokeResponse { // To prevent potential issues related to concurrent modification, assign // the value of the mutable property 'nodeId' to a temporary variable. @@ -451,22 +407,18 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { val devicePtr: Long = getConnectedDevicePointer(nodeId) - val invokeRequest = - InvokeElement.newInstance( - ChipPathId.forId(request.commandPath.endpointId.toLong()), - ChipPathId.forId(request.commandPath.clusterId.toLong()), - ChipPathId.forId(request.commandPath.commandId.toLong()), - request.tlvPayload, - /* jsonString= */ null - ) - return suspendCancellableCoroutine { continuation -> var invokeCallback = object : InvokeCallback { - override fun onResponse(invokeElement: InvokeElement?, successCode: Long) { + override fun onResponse(invokeResponse: InvokeResponse?, successCode: Long) { logger.log(Level.FINE, "Invoke onResponse is received") - val tlvByteArray = invokeElement?.getTlvByteArray() ?: byteArrayOf() - continuation.resume(InvokeResponse(tlvByteArray)) + val ret = + if (invokeResponse == null) { + InvokeResponse(byteArrayOf(), request.commandPath, null) + } else { + invokeResponse + } + continuation.resume(ret) } override fun onError(ex: Exception) { @@ -477,17 +429,27 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { } } } - - deviceController.invoke( - invokeCallback, + val invokeCallbackJni = InvokeCallbackJni(invokeCallback) + invoke( + deviceControllerPtr, + invokeCallbackJni.getJniHandle(), devicePtr, - invokeRequest, + request, request.timedRequest?.toMillis()?.toInt() ?: 0, CHIP_IM_TIMEOUT_MS ) } } + private external fun invoke( + handle: Long, + callbackHandle: Long, + devicePtr: Long, + invokeRequest: InvokeRequest, + timedRequestTimeoutMs: Int, + imTimeoutMs: Int + ) + override fun close() { logger.log(Level.INFO, "MatterController is closed") deviceController.shutdownCommissioning() @@ -515,68 +477,64 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { } } - private fun generateAttributePaths(request: SubscribeRequest): List { - return request.attributePaths.map { attributePath -> - ChipAttributePath.newInstance( - attributePath.endpointId.toInt(), - attributePath.clusterId.toLong(), - attributePath.attributeId.toLong() - ) - } - } - - private fun generateEventPaths(request: SubscribeRequest): List { - return request.eventPaths.map { eventPath -> - ChipEventPath.newInstance( - eventPath.endpointId.toInt(), - eventPath.clusterId.toLong(), - eventPath.eventId.toLong(), - false - ) - } - } - - private fun ChipAttributePath.wrap(): AttributePath { - return AttributePath( - endpointId.getId().toUShort(), - clusterId.getId().toUInt(), - attributeId.getId().toUInt() - ) - } - - private fun ChipEventPath.wrap(): EventPath { - return EventPath( - endpointId.getId().toUShort(), - clusterId.getId().toUInt(), - eventId.getId().toUInt() - ) - } - - private fun chip.devicecontroller.model.NodeState.wrap(): NodeState { - return NodeState( - endpoints = endpointStates.mapValues { (id, value) -> value.wrap(id) }, - ) - } - - private fun chip.devicecontroller.model.EndpointState.wrap(id: Int): EndpointState { - return EndpointState(id, clusterStates.mapValues { (id, value) -> value.wrap(id) }) - } - - private fun chip.devicecontroller.model.ClusterState.wrap(id: Long): ClusterState { - return ClusterState( - id, - attributeStates.mapValues { (id, value) -> value.wrap(id) }, - eventStates.mapValues { (id, value) -> value.map { eventState -> eventState.wrap(id) } } - ) - } - - private fun chip.devicecontroller.model.AttributeState.wrap(id: Long): AttributeState { - return AttributeState(id, tlv, json.toString()) - } - - private fun chip.devicecontroller.model.EventState.wrap(id: Long): EventState { - return EventState(id, eventNumber, priorityLevel, timestampType, timestampValue, tlv) - } + // private fun ChipAttributePath.wrap(): AttributePath { + // return AttributePath( + // endpointId.getId().toUShort(), + // clusterId.getId().toUInt(), + // attributeId.getId().toUInt() + // ) + // } + + // private fun ChipEventPath.wrap(): EventPath { + // return EventPath( + // endpointId.getId().toUShort(), + // clusterId.getId().toUInt(), + // eventId.getId().toUInt() + // ) + // } + + // private fun chip.devicecontroller.model.NodeState.wrap(): NodeState { + // return NodeState( + // endpoints = endpointStates.mapValues { (id, value) -> value.wrap(id) }.toMutableMap(), + // ) + // } + + // private fun chip.devicecontroller.model.EndpointState.wrap(id: Int): EndpointState { + // return EndpointState( + // id, + // clusterStates.mapValues { (id, value) -> value.wrap(id) }.toMutableMap() + // ) + // } + + // private fun chip.devicecontroller.model.ClusterState.wrap(id: Long): ClusterState { + // return ClusterState( + // id, + // attributeStates.mapValues { (id, value) -> value.wrap(id) }.toMutableMap(), + // eventStates + // .mapValues { (id, value) -> + // value.map { eventState -> eventState.wrap(id) }.toMutableList() + // } + // .toMutableMap() + // ) + // } + + // private fun chip.devicecontroller.model.AttributeState.wrap(id: Long): AttributeState { + // return AttributeState(id, tlv, json.toString(), AttributePath(0U, 0U, id.toUInt()), value) + // } + + // private fun chip.devicecontroller.model.EventState.wrap(id: Long): EventState { + // return EventState( + // id, + // eventNumber, + // priorityLevel, + // timestampType, + // timestampValue, + // tlv, + // EventPath(0U, 0U, id.toUInt()), + // json.toString(), + // value + // ) + // } init { val config: OperationalKeyConfig? = params.operationalKeyConfig @@ -597,6 +555,7 @@ class MatterControllerImpl(params: ControllerParams) : MatterController { } deviceController = ChipDeviceController(paramsBuilder.build()) + deviceControllerPtr = deviceController.deviceControllerPtr } companion object { diff --git a/src/controller/java/src/matter/controller/Messages.kt b/src/controller/java/src/matter/controller/Messages.kt index 36f3fd6fc3ad2c..3d14ef09037342 100644 --- a/src/controller/java/src/matter/controller/Messages.kt +++ b/src/controller/java/src/matter/controller/Messages.kt @@ -18,6 +18,7 @@ package matter.controller import java.time.Duration +import java.util.Optional import matter.controller.model.AttributePath import matter.controller.model.CommandPath import matter.controller.model.EventPath @@ -150,11 +151,40 @@ sealed class SubscriptionState { * * @param attributePath The attribute path information in the write request. * @param tlvPayload The ByteArray representation of the TLV payload. + * @param dataVersion The data version in the write request. */ class WriteRequest( val attributePath: AttributePath, val tlvPayload: ByteArray, -) + val dataVersion: UInt? = null +) { + private fun getEndpointId(wildcardId: Long): Long { + return attributePath.endpointId?.toLong() ?: wildcardId + } + + private fun getClusterId(wildcardId: Long): Long { + return attributePath.clusterId?.toLong() ?: wildcardId + } + + private fun getAttributeId(wildcardId: Long): Long { + return attributePath.attributeId?.toLong() ?: wildcardId + } + + // For JNI interface + private fun getJsonString(): String? = null + + fun getTlvByteArray(): ByteArray { + return tlvPayload + } + + fun hasDataVersion(): Boolean { + return dataVersion != null + } + + fun getDataVersion(): Int { + return dataVersion?.toInt() ?: 0 + } +} /** * Information about a collection of write request elements. @@ -189,8 +219,39 @@ sealed interface WriteResponse { class InvokeRequest( val commandPath: CommandPath, val tlvPayload: ByteArray, - val timedRequest: Duration? -) + val timedRequest: Duration?, + val jsonString: String? = null +) { + private fun getEndpointId(wildcardId: Long): Long { + return commandPath.endpointId?.toLong() ?: wildcardId + } + + @Suppress("UNUSED_PARAMETER") + private fun getClusterId(wildcardId: Long): Long { + return commandPath.clusterId.toLong() + } + + @Suppress("UNUSED_PARAMETER") + private fun getCommandId(wildcardId: Long): Long { + return commandPath.commandId.toLong() + } + + fun getGroupId(): Optional { + return Optional.ofNullable(commandPath.groupId?.toInt()) + } + + fun isEndpointIdValid(): Boolean { + return commandPath.groupId == null + } + + fun isGroupIdValid(): Boolean { + return commandPath.groupId != null + } + + fun getTlvByteArray(): ByteArray { + return tlvPayload + } +} /** * InvokeResponse will be received when a invoke response has been successful received and @@ -198,4 +259,4 @@ class InvokeRequest( * * @param payload An invoke response that could contain tlv data or empty. */ -class InvokeResponse(val payload: ByteArray) +class InvokeResponse(val payload: ByteArray, val path: CommandPath, val jsonString: String? = null) diff --git a/src/controller/java/src/matter/controller/ReportCallback.kt b/src/controller/java/src/matter/controller/ReportCallback.kt new file mode 100644 index 00000000000000..3d05fce04dacf8 --- /dev/null +++ b/src/controller/java/src/matter/controller/ReportCallback.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 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. + * + */ +package matter.controller + +import matter.controller.model.AttributePath +import matter.controller.model.EventPath +import matter.controller.model.NodeState + +/** An interface for receiving read/subscribe CHIP reports. */ +interface ReportCallback { + fun onError(attributePath: AttributePath?, eventPath: EventPath?, e: Exception) + + fun onReport(nodeState: NodeState) + + fun onDone() {} +} diff --git a/src/controller/java/src/matter/controller/ReportCallbackJni.kt b/src/controller/java/src/matter/controller/ReportCallbackJni.kt new file mode 100644 index 00000000000000..ec32df596ae9ff --- /dev/null +++ b/src/controller/java/src/matter/controller/ReportCallbackJni.kt @@ -0,0 +1,111 @@ +/* + * 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. + * + */ +package matter.controller + +import matter.controller.model.AttributePath +import matter.controller.model.EventPath +import matter.controller.model.NodeState + +/** JNI wrapper callback class for [ReportCallback]. */ +class ReportCallbackJni( + subscriptionEstablishedCallback: SubscriptionEstablishedCallback?, + reportCallback: ReportCallback, + resubscriptionAttemptCallback: ResubscriptionAttemptCallback? +) { + private val wrappedSubscriptionEstablishedCallback: SubscriptionEstablishedCallback? = + subscriptionEstablishedCallback + private val wrappedResubscriptionAttemptCallback: ResubscriptionAttemptCallback? = + resubscriptionAttemptCallback + + private val wrappedReportCallback: ReportCallback = reportCallback + private var callbackHandle: Long + + private var nodeState: NodeState? = null + + init { + this.callbackHandle = + newCallback(subscriptionEstablishedCallback, resubscriptionAttemptCallback) + } + + private external fun newCallback( + subscriptionEstablishedCallback: SubscriptionEstablishedCallback?, + resubscriptionAttemptCallback: ResubscriptionAttemptCallback? + ): Long + + private external fun deleteCallback(callbackHandle: Long) + + fun getJniHandle(): Long { + return callbackHandle + } + + // Called from native code only, which ignores access modifiers. + private fun onReportBegin() { + nodeState = NodeState() + } + + private fun onReportEnd() { + if (nodeState != null) { + wrappedReportCallback.onReport(nodeState!!) + } + nodeState = null + } + + private fun getNodeState(): NodeState? { + return nodeState + } + + private fun onError( + isAttributePath: Boolean, + attributeEndpointId: Int, + attributeClusterId: Long, + attributeId: Long, + isEventPath: Boolean, + eventEndpointId: Int, + eventClusterId: Long, + eventId: Long, + e: Exception + ) { + wrappedReportCallback.onError( + if (isAttributePath) + AttributePath( + attributeEndpointId.toUShort(), + attributeClusterId.toUInt(), + attributeId.toUInt() + ) + else null, + if (isEventPath) + EventPath(eventEndpointId.toUShort(), eventClusterId.toUInt(), eventId.toUInt()) + else null, + e + ) + } + + private fun onDone() { + wrappedReportCallback.onDone() + } + + // TODO(#8578): Replace finalizer with PhantomReference. + @Suppress("deprecation") + @Throws(Throwable::class) + protected fun finalize() { + if (callbackHandle != 0L) { + deleteCallback(callbackHandle) + callbackHandle = 0 + } + } +} diff --git a/src/controller/java/src/matter/controller/ResubscriptionAttemptCallback.kt b/src/controller/java/src/matter/controller/ResubscriptionAttemptCallback.kt new file mode 100644 index 00000000000000..3d130d395445cc --- /dev/null +++ b/src/controller/java/src/matter/controller/ResubscriptionAttemptCallback.kt @@ -0,0 +1,22 @@ +/* + * 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. + * + */ +package matter.controller + +fun interface ResubscriptionAttemptCallback { + fun onResubscriptionAttempt(terminationCause: Long, nextResubscribeIntervalMsec: Long) +} diff --git a/src/controller/java/src/matter/controller/SubscriptionEstablishedCallback.kt b/src/controller/java/src/matter/controller/SubscriptionEstablishedCallback.kt new file mode 100644 index 00000000000000..8cd5fdc2c07301 --- /dev/null +++ b/src/controller/java/src/matter/controller/SubscriptionEstablishedCallback.kt @@ -0,0 +1,22 @@ +/* + * 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. + * + */ +package matter.controller + +fun interface SubscriptionEstablishedCallback { + fun onSubscriptionEstablished(subscriptionId: Long) +} diff --git a/src/controller/java/src/matter/controller/WriteAttributesCallback.kt b/src/controller/java/src/matter/controller/WriteAttributesCallback.kt new file mode 100644 index 00000000000000..6b1b3f7056f71e --- /dev/null +++ b/src/controller/java/src/matter/controller/WriteAttributesCallback.kt @@ -0,0 +1,47 @@ +/* + * 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. + * + */ +package matter.controller + +import matter.controller.model.AttributePath +import matter.controller.model.Status + +/** An interface for receiving write response. */ +interface WriteAttributesCallback { + /** + * OnError will be called when an error occurs after failing to write + * + * @param attributePath The attribute path field + * @param Exception The IllegalStateException which encapsulated the error message, the possible + * chip error could be CHIP_ERROR_TIMEOUT: A response was not received within the expected + * response timeout. - CHIP_ERROR_*TLV*: A malformed, non-compliant response was received from + * the server. - CHIP_ERROR encapsulating the converted error from the StatusIB: If we got a + * non-path-specific status response from the server. CHIP_ERROR*: All other cases. + */ + fun onError(attributePath: AttributePath?, ex: Exception) + + /** + * OnResponse will be called when a write response has been received and processed for the given + * path. + * + * @param attributePath The attribute path field in write response. + * @param status The attribute status field in write response. + */ + fun onResponse(attributePath: AttributePath, status: Status) + + fun onDone() {} +} diff --git a/src/controller/java/src/matter/controller/WriteAttributesCallbackJni.kt b/src/controller/java/src/matter/controller/WriteAttributesCallbackJni.kt new file mode 100644 index 00000000000000..fe52a329ff3078 --- /dev/null +++ b/src/controller/java/src/matter/controller/WriteAttributesCallbackJni.kt @@ -0,0 +1,83 @@ +/* + * 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. + * + */ +package matter.controller + +import matter.controller.model.AttributePath +import matter.controller.model.Status + +/** JNI wrapper callback class for [WriteAttributesCallback]. */ +class WriteAttributesCallbackJni( + private val wrappedWriteAttributesCallback: WriteAttributesCallback +) { + private var callbackHandle: Long + + init { + this.callbackHandle = newCallback() + } + + private external fun newCallback(): Long + + private external fun deleteCallback(callbackHandle: Long) + + fun getCallbackHandle(): Long { + return callbackHandle + } + + // Called from native code only, which ignores access modifiers. + private fun onError( + isAttributePath: Boolean, + endpointId: Int, + clusterId: Long, + attributeId: Long, + e: Exception + ) { + wrappedWriteAttributesCallback.onError( + if (isAttributePath) + AttributePath(endpointId.toUShort(), clusterId.toUInt(), attributeId.toUInt()) + else null, + e + ) + } + + private fun onResponse( + endpointId: Int, + clusterId: Long, + attributeId: Long, + status: Int, + clusterStatus: Int? + ) { + wrappedWriteAttributesCallback.onResponse( + AttributePath(endpointId.toUShort(), clusterId.toUInt(), attributeId.toUInt()), + Status(status, clusterStatus) + ) + } + + private fun onDone() { + wrappedWriteAttributesCallback.onDone() + } + + // TODO(#8578): Replace finalizer with PhantomReference. + @Suppress("deprecation") + @Throws(Throwable::class) + protected fun finalize() { + if (callbackHandle != 0L) { + deleteCallback(callbackHandle) + callbackHandle = 0 + } + } +} diff --git a/src/controller/java/src/matter/controller/model/Paths.kt b/src/controller/java/src/matter/controller/model/Paths.kt index 76e26db62f0e1e..35fcd4e6bd411c 100644 --- a/src/controller/java/src/matter/controller/model/Paths.kt +++ b/src/controller/java/src/matter/controller/model/Paths.kt @@ -20,40 +20,74 @@ package matter.controller.model /** * Represents a full path for reading an attribute from a node. * - * @param endpointId The UShort representing the endpoint to read from. - * @param clusterId The UInt representing the cluster on the endpoint to read from. - * @param attributeId The UInt representing the attribute(s) on the cluster to read. + * @param endpointId The UShort representing the endpoint to read from. null is used to represent + * wildcards. + * @param clusterId The UInt representing the cluster on the endpoint to read from. null is used to + * represent wildcards. + * @param attributeId The UInt representing the attribute(s) on the cluster to read. null is used to + * represent wildcards. */ -data class AttributePath(val endpointId: UShort, val clusterId: UInt, val attributeId: UInt) { +data class AttributePath(val endpointId: UShort?, val clusterId: UInt?, val attributeId: UInt?) { override fun toString(): String = "$endpointId/$clusterId/$attributeId" + + private fun getEndpointId(wildcardId: Long): Long { + return endpointId?.toLong() ?: wildcardId + } + + private fun getClusterId(wildcardId: Long): Long { + return clusterId?.toLong() ?: wildcardId + } + + private fun getAttributeId(wildcardId: Long): Long { + return attributeId?.toLong() ?: wildcardId + } } /** * Represents a full path to an event emitted from a node. * - * @param endpointId The UShort representing the endpoint to read from. - * @param clusterId The UInt representing the cluster on the endpoint to read from. - * @param eventId The UInt representing the event(s) from the cluster. + * @param endpointId The UShort representing the endpoint to read from. null is used to represent + * wildcards. + * @param clusterId The UInt representing the cluster on the endpoint to read from. null is used to + * represent wildcards. + * @param eventId The UInt representing the event(s) from the cluster. null is used to represent + * wildcards. */ data class EventPath( - val endpointId: UShort, - val clusterId: UInt, - val eventId: UInt, + val endpointId: UShort?, + val clusterId: UInt?, + val eventId: UInt?, + val isUrgent: Boolean = false ) { override fun toString(): String = "$endpointId/$clusterId/$eventId" + + private fun getEndpointId(wildcardId: Long): Long { + return endpointId?.toLong() ?: wildcardId + } + + private fun getClusterId(wildcardId: Long): Long { + return clusterId?.toLong() ?: wildcardId + } + + private fun getEventId(wildcardId: Long): Long { + return eventId?.toLong() ?: wildcardId + } } /** * Represents a full path to a command sent to a node. * - * @param endpointId The UShort representing the endpoint to read from. + * @param endpointId The UShort representing the endpoint to read from. null is used to represent + * wildcards. * @param clusterId The UInt representing the cluster on the endpoint to read from. * @param commandId The UInt representing the command(s) from the cluster. + * @param groupId This UInt representing the group to read from. Used only in group path. */ data class CommandPath( - val endpointId: UShort, + val endpointId: UShort?, val clusterId: UInt, val commandId: UInt, + val groupId: UInt? = null ) { override fun toString(): String = "$endpointId/$clusterId/$commandId" } diff --git a/src/controller/java/src/matter/controller/model/States.kt b/src/controller/java/src/matter/controller/model/States.kt index 39899e7ce735f8..e7799f1f5a64e1 100644 --- a/src/controller/java/src/matter/controller/model/States.kt +++ b/src/controller/java/src/matter/controller/model/States.kt @@ -22,7 +22,150 @@ package matter.controller.model * * @param endpoints A mapping of endpoint IDs with the associated cluster data. */ -data class NodeState(val endpoints: Map) +class NodeState(val endpoints: MutableMap = mutableMapOf()) { + private fun addAttribute( + endpointId: UShort, + clusterId: UInt, + attributeId: UInt, + attributeState: AttributeState + ) { + getEndpointState(endpointId).addAttribute(clusterId, attributeId, attributeState) + } + + private fun addEvent(endpointId: UShort, clusterId: UInt, eventId: UInt, eventState: EventState) { + getEndpointState(endpointId).addEvent(clusterId, eventId, eventState) + } + + private fun setDataVersion(endpointId: UShort, clusterId: UInt, dataVersion: UInt) { + getEndpointState(endpointId).clusters[clusterId.toLong()]?.dataVersion = dataVersion + } + + private fun addAttributeStatus( + endpointId: UShort, + clusterId: UInt, + attributeId: UInt, + statusToAdd: Status + ) { + val endpointState = getEndpointState(endpointId) + val clusterState = endpointState.getClusterState(clusterId) + if (clusterState.attributes[attributeId.toLong()] != null) { + clusterState.attributes.remove(attributeId.toLong()) + } + clusterState.attributeStatuses[attributeId.toLong()] = statusToAdd + } + + private fun addEventStatus( + endpointId: UShort, + clusterId: UInt, + eventId: UInt, + statusToAdd: Status + ) { + val endpointState = getEndpointState(endpointId) + val clusterState = endpointState.getClusterState(clusterId) + if (clusterState.events[eventId.toLong()] != null) { + clusterState.events.remove(eventId.toLong()) + } + val eventStatuses = clusterState.eventStatuses.getOrDefault(eventId.toLong(), mutableListOf()) + eventStatuses.add(statusToAdd) + + clusterState.eventStatuses[eventId.toLong()] = eventStatuses + } + + private fun getEndpointState(endpointId: UShort): EndpointState { + var endpointState: EndpointState? = endpoints[endpointId.toInt()] + if (endpointState == null) { + endpointState = EndpointState(endpointId.toInt()) + endpoints[endpointId.toInt()] = endpointState + } + return endpointState + } + + private fun addAttribute( + endpointId: Int, + clusterId: Long, + attributeId: Long, + valueObject: Any, + tlv: ByteArray, + jsonString: String + ) { + addAttribute( + endpointId.toUShort(), + clusterId.toUInt(), + attributeId.toUInt(), + AttributeState( + attributeId, + tlv, + jsonString, + AttributePath(endpointId.toUShort(), clusterId.toUInt(), attributeId.toUInt()), + valueObject + ) + ) + } + + private fun addEvent( + endpointId: Int, + clusterId: Long, + eventId: Long, + eventNumber: Long, + priorityLevel: Int, + timestampType: Int, + timestampValue: Long, + valueObject: Any, + tlv: ByteArray, + jsonString: String + ) { + addEvent( + endpointId.toUShort(), + clusterId.toUInt(), + eventId.toUInt(), + EventState( + eventId, + eventNumber, + priorityLevel, + timestampType, + timestampValue, + tlv, + EventPath(endpointId.toUShort(), clusterId.toUInt(), eventId.toUInt()), + jsonString, + valueObject + ) + ) + } + + private fun setDataVersion(endpointId: Int, clusterId: Long, dataVersion: Long) { + setDataVersion(endpointId.toUShort(), clusterId.toUInt(), dataVersion.toUInt()) + } + + private fun addAttributeStatus( + endpointId: Int, + clusterId: Long, + attributeId: Long, + status: Int, + clusterStatus: Int? + ) { + addAttributeStatus( + endpointId.toUShort(), + clusterId.toUInt(), + attributeId.toUInt(), + Status(status, clusterStatus) + ) + } + + private fun addEventStatus( + endpointId: Int, + clusterId: Long, + eventId: Long, + status: Int, + clusterStatus: Int? + ) { + addEventStatus( + endpointId.toUShort(), + clusterId.toUInt(), + eventId.toUInt(), + Status(status, clusterStatus) + ) + } +} /** * Represents information about an endpoint and its cluster data. @@ -30,7 +173,24 @@ data class NodeState(val endpoints: Map) * @param id The endpoint ID. * @param clusters A mapping of cluster IDs to the cluster data. */ -data class EndpointState(val id: Int, val clusters: Map) +class EndpointState(val id: Int, val clusters: MutableMap = mutableMapOf()) { + fun addAttribute(clusterId: UInt, attributeId: UInt, attributeState: AttributeState) { + getClusterState(clusterId).addAttribute(attributeId, attributeState) + } + + fun addEvent(clusterId: UInt, eventId: UInt, eventState: EventState) { + getClusterState(clusterId).addEvent(eventId, eventState) + } + + internal fun getClusterState(clusterId: UInt): ClusterState { + var clusterState: ClusterState? = clusters[clusterId.toLong()] + if (clusterState == null) { + clusterState = ClusterState(clusterId.toLong()) + clusters[clusterId.toLong()] = clusterState + } + return clusterState + } +} /** * Represents information about a cluster. @@ -40,11 +200,28 @@ data class EndpointState(val id: Int, val clusters: Map) * @param events A mapping of event IDs to lists of events that occurred on the node under this * cluster. */ -data class ClusterState( +class ClusterState( val id: Long, - val attributes: Map, - val events: Map> -) + val attributes: MutableMap = mutableMapOf(), + val events: MutableMap> = mutableMapOf(), + var dataVersion: UInt? = null, + val attributeStatuses: MutableMap = mutableMapOf(), + val eventStatuses: MutableMap> = mutableMapOf() +) { + fun addAttribute(attributeId: UInt, attributeState: AttributeState) { + attributes[attributeId.toLong()] = attributeState + } + + fun addEvent(eventId: UInt, eventState: EventState) { + var eventStateList = events[eventId.toLong()] + if (eventStateList == null) { + eventStateList = mutableListOf() + events[eventId.toLong()] = eventStateList + } + + eventStateList.add(eventState) + } +} /** * Represents information about an attribute. @@ -53,7 +230,13 @@ data class ClusterState( * @param tlvValue The raw TLV-encoded attribute value. * @param jsonValue A JSON string representing the raw attribute value. */ -data class AttributeState(val id: Long, val tlvValue: ByteArray, val jsonValue: String) +data class AttributeState( + val id: Long, + val tlvValue: ByteArray, + val jsonValue: String, + val path: AttributePath, + val valueObject: Any? = null +) /** * Represents information about an event. @@ -71,5 +254,22 @@ data class EventState( val priorityLevel: Int, val timestampType: Int, val timestampValue: Long, - val tlvValue: ByteArray -) + val tlvValue: ByteArray, + val path: EventPath, + val jsonValue: String? = null, + val valueObject: Any? = null, +) { + enum class TypeStampTypeEnum(val type: Int) { + MILLIS_SINCE_BOOT(0), + MILLIS_SINCE_EPOCH(1) + } + + fun getTimestampType(): TypeStampTypeEnum? { + for (type in TypeStampTypeEnum.values()) { + if (type.type == timestampType) { + return type + } + } + return null + } +} diff --git a/src/controller/java/src/matter/controller/model/Status.kt b/src/controller/java/src/matter/controller/model/Status.kt new file mode 100644 index 00000000000000..fa12f0b1cb25a5 --- /dev/null +++ b/src/controller/java/src/matter/controller/model/Status.kt @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023 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. + * + */ +package matter.controller.model + +/** + * Represents information about a node, including data on all available endpoints. + * + * @param endpoints A mapping of endpoint IDs with the associated cluster data. + */ +data class Status(val status: Int, val clusterStatus: Int?) { + enum class Code(val id: Int) { + SUCCESS(0X0), + FAILURE(0X01), + INVALID_SUSBSCRIPTION(0X7D), + UNSUPPORTED_ACCESS(0X7E), + UNSUPPORTED_ENDPOINT(0X7F), + INVALID_ACTION(0X80), + UNSUPPORTED_COMMAND(0X81), + DEPRECATED82(0X82), + DEPRECATED83(0X83), + DEPRECATED84(0X84), + INVALID_COMMAND(0X85), + UNSUPPORTED_ATTRIBUTE(0X86), + CONSTRAINT_ERROR(0X87), + UNSUPPORTED_WRITE(0X88), + RESOURCE_EXHAUSTED(0X89), + DEPRECATED8A(0X8A), + NOT_FOUND(0X8B), + UNREPORTABLE_ATTRIBUTE(0X8C), + INVALID_DATATYPE(0X8D), + DEPRECATED8E(0X8E), + UNSUPPORTED_READ(0X8F), + DEPRECATED90(0X90), + DEPRECATED91(0X91), + DATA_VERSION_MISMATCH(0X92), + DEPRECATED93(0X93), + TIMEOUT(0X94), + RESERVED95(0X95), + RESERVED96(0X96), + RESERVED97(0X97), + RESERVED98(0X98), + RESERVED99(0X99), + RESERVED9A(0X9A), + BUSY(0X9C), + DEPRECATEDC0(0XC0), + DEPRECATEDC1(0XC1), + DEPRECATEDC2(0XC2), + UNSUPPORTED_CLUSTER(0XC3), + DEPRECATEDC4(0XC4), + NO_UPSTREAM_SUBSRICPTION(0XC5), + NEEDS_TIMED_INTERACTION(0XC6), + UNSUPPORTED_EVENT(0XC7), + PATH_EXHAUSTED(0XC8), + TIMED_REQUEST_MISMATCH(0XC9), + FAILSAFE_REQUIRED(0XCA), + INVALID_IN_STATE(0XCB), + NO_COMMAND_RESPONSE(0XCC), + WRITE_IGNORED(0XF0) + } + + fun getCode(): Code? { + for (code in Code.values()) { + if (code.id == status) { + return code + } + } + return null + } + + override fun toString(): String = "$status/$clusterStatus/" +} diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index b4f2edb2955005..d78c9da8ed74d3 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -152,6 +152,8 @@ PyChipError pychip_DeviceController_EstablishPASESessionIP(chip::Controller::Dev uint32_t setupPINCode, chip::NodeId nodeid, uint16_t port); PyChipError pychip_DeviceController_EstablishPASESessionBLE(chip::Controller::DeviceCommissioner * devCtrl, uint32_t setupPINCode, uint16_t discriminator, chip::NodeId nodeid); +PyChipError pychip_DeviceController_EstablishPASESession(chip::Controller::DeviceCommissioner * devCtrl, const char * setUpCode, + chip::NodeId nodeid); PyChipError pychip_DeviceController_Commission(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeid); PyChipError pychip_DeviceController_DiscoverCommissionableNodesLongDiscriminator(chip::Controller::DeviceCommissioner * devCtrl, @@ -600,6 +602,13 @@ PyChipError pychip_DeviceController_EstablishPASESessionBLE(chip::Controller::De return ToPyChipError(devCtrl->EstablishPASEConnection(nodeid, params)); } +PyChipError pychip_DeviceController_EstablishPASESession(chip::Controller::DeviceCommissioner * devCtrl, const char * setUpCode, + chip::NodeId nodeid) +{ + sPairingDelegate.SetExpectingPairingComplete(true); + return ToPyChipError(devCtrl->EstablishPASEConnection(nodeid, setUpCode)); +} + PyChipError pychip_DeviceController_Commission(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeid) { CommissioningParameters params; diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 2400d543f6d09e..318c2b56ef3d4d 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -500,6 +500,15 @@ def EstablishPASESessionIP(self, ipaddr: str, setupPinCode: int, nodeid: int, po self.devCtrl, ipaddr.encode("utf-8"), setupPinCode, nodeid, port) ) + def EstablishPASESession(self, setUpCode: str, nodeid: int): + self.CheckIsActive() + + self.state = DCState.RENDEZVOUS_ONGOING + return self._ChipStack.CallAsync( + lambda: self._dmLib.pychip_DeviceController_EstablishPASESession( + self.devCtrl, setUpCode.encode("utf-8"), nodeid) + ) + def GetTestCommissionerUsed(self): return self._ChipStack.Call( lambda: self._dmLib.pychip_TestCommissionerUsed() @@ -1588,6 +1597,9 @@ def _InitLib(self): self._dmLib.pychip_DeviceController_EstablishPASESessionBLE.argtypes = [ c_void_p, c_uint32, c_uint16, c_uint64] self._dmLib.pychip_DeviceController_EstablishPASESessionBLE.restype = PyChipError + self._dmLib.pychip_DeviceController_EstablishPASESession.argtypes = [ + c_void_p, c_char_p, c_uint64] + self._dmLib.pychip_DeviceController_EstablishPASESession.restype = PyChipError self._dmLib.pychip_DeviceController_DiscoverAllCommissionableNodes.argtypes = [ c_void_p] diff --git a/src/controller/python/chip/clusters/ClusterObjects.py b/src/controller/python/chip/clusters/ClusterObjects.py index 0aef317257014f..111274c884a8dd 100644 --- a/src/controller/python/chip/clusters/ClusterObjects.py +++ b/src/controller/python/chip/clusters/ClusterObjects.py @@ -301,7 +301,7 @@ def __init_subclass__(cls, *args, **kwargs) -> None: """Register a subclass.""" super().__init_subclass__(*args, **kwargs) try: - if cls.cluster_id not in ALL_ATTRIBUTES: + if cls.standard_attribute and cls.cluster_id not in ALL_ATTRIBUTES: ALL_ATTRIBUTES[cls.cluster_id] = {} # register this clusterattribute in the ALL_ATTRIBUTES dict for quick lookups ALL_ATTRIBUTES[cls.cluster_id][cls.attribute_id] = cls @@ -345,6 +345,10 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: def must_use_timed_write(cls) -> bool: return False + @ChipUtility.classproperty + def standard_attribute(cls) -> bool: + return True + @ChipUtility.classproperty def _cluster_object(cls) -> ClusterObject: return make_dataclass('InternalClass', diff --git a/src/controller/python/chip/clusters/__init__.py b/src/controller/python/chip/clusters/__init__.py index bd15d261d8962a..85048384d8a81c 100644 --- a/src/controller/python/chip/clusters/__init__.py +++ b/src/controller/python/chip/clusters/__init__.py @@ -38,12 +38,12 @@ OccupancySensing, OnOff, OnOffSwitchConfiguration, OperationalCredentials, OperationalState, OtaSoftwareUpdateProvider, OtaSoftwareUpdateRequestor, OvenCavityOperationalState, OvenMode, OzoneConcentrationMeasurement, Pm1ConcentrationMeasurement, Pm10ConcentrationMeasurement, - Pm25ConcentrationMeasurement, PowerSource, PowerSourceConfiguration, PressureMeasurement, ProxyConfiguration, - ProxyDiscovery, ProxyValid, PulseWidthModulation, PumpConfigurationAndControl, RadonConcentrationMeasurement, - RefrigeratorAlarm, RefrigeratorAndTemperatureControlledCabinetMode, RelativeHumidityMeasurement, RvcCleanMode, - RvcOperationalState, RvcRunMode, ScenesManagement, SmokeCoAlarm, SoftwareDiagnostics, Switch, TargetNavigator, - TemperatureControl, TemperatureMeasurement, Thermostat, ThermostatUserInterfaceConfiguration, - ThreadNetworkDiagnostics, TimeFormatLocalization, TimeSynchronization, + Pm25ConcentrationMeasurement, PowerSource, PowerSourceConfiguration, PowerTopology, PressureMeasurement, + ProxyConfiguration, ProxyDiscovery, ProxyValid, PulseWidthModulation, PumpConfigurationAndControl, + RadonConcentrationMeasurement, RefrigeratorAlarm, RefrigeratorAndTemperatureControlledCabinetMode, + RelativeHumidityMeasurement, RvcCleanMode, RvcOperationalState, RvcRunMode, ScenesManagement, SmokeCoAlarm, + SoftwareDiagnostics, Switch, TargetNavigator, TemperatureControl, TemperatureMeasurement, Thermostat, + ThermostatUserInterfaceConfiguration, ThreadNetworkDiagnostics, TimeFormatLocalization, TimeSynchronization, TotalVolatileOrganicCompoundsConcentrationMeasurement, UnitLocalization, UnitTesting, UserLabel, ValveConfigurationAndControl, WakeOnLan, WiFiNetworkDiagnostics, WindowCovering) @@ -61,7 +61,7 @@ OccupancySensing, OnOff, OnOffSwitchConfiguration, OperationalCredentials, OperationalState, OtaSoftwareUpdateProvider, OtaSoftwareUpdateRequestor, OvenCavityOperationalState, OvenMode, OzoneConcentrationMeasurement, Pm1ConcentrationMeasurement, Pm10ConcentrationMeasurement, - Pm25ConcentrationMeasurement, PowerSource, PowerSourceConfiguration, PressureMeasurement, ProxyConfiguration, + Pm25ConcentrationMeasurement, PowerSource, PowerSourceConfiguration, PowerTopology, PressureMeasurement, ProxyConfiguration, ProxyDiscovery, ProxyValid, PulseWidthModulation, PumpConfigurationAndControl, RadonConcentrationMeasurement, RefrigeratorAlarm, RefrigeratorAndTemperatureControlledCabinetMode, RelativeHumidityMeasurement, RvcCleanMode, RvcOperationalState, RvcRunMode, ScenesManagement, SmokeCoAlarm, SoftwareDiagnostics, diff --git a/src/controller/python/chip/interaction_model/__init__.py b/src/controller/python/chip/interaction_model/__init__.py index 61faa7f7d5d741..ec100846b085a5 100644 --- a/src/controller/python/chip/interaction_model/__init__.py +++ b/src/controller/python/chip/interaction_model/__init__.py @@ -86,6 +86,7 @@ class Status(enum.IntEnum): FailsafeRequired = 0xca InvalidInState = 0xcb NoCommandResponse = 0xcc + WriteIgnored = 0xf0 class InteractionModelError(ChipStackException): diff --git a/src/controller/python/test/test_scripts/network_commissioning.py b/src/controller/python/test/test_scripts/network_commissioning.py index 72635677be9c9d..8ecbd59f78393b 100644 --- a/src/controller/python/test/test_scripts/network_commissioning.py +++ b/src/controller/python/test/test_scripts/network_commissioning.py @@ -149,9 +149,9 @@ async def test_wifi(self, endpointId): # Scan networks logger.info("Scan networks") - req = Clusters.NetworkCommissioning.Commands.ScanNetworks( - ssid=b'', breadcrumb=self.with_breadcrumb()) + req = Clusters.NetworkCommissioning.Commands.ScanNetworks(breadcrumb=self.with_breadcrumb()) interactionTimeoutMs = self._devCtrl.ComputeRoundTripTimeout(self._nodeid, upperLayerProcessingTimeoutMs=30000) + logger.info(f"Request: {req}") res = await self._devCtrl.SendCommand( nodeid=self._nodeid, endpoint=endpointId, @@ -309,8 +309,8 @@ async def test_thread(self, endpointId): # Scan networks logger.info("Scan networks") - req = Clusters.NetworkCommissioning.Commands.ScanNetworks( - ssid=b'', breadcrumb=self.with_breadcrumb()) + req = Clusters.NetworkCommissioning.Commands.ScanNetworks(breadcrumb=self.with_breadcrumb()) + logger.info(f"Request: {req}") interactionTimeoutMs = self._devCtrl.ComputeRoundTripTimeout(self._nodeid, upperLayerProcessingTimeoutMs=30000) res = await self._devCtrl.SendCommand(nodeid=self._nodeid, endpoint=endpointId, diff --git a/src/crypto/CHIPCryptoPALmbedTLS.cpp b/src/crypto/CHIPCryptoPALmbedTLS.cpp index d7e0dee28edea6..4df0ce97e30989 100644 --- a/src/crypto/CHIPCryptoPALmbedTLS.cpp +++ b/src/crypto/CHIPCryptoPALmbedTLS.cpp @@ -199,8 +199,6 @@ Hash_SHA256_stream::Hash_SHA256_stream() Hash_SHA256_stream::~Hash_SHA256_stream() { - mbedtls_sha256_context * context = to_inner_hash_sha256_context(&mContext); - mbedtls_sha256_free(context); Clear(); } @@ -272,6 +270,9 @@ CHIP_ERROR Hash_SHA256_stream::Finish(MutableByteSpan & out_buffer) void Hash_SHA256_stream::Clear() { + mbedtls_sha256_context * context = to_inner_hash_sha256_context(&mContext); + mbedtls_sha256_free(context); + mbedtls_platform_zeroize(this, sizeof(*this)); } diff --git a/src/darwin/Framework/CHIP/MTRBaseDevice.mm b/src/darwin/Framework/CHIP/MTRBaseDevice.mm index 0d41d925d49507..2a981cdd860fff 100644 --- a/src/darwin/Framework/CHIP/MTRBaseDevice.mm +++ b/src/darwin/Framework/CHIP/MTRBaseDevice.mm @@ -475,8 +475,21 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue }]; } +static NSDictionary * _MakeDataValueDictionary(NSString * type, id _Nullable value, NSNumber * _Nullable dataVersion) +{ + if (value && dataVersion) { + return @ { MTRTypeKey : type, MTRValueKey : value, MTRDataVersionKey : dataVersion }; + } else if (value) { + return @ { MTRTypeKey : type, MTRValueKey : value }; + } else if (dataVersion) { + return @ { MTRTypeKey : type, MTRDataVersionKey : dataVersion }; + } else { + return @ { MTRTypeKey : type }; + } +} + // Convert TLV data into data-value dictionary as described in MTRDeviceResponseHandler -NSDictionary * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV(chip::TLV::TLVReader * data) +NSDictionary * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV(chip::TLV::TLVReader * data, NSNumber * dataVersion) { chip::TLV::TLVType dataTLVType = data->GetType(); switch (dataTLVType) { @@ -487,8 +500,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue MTR_LOG_ERROR("Error(%s): TLV signed integer decoding failed", chip::ErrorStr(err)); return nil; } - return [NSDictionary dictionaryWithObjectsAndKeys:MTRSignedIntegerValueType, MTRTypeKey, [NSNumber numberWithLongLong:val], - MTRValueKey, nil]; + return _MakeDataValueDictionary(MTRSignedIntegerValueType, @(val), dataVersion); } case chip::TLV::kTLVType_UnsignedInteger: { uint64_t val; @@ -497,8 +509,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue MTR_LOG_ERROR("Error(%s): TLV unsigned integer decoding failed", chip::ErrorStr(err)); return nil; } - return [NSDictionary dictionaryWithObjectsAndKeys:MTRUnsignedIntegerValueType, MTRTypeKey, - [NSNumber numberWithUnsignedLongLong:val], MTRValueKey, nil]; + return _MakeDataValueDictionary(MTRUnsignedIntegerValueType, @(val), dataVersion); } case chip::TLV::kTLVType_Boolean: { bool val; @@ -507,15 +518,14 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue MTR_LOG_ERROR("Error(%s): TLV boolean decoding failed", chip::ErrorStr(err)); return nil; } - return [NSDictionary - dictionaryWithObjectsAndKeys:MTRBooleanValueType, MTRTypeKey, [NSNumber numberWithBool:val], MTRValueKey, nil]; + return _MakeDataValueDictionary(MTRBooleanValueType, @(val), dataVersion); } case chip::TLV::kTLVType_FloatingPointNumber: { // Try float first float floatValue; CHIP_ERROR err = data->Get(floatValue); if (err == CHIP_NO_ERROR) { - return @ { MTRTypeKey : MTRFloatValueType, MTRValueKey : [NSNumber numberWithFloat:floatValue] }; + return _MakeDataValueDictionary(MTRFloatValueType, @(floatValue), dataVersion); } double val; err = data->Get(val); @@ -523,8 +533,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue MTR_LOG_ERROR("Error(%s): TLV floating point decoding failed", chip::ErrorStr(err)); return nil; } - return [NSDictionary - dictionaryWithObjectsAndKeys:MTRDoubleValueType, MTRTypeKey, [NSNumber numberWithDouble:val], MTRValueKey, nil]; + return _MakeDataValueDictionary(MTRDoubleValueType, @(val), dataVersion); } case chip::TLV::kTLVType_UTF8String: { CharSpan stringValue; @@ -538,7 +547,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue MTR_LOG_ERROR("Error(%s): TLV UTF8String value is not actually UTF-8", err.AsString()); return nil; } - return @ { MTRTypeKey : MTRUTF8StringValueType, MTRValueKey : stringObj }; + return _MakeDataValueDictionary(MTRUTF8StringValueType, stringObj, dataVersion); } case chip::TLV::kTLVType_ByteString: { ByteSpan bytesValue; @@ -547,10 +556,10 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue MTR_LOG_ERROR("Error(%s): TLV ByteString decoding failed", chip::ErrorStr(err)); return nil; } - return @ { MTRTypeKey : MTROctetStringValueType, MTRValueKey : AsData(bytesValue) }; + return _MakeDataValueDictionary(MTROctetStringValueType, AsData(bytesValue), dataVersion); } case chip::TLV::kTLVType_Null: { - return [NSDictionary dictionaryWithObjectsAndKeys:MTRNullValueType, MTRTypeKey, nil]; + return _MakeDataValueDictionary(MTRNullValueType, nil, dataVersion); } case chip::TLV::kTLVType_Structure: case chip::TLV::kTLVType_Array: { @@ -606,7 +615,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue MTR_LOG_ERROR("Error(%s): TLV container exiting failed", chip::ErrorStr(err)); return nil; } - return [NSDictionary dictionaryWithObjectsAndKeys:typeName, MTRTypeKey, array, MTRValueKey, nil]; + return _MakeDataValueDictionary(typeName, array, dataVersion); } default: MTR_LOG_ERROR("Error: Unsupported TLV type for conversion: %u", (unsigned) data->GetType()); @@ -815,7 +824,7 @@ CHIP_ERROR Encode(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const class BufferedReadClientCallback final : public app::ReadClient::Callback { public: using OnSuccessAttributeCallbackType - = std::function; + = std::function; using OnSuccessEventCallbackType = std::function; using OnErrorCallbackType = std::function; @@ -1027,6 +1036,16 @@ - (void)readAttributePaths:(NSArray * _Nullable)attri params:(MTRReadParams * _Nullable)params queue:(dispatch_queue_t)queue completion:(MTRDeviceResponseHandler)completion +{ + [self readAttributePaths:attributePaths eventPaths:eventPaths params:params includeDataVersion:NO queue:queue completion:completion]; +} + +- (void)readAttributePaths:(NSArray * _Nullable)attributePaths + eventPaths:(NSArray * _Nullable)eventPaths + params:(MTRReadParams * _Nullable)params + includeDataVersion:(BOOL)includeDataVersion + queue:(dispatch_queue_t)queue + completion:(MTRDeviceResponseHandler)completion { if ((attributePaths == nil || [attributePaths count] == 0) && (eventPaths == nil || [eventPaths count] == 0)) { // No paths, just return an empty array. @@ -1056,11 +1075,20 @@ - (void)readAttributePaths:(NSArray * _Nullable)attri auto resultArray = [[NSMutableArray alloc] init]; auto onAttributeSuccessCb - = [resultArray](const ConcreteAttributePath & aAttributePath, const MTRDataValueDictionaryDecodableType & aData) { - [resultArray addObject:@ { - MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:aAttributePath], - MTRDataKey : aData.GetDecodedObject() - }]; + = [resultArray, includeDataVersion](const ConcreteDataAttributePath & aAttributePath, const MTRDataValueDictionaryDecodableType & aData) { + // TODO: move this logic into MTRDataValueDictionaryDecodableType + if (includeDataVersion && aAttributePath.mDataVersion.HasValue()) { + NSDictionary * dataValue = aData.GetDecodedObject(); + [resultArray addObject:@{ + MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:aAttributePath], + MTRDataKey : _MakeDataValueDictionary(dataValue[MTRTypeKey], dataValue[MTRValueKey], @(aAttributePath.mDataVersion.Value())) + }]; + } else { + [resultArray addObject:@ { + MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:aAttributePath], + MTRDataKey : aData.GetDecodedObject() + }]; + } }; auto onEventSuccessCb @@ -1948,7 +1976,6 @@ - (void)failSubscribers:(dispatch_queue_t)queue completion:(void (^)(void))compl MTR_LOG_DEBUG("Causing failure in subscribers on purpose"); CauseReadClientFailure(self.deviceController, self.nodeID, queue, completion); } -#endif // The following method is for unit testing purpose only + (id)CHIPEncodeAndDecodeNSObject:(id)object @@ -1990,6 +2017,7 @@ + (id)CHIPEncodeAndDecodeNSObject:(id)object } return decodedData.GetDecodedObject(); } +#endif - (void)readEventsWithEndpointID:(NSNumber * _Nullable)endpointID clusterID:(NSNumber * _Nullable)clusterID diff --git a/src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h b/src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h index 71cdee11d3687d..4ebc454925a4a4 100644 --- a/src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h +++ b/src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h @@ -185,6 +185,16 @@ static inline MTRTransportType MTRMakeTransportType(chip::Transport::Type type) queue:(dispatch_queue_t)queue completion:(void (^)(id _Nullable value, NSError * _Nullable error))completion; +/** + * Same as the public -readAttributePaths:eventPaths:params:queue:completion: except also include the data version in the data-value dictionary in the response dictionary, if the includeDataVersion argument is set to YES. + */ +- (void)readAttributePaths:(NSArray * _Nullable)attributePaths + eventPaths:(NSArray * _Nullable)eventPaths + params:(MTRReadParams * _Nullable)params + includeDataVersion:(BOOL)includeDataVersion + queue:(dispatch_queue_t)queue + completion:(MTRDeviceResponseHandler)completion; + @end @interface MTRClusterPath () @@ -228,7 +238,7 @@ static inline MTRTransportType MTRMakeTransportType(chip::Transport::Type type) // Exported utility function // Convert TLV data into data-value dictionary as described in MTRDeviceResponseHandler -NSDictionary * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV(chip::TLV::TLVReader * data); +NSDictionary * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV(chip::TLV::TLVReader * data, NSNumber * _Nullable dataVersion = nil); // Convert a data-value dictionary as described in MTRDeviceResponseHandler into // TLV Data with an anonymous tag. This method assumes the encoding of the diff --git a/src/darwin/Framework/CHIP/MTRBaseSubscriptionCallback.mm b/src/darwin/Framework/CHIP/MTRBaseSubscriptionCallback.mm index 079cefce5c9fc9..684333bad5f47a 100644 --- a/src/darwin/Framework/CHIP/MTRBaseSubscriptionCallback.mm +++ b/src/darwin/Framework/CHIP/MTRBaseSubscriptionCallback.mm @@ -111,9 +111,9 @@ } VerifyOrDie((aReadPrepareParams.mDataVersionFilterListSize == 0 && aReadPrepareParams.mpDataVersionFilterList == nullptr) - || (aReadPrepareParams.mDataVersionFilterListSize == 1 && aReadPrepareParams.mpDataVersionFilterList != nullptr)); + || (aReadPrepareParams.mDataVersionFilterListSize > 0 && aReadPrepareParams.mpDataVersionFilterList != nullptr)); if (aReadPrepareParams.mpDataVersionFilterList != nullptr) { - delete aReadPrepareParams.mpDataVersionFilterList; + delete[] aReadPrepareParams.mpDataVersionFilterList; } VerifyOrDie((aReadPrepareParams.mEventPathParamsListSize == 0 && aReadPrepareParams.mpEventPathParamsList == nullptr) diff --git a/src/darwin/Framework/CHIP/MTRConversion.h b/src/darwin/Framework/CHIP/MTRConversion.h index 543d80968566c6..b14f4c240f9f67 100644 --- a/src/darwin/Framework/CHIP/MTRConversion.h +++ b/src/darwin/Framework/CHIP/MTRConversion.h @@ -46,6 +46,18 @@ inline NSDate * MatterEpochSecondsAsDate(uint32_t matterEpochSeconds) */ bool DateToMatterEpochSeconds(NSDate * date, uint32_t & epoch); +/** + * Returns whether the conversion could be performed. Will return false if the + * passed-in date is our of the range representable as a Matter epoch-s value. + */ +bool DateToMatterEpochMilliseconds(NSDate * date, uint64_t & matterEpochMilliseconds); + +/** + * Returns whether the conversion could be performed. Will return false if the + * passed-in date is our of the range representable as a Matter epoch-s value. + */ +bool DateToMatterEpochMicroseconds(NSDate * date, uint64_t & matterEpochMicroseconds); + /** * Utilities for converting between NSSet and chip::CATValues. */ diff --git a/src/darwin/Framework/CHIP/MTRConversion.mm b/src/darwin/Framework/CHIP/MTRConversion.mm index c6ba6ec52fbf32..5e657b9330a8e5 100644 --- a/src/darwin/Framework/CHIP/MTRConversion.mm +++ b/src/darwin/Framework/CHIP/MTRConversion.mm @@ -63,18 +63,41 @@ CHIP_ERROR SetToCATValues(NSSet * catSet, chip::CATValues & values) bool DateToMatterEpochSeconds(NSDate * date, uint32_t & matterEpochSeconds) { - auto timeSinceUnixEpoch = date.timeIntervalSince1970; - if (timeSinceUnixEpoch < static_cast(chip::kChipEpochSecondsSinceUnixEpoch)) { - // This is a pre-Matter-epoch time, and cannot be represented in epoch-s. + uint64_t matterEpochMicroseconds = 0; + if (!DateToMatterEpochMicroseconds(date, matterEpochMicroseconds)) { + // Could not convert time return false; } - auto timeSinceMatterEpoch = timeSinceUnixEpoch - chip::kChipEpochSecondsSinceUnixEpoch; + uint64_t timeSinceMatterEpoch = matterEpochMicroseconds / chip::kMicrosecondsPerSecond; if (timeSinceMatterEpoch > UINT32_MAX) { // Too far into the future. return false; } - matterEpochSeconds = static_cast(timeSinceMatterEpoch); return true; } + +bool DateToMatterEpochMilliseconds(NSDate * date, uint64_t & matterEpochMilliseconds) +{ + uint64_t matterEpochMicroseconds = 0; + if (!DateToMatterEpochMicroseconds(date, matterEpochMicroseconds)) { + // Could not convert time + return false; + } + + matterEpochMilliseconds = matterEpochMicroseconds / chip::kMicrosecondsPerMillisecond; + return true; +} + +bool DateToMatterEpochMicroseconds(NSDate * date, uint64_t & matterEpochMicroseconds) +{ + uint64_t timeSinceUnixEpoch = static_cast(date.timeIntervalSince1970 * chip::kMicrosecondsPerSecond); + if (timeSinceUnixEpoch < chip::kChipEpochUsSinceUnixEpoch) { + // This is a pre-Matter-epoch time, and cannot be represented as an epoch time value. + return false; + } + + matterEpochMicroseconds = timeSinceUnixEpoch - chip::kChipEpochUsSinceUnixEpoch; + return true; +} diff --git a/src/darwin/Framework/CHIP/MTRDevice.h b/src/darwin/Framework/CHIP/MTRDevice.h index 96526a2ecacf67..d4641d5dd321b3 100644 --- a/src/darwin/Framework/CHIP/MTRDevice.h +++ b/src/darwin/Framework/CHIP/MTRDevice.h @@ -350,6 +350,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @end MTR_EXTERN NSString * const MTRPreviousDataKey MTR_NEWLY_AVAILABLE; +MTR_EXTERN NSString * const MTRDataVersionKey MTR_NEWLY_AVAILABLE; @protocol MTRDeviceDelegate @required @@ -366,6 +367,10 @@ MTR_EXTERN NSString * const MTRPreviousDataKey MTR_NEWLY_AVAILABLE; * In addition to MTRDataKey, each response-value dictionary in the array may also have this key: * * MTRPreviousDataKey : Same data-value dictionary format as the object for MTRDataKey. This is included when the previous value is known for an attribute. + * + * The data-value dictionary also contains this key: + * + * MTRDataVersionKey : NSNumber-wrapped uin32_t. Monotonically increaseing data version for the cluster. */ - (void)device:(MTRDevice *)device receivedAttributeReport:(NSArray *> *)attributeReport; diff --git a/src/darwin/Framework/CHIP/MTRDevice.mm b/src/darwin/Framework/CHIP/MTRDevice.mm index f2ba2d2173e977..1b42caecf80c76 100644 --- a/src/darwin/Framework/CHIP/MTRDevice.mm +++ b/src/darwin/Framework/CHIP/MTRDevice.mm @@ -20,11 +20,13 @@ #import "MTRAsyncWorkQueue.h" #import "MTRAttributeSpecifiedCheck.h" +#import "MTRBaseClusters.h" #import "MTRBaseDevice_Internal.h" #import "MTRBaseSubscriptionCallback.h" #import "MTRCluster.h" #import "MTRClusterConstants.h" #import "MTRCommandTimedCheck.h" +#import "MTRConversion.h" #import "MTRDefines_Internal.h" #import "MTRDeviceController_Internal.h" #import "MTRDevice_Internal.h" @@ -46,6 +48,7 @@ typedef void (^MTRDeviceAttributeReportHandler)(NSArray * _Nonnull); NSString * const MTRPreviousDataKey = @"previousData"; +NSString * const MTRDataVersionKey = @"dataVersion"; // Consider moving utility classes to their own file #pragma mark - Utility Classes @@ -142,6 +145,9 @@ typedef NS_ENUM(NSUInteger, MTRDeviceWorkItemDuplicateTypeID) { @interface MTRDevice () @property (nonatomic, readonly) os_unfair_lock lock; // protects the caches and device state +// protects against concurrent time updates by guarding timeUpdateScheduled flag which manages time updates scheduling, +// and protects device calls to setUTCTime and setDSTOffset +@property (nonatomic, readonly) os_unfair_lock timeSyncLock; @property (nonatomic) chip::FabricIndex fabricIndex; @property (nonatomic) MTRWeakReference> * weakDelegate; @property (nonatomic) dispatch_queue_t delegateQueue; @@ -189,6 +195,8 @@ @interface MTRDevice () @property (nonatomic) BOOL expirationCheckScheduled; +@property (nonatomic) BOOL timeUpdateScheduled; + @property (nonatomic) NSDate * estimatedStartTimeFromGeneralDiagnosticsUpTime; @property (nonatomic) NSMutableDictionary * temporaryMetaDataCache; @@ -213,12 +221,17 @@ - (NSNumber *)unitTestMaxIntervalOverrideForSubscription:(MTRDevice *)device; @end #endif -@implementation MTRDevice +@implementation MTRDevice { +#ifdef DEBUG + NSUInteger _unitTestAttributesReportedSinceLastCheck; +#endif +} - (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller { if (self = [super init]) { _lock = OS_UNFAIR_LOCK_INIT; + _timeSyncLock = OS_UNFAIR_LOCK_INIT; _nodeID = [nodeID copy]; _fabricIndex = controller.fabricIndex; _deviceController = controller; @@ -244,6 +257,226 @@ + (MTRDevice *)deviceWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceControll return [controller deviceForNodeID:nodeID]; } +#pragma mark - Time Synchronization + +- (void)_setTimeOnDevice +{ + NSDate * now = [NSDate date]; + // If no date available, error + if (!now) { + MTR_LOG_ERROR("%@ Could not retrieve current date. Unable to setUTCTime on endpoints.", self); + return; + } + + NSTimeZone * localTimeZone = [NSTimeZone localTimeZone]; + BOOL setDST = TRUE; + if (!localTimeZone) { + MTR_LOG_ERROR("%@ Could not retrieve local time zone. Unable to setDSTOffset on endpoints.", self); + setDST = FALSE; + } + + uint64_t matterEpochTimeMicroseconds = 0; + uint64_t nextDSTInMatterEpochTimeMicroseconds = 0; + if (!DateToMatterEpochMicroseconds(now, matterEpochTimeMicroseconds)) { + MTR_LOG_ERROR("%@ Could not convert NSDate (%@) to Matter Epoch Time. Unable to setUTCTime on endpoints.", self, now); + return; + } + + int32_t dstOffset = 0; + if (setDST) { + NSTimeInterval dstOffsetAsInterval = [localTimeZone daylightSavingTimeOffsetForDate:now]; + dstOffset = int32_t(dstOffsetAsInterval); + + // Calculate time to next DST. This is needed when we set the current DST. + NSDate * nextDSTTransitionDate = [localTimeZone nextDaylightSavingTimeTransition]; + if (!DateToMatterEpochMicroseconds(nextDSTTransitionDate, nextDSTInMatterEpochTimeMicroseconds)) { + MTR_LOG_ERROR("%@ Could not convert NSDate (%@) to Matter Epoch Time. Unable to setDSTOffset on endpoints.", self, nextDSTTransitionDate); + setDST = FALSE; + } + } + + // Set Time on each Endpoint with a Time Synchronization Cluster Server + NSArray * endpointsToSync = [self _endpointsWithTimeSyncClusterServer]; + for (NSNumber * endpoint in endpointsToSync) { + MTR_LOG_DEBUG("%@ Setting Time on Endpoint %@", self, endpoint); + [self _setUTCTime:matterEpochTimeMicroseconds withGranularity:MTRTimeSynchronizationGranularityMicrosecondsGranularity forEndpoint:endpoint]; + if (setDST) { + [self _setDSTOffset:dstOffset validStarting:0 validUntil:nextDSTInMatterEpochTimeMicroseconds forEndpoint:endpoint]; + } + } +} + +- (void)_scheduleNextUpdate:(UInt64)nextUpdateInSeconds +{ + MTRWeakReference * weakSelf = [MTRWeakReference weakReferenceWithObject:self]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (nextUpdateInSeconds * NSEC_PER_SEC)), self.queue, ^{ + MTR_LOG_DEBUG("%@ Timer expired, start Device Time Update", self); + MTRDevice * strongSelf = weakSelf.strongObject; + if (strongSelf) { + [strongSelf _performScheduledTimeUpdate]; + } else { + MTR_LOG_DEBUG("%@ MTRDevice no longer valid. No Timer Scheduled will be scheduled for a Device Time Update.", self); + return; + } + }); + self.timeUpdateScheduled = YES; + MTR_LOG_DEBUG("%@ Timer Scheduled for next Device Time Update, in %llu seconds", self, nextUpdateInSeconds); +} + +// Time Updates are a day apart (this can be changed in the future) +#define MTR_DEVICE_TIME_UPDATE_DEFAULT_WAIT_TIME_SEC (24 * 60 * 60) +// assume lock is held +- (void)_updateDeviceTimeAndScheduleNextUpdate +{ + os_unfair_lock_assert_owner(&self->_timeSyncLock); + if (self.timeUpdateScheduled) { + MTR_LOG_DEBUG("%@ Device Time Update already scheduled", self); + return; + } + + [self _setTimeOnDevice]; + [self _scheduleNextUpdate:MTR_DEVICE_TIME_UPDATE_DEFAULT_WAIT_TIME_SEC]; +} + +- (void)_performScheduledTimeUpdate +{ + os_unfair_lock_lock(&self->_timeSyncLock); + // Device needs to still be reachable + if (self.state != MTRDeviceStateReachable) { + MTR_LOG_DEBUG("%@ Device is not reachable, canceling Device Time Updates.", self); + os_unfair_lock_unlock(&self->_timeSyncLock); + return; + } + // Device must not be invalidated + if (!self.timeUpdateScheduled) { + MTR_LOG_DEBUG("%@ Device Time Update is no longer scheduled, MTRDevice may have been invalidated.", self); + os_unfair_lock_unlock(&self->_timeSyncLock); + return; + } + self.timeUpdateScheduled = NO; + [self _updateDeviceTimeAndScheduleNextUpdate]; + os_unfair_lock_unlock(&self->_timeSyncLock); +} + +- (NSArray *)_endpointsWithTimeSyncClusterServer +{ + auto partsList = [self readAttributeWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributePartsListID) params:nil]; + NSMutableArray * endpointsOnDevice = [self arrayOfNumbersFromAttributeValue:partsList]; + if (!endpointsOnDevice) { + endpointsOnDevice = [[NSMutableArray alloc] init]; + } + // Add Root node! + [endpointsOnDevice addObject:@(0)]; + + NSMutableArray * endpointsWithTimeSyncCluster = [[NSMutableArray alloc] init]; + for (NSNumber * endpoint in endpointsOnDevice) { + // Get list of server clusters on endpoint + auto clusterList = [self readAttributeWithEndpointID:endpoint clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributeServerListID) params:nil]; + NSArray * clusterArray = [self arrayOfNumbersFromAttributeValue:clusterList]; + + if (clusterArray && [clusterArray containsObject:@(MTRClusterIDTypeTimeSynchronizationID)]) { + [endpointsWithTimeSyncCluster addObject:endpoint]; + } + } + MTR_LOG_DEBUG("%@ Device has following endpoints with Time Sync Cluster Server: %@", self, endpointsWithTimeSyncCluster); + return endpointsWithTimeSyncCluster; +} + +- (void)_setUTCTime:(UInt64)matterEpochTime withGranularity:(uint8_t)granularity forEndpoint:(NSNumber *)endpoint +{ + MTR_LOG_DEBUG(" %@ _setUTCTime with matterEpochTime: %llu, endpoint %@", self, matterEpochTime, endpoint); + MTRTimeSynchronizationClusterSetUTCTimeParams * params = [[MTRTimeSynchronizationClusterSetUTCTimeParams + alloc] init]; + params.utcTime = @(matterEpochTime); + params.granularity = @(granularity); + auto setUTCTimeResponseHandler = ^(id _Nullable response, NSError * _Nullable error) { + if (error) { + MTR_LOG_ERROR("%@ _setUTCTime failed on endpoint %@, with parameters %@, error: %@", self, endpoint, params, error); + } + }; + + [self _invokeKnownCommandWithEndpointID:endpoint + clusterID:@(MTRClusterIDTypeTimeSynchronizationID) + commandID:@(MTRCommandIDTypeClusterTimeSynchronizationCommandSetUTCTimeID) + commandPayload:params + expectedValues:nil + expectedValueInterval:nil + timedInvokeTimeout:nil + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:nil + queue:self.queue + completion:setUTCTimeResponseHandler]; +} + +- (void)_setDSTOffset:(int32_t)dstOffset validStarting:(uint64_t)validStarting validUntil:(uint64_t)validUntil forEndpoint:(NSNumber *)endpoint +{ + MTR_LOG_DEBUG("%@ _setDSTOffset with offset: %d, validStarting: %llu, validUntil: %llu, endpoint %@", + self, + dstOffset, validStarting, validUntil, endpoint); + + MTRTimeSynchronizationClusterSetDSTOffsetParams * params = [[MTRTimeSynchronizationClusterSetDSTOffsetParams + alloc] init]; + MTRTimeSynchronizationClusterDSTOffsetStruct * dstOffsetStruct = [[MTRTimeSynchronizationClusterDSTOffsetStruct alloc] init]; + dstOffsetStruct.offset = @(dstOffset); + dstOffsetStruct.validStarting = @(validStarting); + dstOffsetStruct.validUntil = @(validUntil); + params.dstOffset = @[ dstOffsetStruct ]; + + auto setDSTOffsetResponseHandler = ^(id _Nullable response, NSError * _Nullable error) { + if (error) { + MTR_LOG_ERROR("%@ _setDSTOffset failed on endpoint %@, with parameters %@, error: %@", self, endpoint, params, error); + } + }; + + [self _invokeKnownCommandWithEndpointID:endpoint + clusterID:@(MTRClusterIDTypeTimeSynchronizationID) + commandID:@(MTRCommandIDTypeClusterTimeSynchronizationCommandSetDSTOffsetID) + commandPayload:params + expectedValues:nil + expectedValueInterval:nil + timedInvokeTimeout:nil + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:nil + queue:self.queue + completion:setDSTOffsetResponseHandler]; +} + +- (NSMutableArray *)arrayOfNumbersFromAttributeValue:(NSDictionary *)dataDictionary +{ + if (![MTRArrayValueType isEqual:dataDictionary[MTRTypeKey]]) { + return nil; + } + + id value = dataDictionary[MTRValueKey]; + if (![value isKindOfClass:NSArray.class]) { + return nil; + } + + NSArray * valueArray = value; + __auto_type outputArray = [NSMutableArray arrayWithCapacity:valueArray.count]; + + for (id item in valueArray) { + if (![item isKindOfClass:NSDictionary.class]) { + return nil; + } + + NSDictionary * itemDictionary = item; + id data = itemDictionary[MTRDataKey]; + if (![data isKindOfClass:NSDictionary.class]) { + return nil; + } + + NSDictionary * dataDictionary = data; + id dataType = dataDictionary[MTRTypeKey]; + id dataValue = dataDictionary[MTRValueKey]; + if (![dataType isKindOfClass:NSString.class] || ![dataValue isKindOfClass:NSNumber.class]) { + return nil; + } + [outputArray addObject:dataValue]; + } + return outputArray; +} + #pragma mark Subscription and delegate handling // subscription intervals are in seconds @@ -282,6 +515,10 @@ - (void)invalidate [_asyncWorkQueue invalidate]; + os_unfair_lock_lock(&self->_timeSyncLock); + _timeUpdateScheduled = NO; + os_unfair_lock_unlock(&self->_timeSyncLock); + os_unfair_lock_lock(&self->_lock); _state = MTRDeviceStateUnknown; @@ -365,6 +602,8 @@ - (void)_changeState:(MTRDeviceState)state } } +// First Time Sync happens 2 minutes after reachability (this can be changed in the future) +#define MTR_DEVICE_TIME_UPDATE_INITIAL_WAIT_TIME_SEC (60 * 2) - (void)_handleSubscriptionEstablished { os_unfair_lock_lock(&self->_lock); @@ -375,6 +614,14 @@ - (void)_handleSubscriptionEstablished [self _changeState:MTRDeviceStateReachable]; os_unfair_lock_unlock(&self->_lock); + + os_unfair_lock_lock(&self->_timeSyncLock); + + if (!self.timeUpdateScheduled) { + [self _scheduleNextUpdate:MTR_DEVICE_TIME_UPDATE_INITIAL_WAIT_TIME_SEC]; + } + + os_unfair_lock_unlock(&self->_timeSyncLock); } - (void)_handleSubscriptionError:(NSError *)error @@ -641,6 +888,55 @@ - (void)_handleEventReport:(NSArray *> *)eventRepor os_unfair_lock_unlock(&self->_lock); } +- (NSDictionary *)_getCachedDataVersions +{ + NSMutableDictionary * dataVersions = [NSMutableDictionary dictionary]; + os_unfair_lock_lock(&self->_lock); + for (MTRAttributePath * path in _readCache) { + NSDictionary * dataValue = _readCache[path]; + NSNumber * dataVersionNumber = dataValue[MTRDataVersionKey]; + if (dataVersionNumber) { + MTRClusterPath * clusterPath = [MTRClusterPath clusterPathWithEndpointID:path.endpoint clusterID:path.cluster]; + NSNumber * currentDataVersion = dataVersions[clusterPath]; + // Use the highest data version + if (currentDataVersion.unsignedLongValue < dataVersionNumber.unsignedLongValue) { + dataVersions[clusterPath] = dataVersionNumber; + } + } + } + os_unfair_lock_unlock(&self->_lock); + + return dataVersions; +} + +- (void)_createDataVersionFilterListFromDictionary:(NSDictionary *)dataVersions dataVersionFilterList:(DataVersionFilter **)dataVersionFilterList count:(size_t *)count sizeReduction:(size_t)sizeReduction +{ + size_t maxDataVersionFilterSize = dataVersions.count; + + // Check if any filter list should be generated + if (!dataVersions.count || (maxDataVersionFilterSize <= sizeReduction)) { + *count = 0; + *dataVersionFilterList = nullptr; + return; + } + maxDataVersionFilterSize -= sizeReduction; + + DataVersionFilter * dataVersionFilterArray = new DataVersionFilter[maxDataVersionFilterSize]; + size_t i = 0; + for (MTRClusterPath * path in dataVersions) { + NSNumber * dataVersionNumber = dataVersions[path]; + if (dataVersionNumber) { + dataVersionFilterArray[i++] = DataVersionFilter(static_cast(path.endpoint.unsignedShortValue), static_cast(path.cluster.unsignedLongValue), static_cast(dataVersionNumber.unsignedLongValue)); + } + if (i == maxDataVersionFilterSize) { + break; + } + } + + *dataVersionFilterList = dataVersionFilterArray; + *count = maxDataVersionFilterSize; +} + // assume lock is held - (void)_setupSubscription { @@ -677,55 +973,21 @@ - (void)_setupSubscription return; } - // Wildcard endpoint, cluster, attribute, event. - auto attributePath = std::make_unique(); - auto eventPath = std::make_unique(); - // We want to get event reports at the minInterval, not the maxInterval. - eventPath->mIsUrgentEvent = true; - ReadPrepareParams readParams(session.Value()); - - readParams.mMinIntervalFloorSeconds = 0; - // Select a max interval based on the device's claimed idle sleep interval. - auto idleSleepInterval = std::chrono::duration_cast( - session.Value()->GetRemoteMRPConfig().mIdleRetransTimeout); - - auto maxIntervalCeilingMin = System::Clock::Seconds32(MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MIN); - if (idleSleepInterval < maxIntervalCeilingMin) { - idleSleepInterval = maxIntervalCeilingMin; - } - - auto maxIntervalCeilingMax = System::Clock::Seconds32(MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MAX); - if (idleSleepInterval > maxIntervalCeilingMax) { - idleSleepInterval = maxIntervalCeilingMax; - } -#ifdef DEBUG - if (maxIntervalOverride.HasValue()) { - idleSleepInterval = maxIntervalOverride.Value(); - } -#endif - readParams.mMaxIntervalCeilingSeconds = static_cast(idleSleepInterval.count()); - - readParams.mpAttributePathParamsList = attributePath.get(); - readParams.mAttributePathParamsListSize = 1; - readParams.mpEventPathParamsList = eventPath.get(); - readParams.mEventPathParamsListSize = 1; - readParams.mKeepSubscriptions = true; - readParams.mIsFabricFiltered = false; - attributePath.release(); - eventPath.release(); - auto callback = std::make_unique( ^(NSArray * value) { MTR_LOG_INFO("%@ got attribute report %@", self, value); dispatch_async(self.queue, ^{ - // OnAttributeData (after OnReportEnd) + // OnAttributeData [self _handleAttributeReport:value]; +#ifdef DEBUG + self->_unitTestAttributesReportedSinceLastCheck += value.count; +#endif }); }, ^(NSArray * value) { MTR_LOG_INFO("%@ got event report %@", self, value); dispatch_async(self.queue, ^{ - // OnEventReport (after OnReportEnd) + // OnEventReport [self _handleEventReport:value]; }); }, @@ -793,19 +1055,88 @@ - (void)_setupSubscription auto readClient = std::make_unique(InteractionModelEngine::GetInstance(), exchangeManager, clusterStateCache->GetBufferedCallback(), ReadClient::InteractionType::Subscribe); - // SendAutoResubscribeRequest cleans up the params, even on failure. - CHIP_ERROR err = readClient->SendAutoResubscribeRequest(std::move(readParams)); + // Subscribe with data version filter list and retry with smaller list if out of packet space + CHIP_ERROR err; + NSDictionary * dataVersions = [self _getCachedDataVersions]; + size_t dataVersionFilterListSizeReduction = 0; + for (;;) { + // Wildcard endpoint, cluster, attribute, event. + auto attributePath = std::make_unique(); + auto eventPath = std::make_unique(); + // We want to get event reports at the minInterval, not the maxInterval. + eventPath->mIsUrgentEvent = true; + ReadPrepareParams readParams(session.Value()); + + readParams.mMinIntervalFloorSeconds = 0; + // Select a max interval based on the device's claimed idle sleep interval. + auto idleSleepInterval = std::chrono::duration_cast( + session.Value()->GetRemoteMRPConfig().mIdleRetransTimeout); + + auto maxIntervalCeilingMin = System::Clock::Seconds32(MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MIN); + if (idleSleepInterval < maxIntervalCeilingMin) { + idleSleepInterval = maxIntervalCeilingMin; + } + + auto maxIntervalCeilingMax = System::Clock::Seconds32(MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MAX); + if (idleSleepInterval > maxIntervalCeilingMax) { + idleSleepInterval = maxIntervalCeilingMax; + } +#ifdef DEBUG + if (maxIntervalOverride.HasValue()) { + idleSleepInterval = maxIntervalOverride.Value(); + } +#endif + readParams.mMaxIntervalCeilingSeconds = static_cast(idleSleepInterval.count()); + + readParams.mpAttributePathParamsList = attributePath.get(); + readParams.mAttributePathParamsListSize = 1; + readParams.mpEventPathParamsList = eventPath.get(); + readParams.mEventPathParamsListSize = 1; + readParams.mKeepSubscriptions = true; + readParams.mIsFabricFiltered = false; + size_t dataVersionFilterListSize = 0; + DataVersionFilter * dataVersionFilterList; + [self _createDataVersionFilterListFromDictionary:dataVersions dataVersionFilterList:&dataVersionFilterList count:&dataVersionFilterListSize sizeReduction:dataVersionFilterListSizeReduction]; + readParams.mDataVersionFilterListSize = dataVersionFilterListSize; + readParams.mpDataVersionFilterList = dataVersionFilterList; + attributePath.release(); + eventPath.release(); + + // TODO: Change from local filter list generation to rehydrating ClusterStateCache ot take advantage of existing filter list sorting algorithm + + // SendAutoResubscribeRequest cleans up the params, even on failure. + err = readClient->SendAutoResubscribeRequest(std::move(readParams)); + if (err == CHIP_NO_ERROR) { + break; + } + + // If error is not a "no memory" issue, then break and go through regular resubscribe logic + if (err != CHIP_ERROR_NO_MEMORY) { + break; + } + + // If "no memory" error is not caused by data version filter list, break as well + if (!dataVersionFilterListSize) { + break; + } + + // Now "no memory" could mean subscribe request packet space ran out. Reduce size and try again immediately + dataVersionFilterListSizeReduction++; + } if (err != CHIP_NO_ERROR) { NSError * error = [MTRError errorForCHIPErrorCode:err logContext:self]; MTR_LOG_ERROR("%@ SendAutoResubscribeRequest error %@", self, error); dispatch_async(self.queue, ^{ [self _handleSubscriptionError:error]; + [self _handleSubscriptionReset]; }); return; } + MTR_LOG_DEFAULT("%@ Subscribe with data version list size %lu, reduced by %lu", self, (unsigned long) dataVersions.count, (unsigned long) dataVersionFilterListSizeReduction); + // Callback and ClusterStateCache and ReadClient will be deleted // when OnDone is called. os_unfair_lock_lock(&self->_lock); @@ -818,6 +1149,15 @@ - (void)_setupSubscription }]; } +#ifdef DEBUG +- (NSUInteger)unitTestAttributesReportedSinceLastCheck +{ + NSUInteger attributesReportedSinceLastCheck = _unitTestAttributesReportedSinceLastCheck; + _unitTestAttributesReportedSinceLastCheck = 0; + return attributesReportedSinceLastCheck; +} +#endif + #pragma mark Device Interactions // Helper function to determine whether an attribute has "Changes Omitted" quality, which indicates that past the priming report in @@ -1055,6 +1395,7 @@ static BOOL AttributeHasChangesOmittedQuality(MTRAttributePath * attributePath) readAttributePaths:attributePaths eventPaths:nil params:readParams + includeDataVersion:YES queue:self.queue completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { if (values) { @@ -1980,7 +2321,8 @@ - (void)invokeCommandWithEndpointID:(NSNumber *)endpointID MTRErrorKey : [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT] }]; } else { - id value = MTRDecodeDataValueDictionaryFromCHIPTLV(apData); + NSNumber * dataVersionNumber = aPath.mDataVersion.HasValue() ? @(aPath.mDataVersion.Value()) : nil; + NSDictionary * value = MTRDecodeDataValueDictionaryFromCHIPTLV(apData, dataVersionNumber); if (value == nil) { MTR_LOG_ERROR("Failed to decode attribute data for path %@", attributePath); [mAttributeReports addObject:@ { diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index 64d70ce647cdb7..edd521845b2415 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -32,6 +32,7 @@ #import "MTRConversion.h" #import "MTRDeviceControllerDelegateBridge.h" #import "MTRDeviceControllerFactory_Internal.h" +#import "MTRDeviceControllerLocalTestStorage.h" #import "MTRDeviceControllerStartupParams.h" #import "MTRDeviceControllerStartupParams_Internal.h" #import "MTRDevice_Internal.h" @@ -173,12 +174,31 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory return nil; } + id storageDelegateToUse = storageDelegate; +#if MTR_PER_CONTROLLER_STORAGE_ENABLED + if (MTRDeviceControllerLocalTestStorage.localTestStorageEnabled) { + storageDelegateToUse = [[MTRDeviceControllerLocalTestStorage alloc] initWithPassThroughStorage:storageDelegate]; + } +#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED _controllerDataStore = [[MTRDeviceControllerDataStore alloc] initWithController:self - storageDelegate:storageDelegate + storageDelegate:storageDelegateToUse storageDelegateQueue:storageDelegateQueue]; if (_controllerDataStore == nil) { return nil; } + } else { +#if MTR_PER_CONTROLLER_STORAGE_ENABLED + if (MTRDeviceControllerLocalTestStorage.localTestStorageEnabled) { + dispatch_queue_t localTestStorageQueue = dispatch_queue_create("org.csa-iot.matter.framework.devicecontroller.localteststorage", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); + MTRDeviceControllerLocalTestStorage * localTestStorage = [[MTRDeviceControllerLocalTestStorage alloc] initWithPassThroughStorage:nil]; + _controllerDataStore = [[MTRDeviceControllerDataStore alloc] initWithController:self + storageDelegate:localTestStorage + storageDelegateQueue:localTestStorageQueue]; + if (_controllerDataStore == nil) { + return nil; + } + } +#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED } // Ensure the otaProviderDelegate, if any, is valid. diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerLocalTestStorage.h b/src/darwin/Framework/CHIP/MTRDeviceControllerLocalTestStorage.h new file mode 100644 index 00000000000000..915834ecabd35c --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerLocalTestStorage.h @@ -0,0 +1,37 @@ +// +/** + * 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. + */ + +#import +#import + +#if MTR_PER_CONTROLLER_STORAGE_ENABLED + +NS_ASSUME_NONNULL_BEGIN + +MTR_EXTERN @interface MTRDeviceControllerLocalTestStorage : NSObject + +// Setting this variable only affects subsequent MTRDeviceController initializations +@property (class, nonatomic, assign) BOOL localTestStorageEnabled; + +// This storage persists items to NSUserDefaults for MTRStorageSharingTypeNotShared data. Items with other sharing types will be droppped, or stored/fetched with the "passthrough storage" if one is specified. +- (instancetype)initWithPassThroughStorage:(id _Nullable)passThroughStorage; + +@end + +NS_ASSUME_NONNULL_END + +#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerLocalTestStorage.m b/src/darwin/Framework/CHIP/MTRDeviceControllerLocalTestStorage.m new file mode 100644 index 00000000000000..4d52e4bf18afb6 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerLocalTestStorage.m @@ -0,0 +1,97 @@ +// +/** + * 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. + */ + +#import "MTRDeviceControllerLocalTestStorage.h" + +#if MTR_PER_CONTROLLER_STORAGE_ENABLED + +static NSString * const kLocalTestUserDefaultDomain = @"org.csa-iot.matter.darwintest"; +static NSString * const kLocalTestUserDefaultEnabledKey = @"enableTestStorage"; + +@implementation MTRDeviceControllerLocalTestStorage { + id _passThroughStorage; +} + ++ (BOOL)localTestStorageEnabled +{ + NSUserDefaults * defaults = [[NSUserDefaults alloc] initWithSuiteName:kLocalTestUserDefaultDomain]; + return [defaults boolForKey:kLocalTestUserDefaultEnabledKey]; +} + ++ (void)setLocalTestStorageEnabled:(BOOL)localTestStorageEnabled +{ + NSUserDefaults * defaults = [[NSUserDefaults alloc] initWithSuiteName:kLocalTestUserDefaultDomain]; + [defaults setBool:localTestStorageEnabled forKey:kLocalTestUserDefaultEnabledKey]; +} + +- (instancetype)initWithPassThroughStorage:(id)passThroughStorage +{ + if (self = [super init]) { + _passThroughStorage = passThroughStorage; + } + return self; +} + +- (nullable id)controller:(MTRDeviceController *)controller + valueForKey:(NSString *)key + securityLevel:(MTRStorageSecurityLevel)securityLevel + sharingType:(MTRStorageSharingType)sharingType +{ + if (sharingType == MTRStorageSharingTypeNotShared) { + NSUserDefaults * defaults = [[NSUserDefaults alloc] initWithSuiteName:kLocalTestUserDefaultDomain]; + NSData * storedData = [defaults dataForKey:key]; + NSError * error; + id value = [NSKeyedUnarchiver unarchivedObjectOfClasses:MTRDeviceControllerStorageClasses() fromData:storedData error:&error]; + return value; + } else { + return [_passThroughStorage controller:controller valueForKey:key securityLevel:securityLevel sharingType:sharingType]; + } +} + +- (BOOL)controller:(MTRDeviceController *)controller + storeValue:(id)value + forKey:(NSString *)key + securityLevel:(MTRStorageSecurityLevel)securityLevel + sharingType:(MTRStorageSharingType)sharingType +{ + if (sharingType == MTRStorageSharingTypeNotShared) { + NSError * error; + NSData * data = [NSKeyedArchiver archivedDataWithRootObject:value requiringSecureCoding:YES error:&error]; + NSUserDefaults * defaults = [[NSUserDefaults alloc] initWithSuiteName:kLocalTestUserDefaultDomain]; + [defaults setObject:data forKey:key]; + return YES; + } else { + return [_passThroughStorage controller:controller storeValue:value forKey:key securityLevel:securityLevel sharingType:sharingType]; + } +} + +- (BOOL)controller:(MTRDeviceController *)controller + removeValueForKey:(NSString *)key + securityLevel:(MTRStorageSecurityLevel)securityLevel + sharingType:(MTRStorageSharingType)sharingType +{ + if (sharingType == MTRStorageSharingTypeNotShared) { + NSUserDefaults * defaults = [[NSUserDefaults alloc] initWithSuiteName:kLocalTestUserDefaultDomain]; + [defaults removeObjectForKey:key]; + return YES; + } else { + return [_passThroughStorage controller:controller removeValueForKey:key securityLevel:securityLevel sharingType:sharingType]; + } +} +@end + +#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED diff --git a/src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm b/src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm index c37754e15a95e9..36dc5b27410da1 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm @@ -138,6 +138,16 @@ - (void)readAttributePaths:(NSArray * _Nullable)attri params:(MTRReadParams * _Nullable)params queue:(dispatch_queue_t)queue completion:(MTRDeviceResponseHandler)completion +{ + [self readAttributePaths:attributePaths eventPaths:eventPaths params:params includeDataVersion:NO queue:queue completion:completion]; +} + +- (void)readAttributePaths:(NSArray * _Nullable)attributePaths + eventPaths:(NSArray * _Nullable)eventPaths + params:(MTRReadParams * _Nullable)params + includeDataVersion:(BOOL)includeDataVersion + queue:(dispatch_queue_t)queue + completion:(MTRDeviceResponseHandler)completion { if (attributePaths == nil || eventPaths != nil) { MTR_LOG_ERROR("MTRBaseDevice doesn't support reading event paths over XPC"); diff --git a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m index 66bca12cc47bfd..e4628bd475b5ae 100644 --- a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m +++ b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m @@ -25,8 +25,10 @@ #import #import "MTRCommandPayloadExtensions_Internal.h" +#import "MTRDeviceControllerLocalTestStorage.h" #import "MTRDeviceTestDelegate.h" #import "MTRErrorTestUtils.h" +#import "MTRTestDeclarations.h" #import "MTRTestKeys.h" #import "MTRTestResetCommissioneeHelper.h" #import "MTRTestStorage.h" @@ -74,19 +76,6 @@ static void WaitForCommissionee(XCTestExpectation * expectation) return mConnectedDevice; } -#ifdef DEBUG -@interface MTRBaseDevice (Test) -- (void)failSubscribers:(dispatch_queue_t)queue completion:(void (^)(void))completion; - -// Test function for whitebox testing -+ (id)CHIPEncodeAndDecodeNSObject:(id)object; -@end - -@interface MTRDevice (Test) -- (void)unitTestInjectEventReport:(NSArray *> *)eventReport; -@end -#endif - @interface MTRDeviceTestDeviceControllerDelegate : NSObject @property (nonatomic, strong) XCTestExpectation * expectation; @end @@ -129,10 +118,19 @@ @interface MTRDeviceTests : XCTestCase @implementation MTRDeviceTests +#if MTR_PER_CONTROLLER_STORAGE_ENABLED +static BOOL slocalTestStorageEnabledBeforeUnitTest; +#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED + + (void)setUp { XCTestExpectation * pairingExpectation = [[XCTestExpectation alloc] initWithDescription:@"Pairing Complete"]; +#if MTR_PER_CONTROLLER_STORAGE_ENABLED + slocalTestStorageEnabledBeforeUnitTest = MTRDeviceControllerLocalTestStorage.localTestStorageEnabled; + MTRDeviceControllerLocalTestStorage.localTestStorageEnabled = YES; +#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED + __auto_type * factory = [MTRDeviceControllerFactory sharedInstance]; XCTAssertNotNil(factory); @@ -182,6 +180,14 @@ + (void)tearDown { ResetCommissionee(GetConnectedDevice(), dispatch_get_main_queue(), nil, kTimeoutInSeconds); +#if MTR_PER_CONTROLLER_STORAGE_ENABLED + // Restore testing setting to previous state, and remove all persisted attributes + MTRDeviceControllerLocalTestStorage.localTestStorageEnabled = slocalTestStorageEnabledBeforeUnitTest; + [sController.controllerDataStore clearAllStoredAttributes]; + NSArray * storedAttributesAfterClear = [sController.controllerDataStore getStoredAttributesForNodeID:@(kDeviceId)]; + XCTAssertEqual(storedAttributesAfterClear.count, 0); +#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED + MTRDeviceController * controller = sController; XCTAssertNotNil(controller); [controller shutdown]; @@ -1236,7 +1242,7 @@ - (void)test015_FailedSubscribeWithQueueAcrossShutdown __auto_type * params = [[MTRSubscribeParams alloc] init]; params.resubscribeAutomatically = NO; params.replaceExistingSubscriptions = NO; // Not strictly needed, but checking that doing this does not - // affect this subscription erroring out correctly. + // affect this subscription erroring out correctly. [device subscribeWithQueue:queue minInterval:1 maxInterval:2 @@ -1344,6 +1350,11 @@ - (void)test016_FailedSubscribeWithCacheReadDuringFailure - (void)test017_TestMTRDeviceBasics { + // Ensure the test starts with clean slate, even with MTRDeviceControllerLocalTestStorage enabled + [sController.controllerDataStore clearAllStoredAttributes]; + NSArray * storedAttributesAfterClear = [sController.controllerDataStore getStoredAttributesForNodeID:@(kDeviceId)]; + XCTAssertEqual(storedAttributesAfterClear.count, 0); + __auto_type * device = [MTRDevice deviceWithNodeID:kDeviceId deviceController:sController]; dispatch_queue_t queue = dispatch_get_main_queue(); @@ -1526,6 +1537,7 @@ - (void)test017_TestMTRDeviceBasics // Resubscription test setup XCTestExpectation * subscriptionDroppedExpectation = [self expectationWithDescription:@"Subscription has dropped"]; + delegate.onNotReachable = ^() { [subscriptionDroppedExpectation fulfill]; }; @@ -1600,7 +1612,7 @@ - (void)test018_SubscriptionErrorWhenNotResubscribing MTRSubscribeParams * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(1) maxInterval:@(10)]; params.resubscribeAutomatically = NO; params.replaceExistingSubscriptions = NO; // Not strictly needed, but checking that doing this does not - // affect this subscription erroring out correctly. + // affect this subscription erroring out correctly. __block BOOL subscriptionEstablished = NO; [device subscribeToAttributesWithEndpointID:@1 clusterID:@6 @@ -2826,6 +2838,65 @@ - (void)test030_DeviceAndClusterProperties XCTAssertEqualObjects(cluster.endpointID, @(0)); } +#if MTR_PER_CONTROLLER_STORAGE_ENABLED +- (void)test031_MTRDeviceAttributeCacheLocalTestStorage +{ + dispatch_queue_t queue = dispatch_get_main_queue(); + + // First start with clean slate and + __auto_type * device = [MTRDevice deviceWithNodeID:@(kDeviceId) controller:sController]; + [sController removeDevice:device]; + [sController.controllerDataStore clearAllStoredAttributes]; + NSArray * storedAttributesAfterClear = [sController.controllerDataStore getStoredAttributesForNodeID:@(kDeviceId)]; + XCTAssertEqual(storedAttributesAfterClear.count, 0); + + // Now recreate device and get subscription primed + device = [MTRDevice deviceWithNodeID:@(kDeviceId) controller:sController]; + XCTestExpectation * gotReportsExpectation = [self expectationWithDescription:@"Attribute and Event reports have been received"]; + __auto_type * delegate = [[MTRDeviceTestDelegate alloc] init]; + __weak __auto_type weakDelegate = delegate; + delegate.onReportEnd = ^{ + [gotReportsExpectation fulfill]; + __strong __auto_type strongDelegate = weakDelegate; + strongDelegate.onReportEnd = nil; + }; + [device setDelegate:delegate queue:queue]; + + [self waitForExpectations:@[ gotReportsExpectation ] timeout:60]; + + NSUInteger attributesReportedWithFirstSubscription = [device unitTestAttributesReportedSinceLastCheck]; + + NSArray * dataStoreValuesAfterFirstSubscription = [sController.controllerDataStore getStoredAttributesForNodeID:@(kDeviceId)]; + XCTAssertTrue(dataStoreValuesAfterFirstSubscription.count > 0); + + // Now remove device, resubscribe, and see that it succeeds + [sController removeDevice:device]; + device = [MTRDevice deviceWithNodeID:@(kDeviceId) controller:sController]; + + XCTestExpectation * resubGotReportsExpectation = [self expectationWithDescription:@"Attribute and Event reports have been received for resubscription"]; + delegate.onReportEnd = ^{ + [resubGotReportsExpectation fulfill]; + __strong __auto_type strongDelegate = weakDelegate; + strongDelegate.onReportEnd = nil; + }; + [device setDelegate:delegate queue:queue]; + + [self waitForExpectations:@[ resubGotReportsExpectation ] timeout:60]; + + NSUInteger attributesReportedWithSecondSubscription = [device unitTestAttributesReportedSinceLastCheck]; + + XCTAssertTrue(attributesReportedWithSecondSubscription < attributesReportedWithFirstSubscription); + + // 1) MTRDevice actually gets some attributes reported more than once + // 2) Some attributes do change on resubscribe + // * With all-clusts-app as of 2024-02-10, out of 1287 persisted attributes, still 450 attributes were reported with filter + // And so conservatively, assert that data version filters save at least 300 entries. + NSArray * dataStoreValuesAfterSecondSubscription = [sController.controllerDataStore getStoredAttributesForNodeID:@(kDeviceId)]; + NSUInteger storedAttributeCountDifferenceFromMTRDeviceReport = dataStoreValuesAfterSecondSubscription.count - attributesReportedWithSecondSubscription; + XCTAssertTrue(storedAttributeCountDifferenceFromMTRDeviceReport > 300); +} +#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED + @end @interface MTRDeviceEncoderTests : XCTestCase diff --git a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m index 604ed600fb02d6..38795bcc8cef87 100644 --- a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m +++ b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m @@ -22,6 +22,7 @@ #import "MTRDeviceTestDelegate.h" #import "MTRErrorTestUtils.h" #import "MTRFabricInfoChecker.h" +#import "MTRTestDeclarations.h" #import "MTRTestKeys.h" #import "MTRTestPerControllerStorage.h" #import "MTRTestResetCommissioneeHelper.h" @@ -33,27 +34,6 @@ static NSString * kOnboardingPayload = @"MT:-24J0AFN00KA0648G00"; static const uint16_t kTestVendorId = 0xFFF1u; -#ifdef DEBUG -// MTRDeviceControllerDataStore.h includes C++ header, and so we need to declare the methods separately -@protocol MTRDeviceControllerDataStoreAttributeStoreMethods -- (nullable NSArray *)getStoredAttributesForNodeID:(NSNumber *)nodeID; -- (void)storeAttributeValues:(NSArray *)dataValues forNodeID:(NSNumber *)nodeID; -- (void)clearStoredAttributesForNodeID:(NSNumber *)nodeID; -- (void)clearAllStoredAttributes; -@end - -// Declare internal methods for testing -@interface MTRDeviceController (Test) -+ (void)forceLocalhostAdvertisingOnly; -- (void)removeDevice:(MTRDevice *)device; -@property (nonatomic, readonly, nullable) id controllerDataStore; -@end - -@interface MTRDevice (Test) -- (BOOL)_attributeDataValue:(NSDictionary *)one isEqualToDataValue:(NSDictionary *)theOther; -@end -#endif // DEBUG - @interface MTRPerControllerStorageTestsControllerDelegate : NSObject @property (nonatomic, strong) XCTestExpectation * expectation; @property (nonatomic, strong) NSNumber * deviceID; @@ -1235,20 +1215,45 @@ - (void)test009_TestDataStoreMTRDevice [controller removeDevice:device]; // Verify the new device is initialized with the same values - __auto_type * deviceNew = [MTRDevice deviceWithNodeID:deviceID controller:controller]; - BOOL storedAttributeDifferFromMTRDevice = NO; + __auto_type * newDevice = [MTRDevice deviceWithNodeID:deviceID controller:controller]; + NSUInteger storedAttributeDifferFromMTRDeviceCount = 0; for (NSDictionary * responseValue in dataStoreValues) { MTRAttributePath * path = responseValue[MTRAttributePathKey]; XCTAssertNotNil(path); NSDictionary * dataValue = responseValue[MTRDataKey]; XCTAssertNotNil(dataValue); - NSDictionary * dataValueFromMTRDevice = [deviceNew readAttributeWithEndpointID:path.endpoint clusterID:path.cluster attributeID:path.attribute params:nil]; - if (![deviceNew _attributeDataValue:dataValue isEqualToDataValue:dataValueFromMTRDevice]) { - storedAttributeDifferFromMTRDevice = YES; + NSDictionary * dataValueFromMTRDevice = [newDevice readAttributeWithEndpointID:path.endpoint clusterID:path.cluster attributeID:path.attribute params:nil]; + if (![newDevice _attributeDataValue:dataValue isEqualToDataValue:dataValueFromMTRDevice]) { + storedAttributeDifferFromMTRDeviceCount++; } } - XCTAssertTrue(storedAttributeDifferFromMTRDevice); + + // Only test that 90% of attributes are the same because there are some changing attributes each time (UTC time, for example) + // * With all-clusters-app as of 2024-02-10, about 1.476% of attributes change. + double storedAttributeDifferFromMTRDevicePercentage = storedAttributeDifferFromMTRDeviceCount * 100.0 / dataStoreValues.count; + XCTAssertTrue(storedAttributeDifferFromMTRDevicePercentage < 10.0); + + // Now + __auto_type * newDelegate = [[MTRDeviceTestDelegate alloc] init]; + + XCTestExpectation * newDeviceSubscriptionExpectation = [self expectationWithDescription:@"Subscription has been set up for new device"]; + + newDelegate.onReportEnd = ^{ + [newDeviceSubscriptionExpectation fulfill]; + }; + + [newDevice setDelegate:newDelegate queue:queue]; + + [self waitForExpectations:@[ newDeviceSubscriptionExpectation ] timeout:60]; + newDelegate.onReportEnd = nil; + + // 1) MTRDevice actually gets some attributes reported more than once + // 2) Some attributes do change on resubscribe + // * With all-clusts-app as of 2024-02-10, out of 1287 persisted attributes, still 450 attributes were reported with filter + // And so conservatively, assert that data version filters save at least 300 entries. + NSUInteger storedAttributeCountDifferenceFromMTRDeviceReport = dataStoreValues.count - [device unitTestAttributesReportedSinceLastCheck]; + XCTAssertTrue(storedAttributeCountDifferenceFromMTRDeviceReport > 300); // Reset our commissionee. __auto_type * baseDevice = [MTRBaseDevice deviceWithNodeID:deviceID controller:controller]; diff --git a/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestDeclarations.h b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestDeclarations.h new file mode 100644 index 00000000000000..5b77d0ec06aad7 --- /dev/null +++ b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestDeclarations.h @@ -0,0 +1,60 @@ +// +/** + * 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. + */ + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - Declarations for internal methods + +// MTRDeviceControllerDataStore.h includes C++ header, and so we need to declare the methods separately +@protocol MTRDeviceControllerDataStoreAttributeStoreMethods +- (nullable NSArray *)getStoredAttributesForNodeID:(NSNumber *)nodeID; +- (void)storeAttributeValues:(NSArray *)dataValues forNodeID:(NSNumber *)nodeID; +- (void)clearStoredAttributesForNodeID:(NSNumber *)nodeID; +- (void)clearAllStoredAttributes; +@end + +// Declare internal methods for testing +@interface MTRDeviceController (Test) ++ (void)forceLocalhostAdvertisingOnly; +- (void)removeDevice:(MTRDevice *)device; +@property (nonatomic, readonly, nullable) id controllerDataStore; +@end + +@interface MTRDevice (Test) +- (BOOL)_attributeDataValue:(NSDictionary *)one isEqualToDataValue:(NSDictionary *)theOther; +@end + +#pragma mark - Declarations for items compiled only for DEBUG configuration + +#ifdef DEBUG +@interface MTRBaseDevice (TestDebug) +- (void)failSubscribers:(dispatch_queue_t)queue completion:(void (^)(void))completion; + +// Test function for whitebox testing ++ (id)CHIPEncodeAndDecodeNSObject:(id)object; +@end + +@interface MTRDevice (TestDebug) +- (void)unitTestInjectEventReport:(NSArray *> *)eventReport; +- (NSUInteger)unitTestAttributesReportedSinceLastCheck; +@end +#endif + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index 5e227bc7a8d2b2..a49b33fa3a1ea4 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -240,6 +240,8 @@ 5ACDDD7D27CD16D200EFD68A /* MTRClusterStateCacheContainer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5ACDDD7C27CD16D200EFD68A /* MTRClusterStateCacheContainer.mm */; }; 5ACDDD7E27CD3F3A00EFD68A /* MTRClusterStateCacheContainer_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5ACDDD7B27CD14AF00EFD68A /* MTRClusterStateCacheContainer_Internal.h */; }; 5AE6D4E427A99041001F2493 /* MTRDeviceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AE6D4E327A99041001F2493 /* MTRDeviceTests.m */; }; + 75139A6F2B7FE5E900E3A919 /* MTRDeviceControllerLocalTestStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 75139A6E2B7FE5E900E3A919 /* MTRDeviceControllerLocalTestStorage.m */; }; + 75139A702B7FE68C00E3A919 /* MTRDeviceControllerLocalTestStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 75139A6D2B7FE5D600E3A919 /* MTRDeviceControllerLocalTestStorage.h */; settings = {ATTRIBUTES = (Private, ); }; }; 7534F12828BFF20300390851 /* MTRDeviceAttestationDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7534F12628BFF20300390851 /* MTRDeviceAttestationDelegate.mm */; }; 7534F12928BFF20300390851 /* MTRDeviceAttestationDelegate_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 7534F12728BFF20300390851 /* MTRDeviceAttestationDelegate_Internal.h */; }; 754F3DF427FBB94B00E60580 /* MTREventTLVValueDecoder_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 754F3DF327FBB94B00E60580 /* MTREventTLVValueDecoder_Internal.h */; }; @@ -633,6 +635,9 @@ 5ACDDD7B27CD14AF00EFD68A /* MTRClusterStateCacheContainer_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRClusterStateCacheContainer_Internal.h; sourceTree = ""; }; 5ACDDD7C27CD16D200EFD68A /* MTRClusterStateCacheContainer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRClusterStateCacheContainer.mm; sourceTree = ""; }; 5AE6D4E327A99041001F2493 /* MTRDeviceTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRDeviceTests.m; sourceTree = ""; }; + 75139A6C2B7FE19100E3A919 /* MTRTestDeclarations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRTestDeclarations.h; sourceTree = ""; }; + 75139A6D2B7FE5D600E3A919 /* MTRDeviceControllerLocalTestStorage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDeviceControllerLocalTestStorage.h; sourceTree = ""; }; + 75139A6E2B7FE5E900E3A919 /* MTRDeviceControllerLocalTestStorage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRDeviceControllerLocalTestStorage.m; sourceTree = ""; }; 7534F12628BFF20300390851 /* MTRDeviceAttestationDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceAttestationDelegate.mm; sourceTree = ""; }; 7534F12728BFF20300390851 /* MTRDeviceAttestationDelegate_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDeviceAttestationDelegate_Internal.h; sourceTree = ""; }; 754F3DF327FBB94B00E60580 /* MTREventTLVValueDecoder_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTREventTLVValueDecoder_Internal.h; sourceTree = ""; }; @@ -792,9 +797,6 @@ 039145E02993102B00257B3E /* main.mm */, 03F430A52994100000166449 /* controller */, 039547092992DB02006D42A8 /* editline */, - 039546AD2991E193006D42A8 /* log */, - 039546B12991E194006D42A8 /* system */, - 039546A72991E185006D42A8 /* delay */, 039546A22991E132006D42A8 /* interaction_model */, 039546972991DFC4006D42A8 /* lib_json */, 039546872991C400006D42A8 /* chip-tool */, @@ -815,7 +817,6 @@ 03FB93DA2A46200A0048CB35 /* discover */, 037C3D7C2991BD4F00B7EEE2 /* pairing */, 037C3D852991BD4F00B7EEE2 /* clusters */, - 037C3D8B2991BD4F00B7EEE2 /* tests */, 037C3D8D2991BD4F00B7EEE2 /* provider */, 037C3D932991BD4F00B7EEE2 /* payload */, 037C3D972991BD4F00B7EEE2 /* storage */, @@ -1105,6 +1106,7 @@ 51C984602A61CE2A00B0AD9A /* MTRFabricInfoChecker.m */, 75B0D01C2B71B46F002074DD /* MTRDeviceTestDelegate.h */, 75B0D01D2B71B47F002074DD /* MTRDeviceTestDelegate.m */, + 75139A6C2B7FE19100E3A919 /* MTRTestDeclarations.h */, ); path = TestHelpers; sourceTree = ""; @@ -1238,6 +1240,8 @@ 5136661228067D550025EDAE /* MTRDeviceControllerFactory.h */, 5136661128067D540025EDAE /* MTRDeviceControllerFactory_Internal.h */, 5136661028067D540025EDAE /* MTRDeviceControllerFactory.mm */, + 75139A6D2B7FE5D600E3A919 /* MTRDeviceControllerLocalTestStorage.h */, + 75139A6E2B7FE5E900E3A919 /* MTRDeviceControllerLocalTestStorage.m */, 5A6FEC8D27B5624E00F25F42 /* MTRDeviceControllerOverXPC.h */, 5A830D6B27CFCF590053B85D /* MTRDeviceControllerOverXPC_Internal.h */, 5A6FEC8F27B563D900F25F42 /* MTRDeviceControllerOverXPC.mm */, @@ -1555,6 +1559,7 @@ 1EC4CE6425CC276600D7304F /* MTRBaseClusters.h in Headers */, 3D843712294977000070D20A /* MTRCallbackBridgeBase.h in Headers */, 3DECCB742934C21B00585AEC /* MTRDefines.h in Headers */, + 75139A702B7FE68C00E3A919 /* MTRDeviceControllerLocalTestStorage.h in Headers */, 2C5EEEF6268A85C400CAE3D3 /* MTRDeviceConnectionBridge.h in Headers */, 2C8C8FC0253E0C2100797F05 /* MTRPersistentStorageDelegateBridge.h in Headers */, 51FE72352ACDB40000437032 /* MTRCommandPayloads_Internal.h in Headers */, @@ -1753,7 +1758,6 @@ B45373EF2A9FEBFE00807602 /* ops-raw-skt.c in Sources */, 516411332B6BF77700E67C05 /* MTRServerAccessControl.mm in Sources */, 037C3DD52991C2E200B7EEE2 /* CHIPCommandBridge.mm in Sources */, - 039546BC2991E1CB006D42A8 /* LogCommands.cpp in Sources */, 516411312B6BF70300E67C05 /* DataModelHandler.cpp in Sources */, B45373E12A9FEB7F00807602 /* ops-h1.c in Sources */, B45373EB2A9FEBDB00807602 /* ops-listen.c in Sources */, @@ -1766,13 +1770,11 @@ B45373E62A9FEBA400807602 /* header.c in Sources */, B45374002A9FEC4F00807602 /* unix-init.c in Sources */, B45373DF2A9FEB6F00807602 /* system.c in Sources */, - 039546BD2991E1CB006D42A8 /* SystemCommands.cpp in Sources */, B45373FC2A9FEC4F00807602 /* unix-caps.c in Sources */, B4E262162AA0CF1C00DBA5BC /* RemoteDataModelLogger.mm in Sources */, B45373ED2A9FEBEC00807602 /* ops-pipe.c in Sources */, B45373C02A9FEA9100807602 /* output.c in Sources */, 0395470F2992DB37006D42A8 /* complete.c in Sources */, - 039546BE2991E1CB006D42A8 /* DelayCommands.cpp in Sources */, B4E2621B2AA0D02000DBA5BC /* SleepCommand.mm in Sources */, B45373FF2A9FEC4F00807602 /* unix-misc.c in Sources */, B45373D92A9FEB3800807602 /* poll.c in Sources */, @@ -1840,6 +1842,7 @@ 75B765C32A1D82D30014719B /* MTRAttributeSpecifiedCheck.mm in Sources */, AF5F90FF2878D351005503FA /* MTROTAProviderDelegateBridge.mm in Sources */, 516415FF2B6B132200D5CE11 /* DataModelHandler.cpp in Sources */, + 75139A6F2B7FE5E900E3A919 /* MTRDeviceControllerLocalTestStorage.m in Sources */, 51E95DFC2A78443C00A434F0 /* MTRSessionResumptionStorageBridge.mm in Sources */, 514C79ED2B62ADCD00DD6D7B /* ember-compatibility-functions.cpp in Sources */, 7534F12828BFF20300390851 /* MTRDeviceAttestationDelegate.mm in Sources */, diff --git a/src/include/platform/CHIPDeviceEvent.h b/src/include/platform/CHIPDeviceEvent.h index a7656fd6cba7fc..dae127ceba1f06 100644 --- a/src/include/platform/CHIPDeviceEvent.h +++ b/src/include/platform/CHIPDeviceEvent.h @@ -169,9 +169,10 @@ enum PublicEventTypes /** * When supportsConcurrentConnection = False, the ConnectNetwork command cannot start until - * the BLE device is closed and the WiFi device has been started. + * the BLE device is closed and the Operation Network device (e.g. WiFi) has been started. */ kWiFiDeviceAvailable, + kOperationalNetworkStarted, /** * Thread State Change diff --git a/src/include/platform/DeviceControlServer.h b/src/include/platform/DeviceControlServer.h index 073f6a035e95b0..2d292cfee261f4 100644 --- a/src/include/platform/DeviceControlServer.h +++ b/src/include/platform/DeviceControlServer.h @@ -38,6 +38,7 @@ class DeviceControlServer final CHIP_ERROR PostConnectedToOperationalNetworkEvent(ByteSpan networkID); CHIP_ERROR PostCloseAllBLEConnectionsToOperationalNetworkEvent(); CHIP_ERROR PostWiFiDeviceAvailableNetworkEvent(); + CHIP_ERROR PostOperationalNetworkStartedEvent(); static DeviceControlServer & DeviceControlSvr(); private: diff --git a/src/include/platform/ThreadStackManager.h b/src/include/platform/ThreadStackManager.h index 86d895ec1cfe52..cda3c7acdccbd5 100644 --- a/src/include/platform/ThreadStackManager.h +++ b/src/include/platform/ThreadStackManager.h @@ -121,6 +121,26 @@ class ThreadStackManager CHIP_ERROR RemoveSrpService(const char * aInstanceName, const char * aName); CHIP_ERROR InvalidateAllSrpServices(); ///< Mark all SRP services as invalid CHIP_ERROR RemoveInvalidSrpServices(); ///< Remove SRP services marked as invalid + + /* + * @brief Utility function to clear all thread SRP host and services established between the SRP server and client. + * It is expected that a transaction is done between the SRP server and client so the clear request is applied on both ends + * + * A generic implementation is provided in `GenericThreadStackManagerImpl_OpenThread` with the SoC OT stack + */ + CHIP_ERROR ClearAllSrpHostAndServices(); + + /* + * @brief Used to synchronize on the SRP server response confirming the clearing of the host and service entries + * Should be called in ClearAllSrpHostAndServices once the request is sent. + */ + void WaitOnSrpClearAllComplete(); + + /* + * @brief Notify that the SRP server confirmed the clearing of the host and service entries + * Should be called in the SRP Client set callback in the removal confirmation. + */ + void NotifySrpClearAllComplete(); CHIP_ERROR SetupSrpHost(const char * aHostName); CHIP_ERROR ClearSrpHost(const char * aHostName); CHIP_ERROR SetSrpDnsCallbacks(DnsAsyncReturnCallback aInitCallback, DnsAsyncReturnCallback aErrorCallback, void * aContext); @@ -289,6 +309,21 @@ inline CHIP_ERROR ThreadStackManager::RemoveInvalidSrpServices() return static_cast(this)->_RemoveInvalidSrpServices(); } +inline CHIP_ERROR ThreadStackManager::ClearAllSrpHostAndServices() +{ + return static_cast(this)->_ClearAllSrpHostAndServices(); +} + +inline void ThreadStackManager::WaitOnSrpClearAllComplete() +{ + return static_cast(this)->_WaitOnSrpClearAllComplete(); +} + +inline void ThreadStackManager::NotifySrpClearAllComplete() +{ + return static_cast(this)->_NotifySrpClearAllComplete(); +} + inline CHIP_ERROR ThreadStackManager::SetupSrpHost(const char * aHostName) { return static_cast(this)->_SetupSrpHost(aHostName); diff --git a/src/lib/core/BUILD.gn b/src/lib/core/BUILD.gn index 27611376c10069..9163cafd85fe0c 100644 --- a/src/lib/core/BUILD.gn +++ b/src/lib/core/BUILD.gn @@ -68,7 +68,7 @@ buildconfig_header("chip_buildconfig") { "CHIP_CONFIG_BIG_ENDIAN_TARGET=${chip_target_is_big_endian}", "CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_WRITE=${chip_tlv_validate_char_string_on_write}", "CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ=${chip_tlv_validate_char_string_on_read}", - "CHIP_CONFIG_SENDING_BATCH_COMMANDS_ENABLED=${chip_enable_sending_batch_commands}", + "CHIP_CONFIG_COMMAND_SENDER_BUILTIN_SUPPORT_FOR_BATCHED_COMMANDS=${chip_enable_sending_batch_commands}", ] visibility = [ ":chip_config_header" ] diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 09131aed21cebd..2de6a662ee8c4d 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1703,12 +1703,15 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #endif /** - * @def CHIP_CONFIG_SENDING_BATCH_COMMANDS_ENABLED + * @def CHIP_CONFIG_COMMAND_SENDER_BUILTIN_SUPPORT_FOR_BATCHED_COMMANDS * - * @brief Device supports sending multiple batch commands in a single Invoke Request Message. + * @brief CommandSender will use built-in support to enable sending batch commands in a single Invoke Request Message. + * + * **Important:** This feature is code and RAM intensive. Enable only on platforms where these + * resources are not constrained. */ -#ifndef CHIP_CONFIG_SENDING_BATCH_COMMANDS_ENABLED -#define CHIP_CONFIG_SENDING_BATCH_COMMANDS_ENABLED 0 +#ifndef CHIP_CONFIG_COMMAND_SENDER_BUILTIN_SUPPORT_FOR_BATCHED_COMMANDS +#define CHIP_CONFIG_COMMAND_SENDER_BUILTIN_SUPPORT_FOR_BATCHED_COMMANDS 0 #endif /** diff --git a/src/lib/dnssd/Discovery_ImplPlatform.cpp b/src/lib/dnssd/Discovery_ImplPlatform.cpp index abbc4647ff3805..3369f8c00b3b3b 100644 --- a/src/lib/dnssd/Discovery_ImplPlatform.cpp +++ b/src/lib/dnssd/Discovery_ImplPlatform.cpp @@ -420,8 +420,13 @@ void DiscoveryImplPlatform::HandleDnssdInit(void * context, CHIP_ERROR initError void DiscoveryImplPlatform::HandleDnssdError(void * context, CHIP_ERROR error) { + DiscoveryImplPlatform * publisher = static_cast(context); + if (error == CHIP_ERROR_FORCED_RESET) { + // Restore dnssd state before restart, also needs to call ChipDnssdShutdown() + publisher->Shutdown(); + DeviceLayer::ChipDeviceEvent event; event.Type = DeviceLayer::DeviceEventType::kDnssdRestartNeeded; error = DeviceLayer::PlatformMgr().PostEvent(&event); diff --git a/src/lib/dnssd/Types.h b/src/lib/dnssd/Types.h index 06a7352d60d919..a835ebf5647a97 100644 --- a/src/lib/dnssd/Types.h +++ b/src/lib/dnssd/Types.h @@ -112,7 +112,7 @@ struct CommonResolutionData bool IsDeviceTreatedAsSleepy(const ReliableMessageProtocolConfig * defaultMRPConfig) const { - // If either sleepy interval (Idle - SII, Active - SAI) has a value and that value is greater + // If either session interval (Idle - SII, Active - SAI) has a value and that value is greater // than the value passed to this function, then the peer device will be treated as if it is // a Sleepy End Device (SED) return (mrpRetryIntervalIdle.HasValue() && (mrpRetryIntervalIdle.Value() > defaultMRPConfig->mIdleRetransTimeout)) || diff --git a/src/lib/dnssd/tests/TestIncrementalResolve.cpp b/src/lib/dnssd/tests/TestIncrementalResolve.cpp index 2791631a32e8a0..1cc3b714d28ae3 100644 --- a/src/lib/dnssd/tests/TestIncrementalResolve.cpp +++ b/src/lib/dnssd/tests/TestIncrementalResolve.cpp @@ -294,7 +294,7 @@ void TestParseOperational(nlTestSuite * inSuite, void * inContext) { const char * entries[] = { "foo=bar", // unused data - "SII=23" // sleepy idle interval + "SII=23" // session idle interval }; CallOnRecord(inSuite, resolver, TxtResourceRecord(kTestOperationalName.Full(), entries)); @@ -369,7 +369,7 @@ void TestParseCommissionable(nlTestSuite * inSuite, void * inContext) { const char * entries[] = { "some", "foo=bar", "x=y=z", "a=", // unused data - "SII=123" // Sleepy idle interval + "SII=123" // session idle interval }; CallOnRecord(inSuite, resolver, TxtResourceRecord(kTestHostName.Full(), entries)); @@ -381,7 +381,7 @@ void TestParseCommissionable(nlTestSuite * inSuite, void * inContext) { const char * entries[] = { "foo=bar", // unused data - "SAI=321", // sleepy active interval + "SAI=321", // session active interval "D=22345", // Long discriminator "VP=321+654", // VendorProduct "DN=mytest" // Device name diff --git a/src/lib/support/BUILD.gn b/src/lib/support/BUILD.gn index e1e87aeb2b2192..02ca1eef593def 100644 --- a/src/lib/support/BUILD.gn +++ b/src/lib/support/BUILD.gn @@ -171,6 +171,10 @@ source_set("type-traits") { sources = [ "TypeTraits.h" ] } +source_set("static-support") { + sources = [ "static_support_smart_ptr.h" ] +} + static_library("support") { output_name = "libSupportLayer" @@ -208,6 +212,7 @@ static_library("support") { "Iterators.h", "LambdaBridge.h", "LifetimePersistedCounter.h", + "LinkedList.h", "ObjectLifeCycle.h", "OwnerOf.h", "PersistedCounter.h", diff --git a/src/lib/support/CHIPFaultInjection.cpp b/src/lib/support/CHIPFaultInjection.cpp index fc50021a6fe1e9..15cb5a40ec5b4d 100644 --- a/src/lib/support/CHIPFaultInjection.cpp +++ b/src/lib/support/CHIPFaultInjection.cpp @@ -35,9 +35,21 @@ static int32_t sFault_FuzzExchangeHeader_Arguments[1]; static class nl::FaultInjection::Manager sChipFaultInMgr; static const nl::FaultInjection::Name sManagerName = "chip"; static const nl::FaultInjection::Name sFaultNames[] = { - "AllocExchangeContext", "DropIncomingUDPMsg", "DropOutgoingUDPMsg", "AllocBinding", "SendAlarm", - "HandleAlarm", "FuzzExchangeHeaderTx", "RMPDoubleTx", "RMPSendError", "BDXBadBlockCounter", - "BDXAllocTransfer", "CASEKeyConfirm", "SecMgrBusy", + "AllocExchangeContext", + "DropIncomingUDPMsg", + "DropOutgoingUDPMsg", + "AllocBinding", + "SendAlarm", + "HandleAlarm", + "FuzzExchangeHeaderTx", + "RMPDoubleTx", + "RMPSendError", + "BDXBadBlockCounter", + "BDXAllocTransfer", + "SecMgrBusy", + "IMInvoke_SeparateResponses", + "IMInvoke_SeparateResponsesInvertResponseOrder", + "IMInvoke_SkipSecondResponse", #if CONFIG_NETWORK_LAYER_BLE "CHIPOBLESend", #endif // CONFIG_NETWORK_LAYER_BLE diff --git a/src/lib/support/CHIPFaultInjection.h b/src/lib/support/CHIPFaultInjection.h index 9fe78aed8c9ac9..44e582ba01d64d 100644 --- a/src/lib/support/CHIPFaultInjection.h +++ b/src/lib/support/CHIPFaultInjection.h @@ -26,6 +26,11 @@ #include #if CHIP_WITH_NLFAULTINJECTION +#ifdef NDEBUG +// TODO(#30453): After fixing the issue where CHIP_WITH_NLFAULTINJECTION is seemingly enabled on release builds, +// uncomment the line below. +// static_assert(false, "CHIP_WITH_NLFAULTINJECTION should NOT be enabled on release build"); +#endif #include @@ -57,12 +62,25 @@ typedef enum kFault_BDXBadBlockCounter, /**< Corrupt the BDX Block Counter in the BDX BlockSend or BlockEOF message about to be sent */ kFault_BDXAllocTransfer, /**< Fail the allocation of a BDXTransfer object */ kFault_SecMgrBusy, /**< Trigger a WEAVE_ERROR_SECURITY_MANAGER_BUSY when starting an authentication session */ + kFault_IMInvoke_SeparateResponses, /**< Validate incoming InvokeRequestMessage contains exactly 2 valid commands and respond + with 2 InvokeResponseMessages */ + kFault_IMInvoke_SeparateResponsesInvertResponseOrder, /**< Validate incoming InvokeRequestMessage contains exactly 2 valid + commands and respond with 2 InvokeResponseMessages where the response order is inverted + compared to the request order */ + kFault_IMInvoke_SkipSecondResponse, /**< Validate incoming InvokeRequestMessage contains exactly 2 valid commands and respond + with 1 InvokeResponseMessage, dropping the response to the second request */ #if CONFIG_NETWORK_LAYER_BLE kFault_CHIPOBLESend, /**< Inject a GATT error when sending the first fragment of a chip message over BLE */ #endif // CONFIG_NETWORK_LAYER_BLE kFault_NumItems, } Id; +static_assert(kFault_IMInvoke_SeparateResponses == 12, "Test plan specification and automation code relies on this value being 12"); +static_assert(kFault_IMInvoke_SeparateResponsesInvertResponseOrder == 13, + "Test plan specification and automation code relies on this value being 13"); +static_assert(kFault_IMInvoke_SkipSecondResponse == 14, + "Test plan specification and automation code relies on this value being 14"); + DLL_EXPORT nl::FaultInjection::Manager & GetManager(); /** diff --git a/src/lib/support/JniReferences.cpp b/src/lib/support/JniReferences.cpp index 506ae0a82b7788..c75a0ef83f222f 100644 --- a/src/lib/support/JniReferences.cpp +++ b/src/lib/support/JniReferences.cpp @@ -168,7 +168,12 @@ CHIP_ERROR JniReferences::FindMethod(JNIEnv * env, jobject object, const char * *methodId = env->GetMethodID(javaClass, methodName, method_signature.data()); env->ExceptionClear(); - VerifyOrReturnError(*methodId != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); + if (*methodId == nullptr) + { + ChipLogError(Support, "methodId is null : %s, %s", methodName, methodSignature); + return CHIP_JNI_ERROR_METHOD_NOT_FOUND; + } + return CHIP_NO_ERROR; } diff --git a/src/app/ObjectList.h b/src/lib/support/LinkedList.h similarity index 90% rename from src/app/ObjectList.h rename to src/lib/support/LinkedList.h index 416db0bb70a6b5..d830c2b3a23351 100644 --- a/src/app/ObjectList.h +++ b/src/lib/support/LinkedList.h @@ -22,13 +22,13 @@ #include namespace chip { -namespace app { +/// A very basic single-linked list template -struct ObjectList +struct SingleLinkedListNode { T mValue; - ObjectList * mpNext = nullptr; + SingleLinkedListNode * mpNext = nullptr; size_t Count() const { @@ -41,5 +41,4 @@ struct ObjectList } }; -} // namespace app } // namespace chip diff --git a/src/lib/support/Pool.h b/src/lib/support/Pool.h index c2486f0c0e20b3..a3959fd1e868f9 100644 --- a/src/lib/support/Pool.h +++ b/src/lib/support/Pool.h @@ -104,18 +104,6 @@ class StaticAllocatorBitmap : public internal::StaticAllocatorBase std::atomic * mUsage; }; -template -class PoolCommon -{ -public: - template - void ResetObject(T * element, Args &&... args) - { - element->~T(); - new (element) T(std::forward(args)...); - } -}; - template class LambdaProxy { @@ -211,7 +199,7 @@ struct HeapObjectList : HeapObjectListNode * @tparam N a positive integer max number of elements the pool provides. */ template -class BitMapObjectPool : public internal::StaticAllocatorBitmap, public internal::PoolCommon +class BitMapObjectPool : public internal::StaticAllocatorBitmap { public: BitMapObjectPool() : StaticAllocatorBitmap(mData.mMemory, mUsage, N, sizeof(T)) {} @@ -314,7 +302,7 @@ class HeapObjectPoolExitHandling * @tparam T type to be allocated. */ template -class HeapObjectPool : public internal::Statistics, public internal::PoolCommon, public HeapObjectPoolExitHandling +class HeapObjectPool : public internal::Statistics, public HeapObjectPoolExitHandling { public: HeapObjectPool() {} diff --git a/src/lib/support/PoolWrapper.h b/src/lib/support/PoolWrapper.h index 78b6d838245633..fd9972429d9661 100644 --- a/src/lib/support/PoolWrapper.h +++ b/src/lib/support/PoolWrapper.h @@ -33,10 +33,9 @@ class PoolInterface virtual ~PoolInterface() {} - virtual U * CreateObject(ConstructorArguments... args) = 0; - virtual void ReleaseObject(U * element) = 0; - virtual void ReleaseAll() = 0; - virtual void ResetObject(U * element, ConstructorArguments... args) = 0; + virtual U * CreateObject(ConstructorArguments... args) = 0; + virtual void ReleaseObject(U * element) = 0; + virtual void ReleaseAll() = 0; template Loop ForEachActiveObject(Function && function) @@ -82,11 +81,6 @@ class PoolProxy> : public PoolIn void ReleaseAll() override { Impl().ReleaseAll(); } - void ResetObject(U * element, ConstructorArguments... args) override - { - return Impl().ResetObject(static_cast(element), std::move(args)...); - } - protected: Loop ForEachActiveObjectInner(void * context, typename PoolInterface::Lambda lambda) override { diff --git a/src/lib/support/static_support_smart_ptr.h b/src/lib/support/static_support_smart_ptr.h new file mode 100644 index 00000000000000..896073a9b15801 --- /dev/null +++ b/src/lib/support/static_support_smart_ptr.h @@ -0,0 +1,104 @@ +/* + * + * 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 { + +/// A template that is able to provide the global instance +/// for some application-specific class +/// +/// It works specifically together with CheckedGlobalInstanceReference +template +struct GlobalInstanceProvider +{ + static T * InstancePointer(); +}; + +/// A class that looks like a smart pointer (overrides operator->) +/// +/// However internally it only checks that the provided value is a given +/// Global instance. +/// +/// The global instance should be provided via GlobalInstanceProvider, for +/// example +/// +/// namespace chip { +/// template<> +/// Foo *GlobalInstanceProvider::InstancePointer() { +/// return Foo::Instance(); +/// } +/// } // namespace chip +/// +/// The CheckedGlobalInstanceReference will have minimal size (1 byte because +/// comparing instance pointers has to work) and does not require alignment, +/// as opposed to sizeof(void*) usage for SimpleInstanceReferences +/// +template +class CheckedGlobalInstanceReference +{ +public: + CheckedGlobalInstanceReference(T * e) { VerifyOrDie(e == GlobalInstanceProvider::InstancePointer()); } + CheckedGlobalInstanceReference & operator=(T * value) + { + VerifyOrDie(value == GlobalInstanceProvider::InstancePointer()); + return *this; + } + + inline T * operator->() { return GlobalInstanceProvider::InstancePointer(); } + inline const T * operator->() const { return GlobalInstanceProvider::InstancePointer(); } +}; + +/// A class that acts as a wrapper to a pointer and provides +/// operator-> overrides. +/// +/// It provides the same interface as CheckedGlobalInstanceReference +/// however it does NOT use a global value. +/// +/// The intended usage of these pair of classes is to compile-time decide +/// if global variables are to be used or if fully dynamic pointers are +/// allowed. +/// +/// Example: +/// #if USE_GLOBALS +/// template +/// using PointerContainer = chip::CheckedGlobalInstanceReference; +/// #else +/// template +/// using PointerContainer = chip::SimpleInstanceReference; +/// #endif +template +class SimpleInstanceReference +{ +public: + SimpleInstanceReference(T * e) : mValue(e) {} + SimpleInstanceReference & operator=(T * value) + { + mValue = value; + return *this; + } + + T * operator->() { return mValue; } + const T * operator->() const { return mValue; } + +private: + T * mValue; +}; + +} // namespace chip diff --git a/src/lib/support/tests/BUILD.gn b/src/lib/support/tests/BUILD.gn index d0b91feeba7061..deac3e2cbb1342 100644 --- a/src/lib/support/tests/BUILD.gn +++ b/src/lib/support/tests/BUILD.gn @@ -49,6 +49,7 @@ chip_test_suite_using_nltest("tests") { "TestSerializableIntegerSet.cpp", "TestSpan.cpp", "TestStateMachine.cpp", + "TestStaticSupportSmartPtr.cpp", "TestStringBuilder.cpp", "TestStringSplitter.cpp", "TestTestPersistentStorageDelegate.cpp", @@ -79,6 +80,7 @@ chip_test_suite_using_nltest("tests") { public_deps = [ "${chip_root}/src/credentials", "${chip_root}/src/lib/core", + "${chip_root}/src/lib/support:static-support", "${chip_root}/src/lib/support:testing", "${chip_root}/src/lib/support:testing_nlunit", "${chip_root}/src/lib/support/jsontlv", diff --git a/src/lib/support/tests/TestStaticSupportSmartPtr.cpp b/src/lib/support/tests/TestStaticSupportSmartPtr.cpp new file mode 100644 index 00000000000000..809c2e4887969c --- /dev/null +++ b/src/lib/support/tests/TestStaticSupportSmartPtr.cpp @@ -0,0 +1,127 @@ +/* + * + * 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 + +using namespace chip; +namespace { + +struct TestClass +{ + const char * str; + int num; + + TestClass(const char * s, int n) : str(s), num(n) {} +}; + +TestClass gTestClass("abc", 123); +} // namespace + +namespace chip { + +template <> +TestClass * GlobalInstanceProvider::InstancePointer() +{ + return &gTestClass; +} + +} // namespace chip + +namespace { + +void TestCheckedGlobalInstanceReference(nlTestSuite * inSuite, void * inContext) +{ + CheckedGlobalInstanceReference ref(&gTestClass); + + // We expect that sizes of global references is minimal + NL_TEST_ASSERT(inSuite, sizeof(ref) == 1); + + NL_TEST_ASSERT(inSuite, ref->num == 123); + NL_TEST_ASSERT(inSuite, strcmp(ref->str, "abc") == 0); + + { + ScopedChange change1(gTestClass.num, 100); + ScopedChange change2(ref->str, "xyz"); + + NL_TEST_ASSERT(inSuite, ref->num == 100); + NL_TEST_ASSERT(inSuite, strcmp(gTestClass.str, "xyz") == 0); + } + + CheckedGlobalInstanceReference ref2(&gTestClass); + + NL_TEST_ASSERT(inSuite, ref->num == ref2->num); + NL_TEST_ASSERT(inSuite, strcmp(ref->str, ref2->str) == 0); + + { + ScopedChange change1(gTestClass.num, 321); + ScopedChange change2(ref->str, "test"); + + NL_TEST_ASSERT(inSuite, ref->num == ref2->num); + NL_TEST_ASSERT(inSuite, strcmp(ref->str, ref2->str) == 0); + + NL_TEST_ASSERT(inSuite, ref2->num == 321); + NL_TEST_ASSERT(inSuite, strcmp(ref2->str, "test") == 0); + } +} + +void TestSimpleInstanceReference(nlTestSuite * inSuite, void * inContext) +{ + TestClass a("abc", 123); + TestClass b("xyz", 100); + + SimpleInstanceReference ref_a(&a); + SimpleInstanceReference ref_b(&b); + + // overhead of simple references should be a simple pointer + NL_TEST_ASSERT(inSuite, sizeof(ref_a) <= sizeof(void *)); + + NL_TEST_ASSERT(inSuite, ref_a->num == 123); + NL_TEST_ASSERT(inSuite, ref_b->num == 100); + + ref_a->num = 99; + b.num = 30; + + NL_TEST_ASSERT(inSuite, a.num == 99); + NL_TEST_ASSERT(inSuite, ref_b->num == 30); +} + +#define NL_TEST_DEF_FN(fn) NL_TEST_DEF("Test " #fn, fn) +const nlTest sTests[] = { + NL_TEST_DEF_FN(TestCheckedGlobalInstanceReference), + NL_TEST_DEF_FN(TestSimpleInstanceReference), + NL_TEST_SENTINEL(), +}; + +} // namespace + +int TestStaticSupportSmartPtr() +{ + nlTestSuite theSuite = { "CHIP Static support smart pointers", &sTests[0], nullptr, nullptr }; + + // Run test suite against one context. + nlTestRunner(&theSuite, nullptr); + return nlTestRunnerStats(&theSuite); +} + +CHIP_REGISTER_TEST_SUITE(TestStaticSupportSmartPtr) diff --git a/src/messaging/ReliableMessageProtocolConfig.cpp b/src/messaging/ReliableMessageProtocolConfig.cpp index 86c95b1ff07346..d1a4deece9c0f8 100644 --- a/src/messaging/ReliableMessageProtocolConfig.cpp +++ b/src/messaging/ReliableMessageProtocolConfig.cpp @@ -60,8 +60,8 @@ void ClearLocalMRPConfigOverride() ReliableMessageProtocolConfig GetDefaultMRPConfig() { - // Default MRP intervals are defined in spec <2.11.3. Parameters and Constants> - static constexpr const System::Clock::Milliseconds32 idleRetransTimeout = 300_ms32; + // Default MRP intervals are defined in spec <4.12.8. Parameters and Constants> + static constexpr const System::Clock::Milliseconds32 idleRetransTimeout = 500_ms32; static constexpr const System::Clock::Milliseconds32 activeRetransTimeout = 300_ms32; static constexpr const System::Clock::Milliseconds16 activeThresholdTime = 4000_ms16; return ReliableMessageProtocolConfig(idleRetransTimeout, activeRetransTimeout, activeThresholdTime); diff --git a/src/messaging/ReliableMessageProtocolConfig.h b/src/messaging/ReliableMessageProtocolConfig.h index a49740ad4d5227..87864d1a67e922 100644 --- a/src/messaging/ReliableMessageProtocolConfig.h +++ b/src/messaging/ReliableMessageProtocolConfig.h @@ -45,7 +45,7 @@ namespace chip { * timeout when it sends a message to the present node and the present node is * perceived by the peer as active. * - * This value is announced to the peer using SAI (Sleepy Active Interval) key + * This value is announced to the peer using SAI (Session Active Interval) key * in the advertised DNS Service Discovery TXT records. Additionally, it is * exchanged in the initial phase of the PASE/CASE session establishment. * @@ -84,7 +84,7 @@ namespace chip { #if CHIP_ENABLE_OPENTHREAD && !CHIP_DEVICE_LAYER_TARGET_LINUX #define CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL (800_ms32) #else -#define CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL (300_ms32) +#define CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL (500_ms32) #endif #endif // CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL && !CHIP_DEVICE_LAYER_TARGET_LINUX diff --git a/src/messaging/tests/MessagingContext.h b/src/messaging/tests/MessagingContext.h index a6a6d34fa1c36c..31143a727326be 100644 --- a/src/messaging/tests/MessagingContext.h +++ b/src/messaging/tests/MessagingContext.h @@ -78,7 +78,7 @@ class MessagingContext : public PlatformMemoryUser enum MRPMode { kDefault = 1, // This adopts the default MRP values for idle/active as per the spec. - // i.e IDLE = 4s, ACTIVE = 300ms + // i.e IDLE = 500ms, ACTIVE = 300ms kResponsive = 2, // This adopts values that are better suited for loopback tests that // don't actually go over a network interface, and are tuned much lower diff --git a/src/platform/DeviceControlServer.cpp b/src/platform/DeviceControlServer.cpp index 76008965498028..ec348669aec213 100644 --- a/src/platform/DeviceControlServer.cpp +++ b/src/platform/DeviceControlServer.cpp @@ -87,5 +87,12 @@ CHIP_ERROR DeviceControlServer::PostWiFiDeviceAvailableNetworkEvent() return PlatformMgr().PostEvent(&event); } +CHIP_ERROR DeviceControlServer::PostOperationalNetworkStartedEvent() +{ + ChipDeviceEvent event; + event.Type = DeviceEventType::kOperationalNetworkStarted; + return PlatformMgr().PostEvent(&event); +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/ESP32/ThreadStackManagerImpl.cpp b/src/platform/ESP32/ThreadStackManagerImpl.cpp index eed07af6d68af1..0449607999668b 100644 --- a/src/platform/ESP32/ThreadStackManagerImpl.cpp +++ b/src/platform/ESP32/ThreadStackManagerImpl.cpp @@ -77,6 +77,30 @@ void ThreadStackManagerImpl::_UnlockThreadStack() esp_openthread_lock_release(); } +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT +void ThreadStackManagerImpl::_WaitOnSrpClearAllComplete() +{ + // Only 1 task can be blocked on a srpClearAll request + if (mSrpClearAllRequester == nullptr) + { + mSrpClearAllRequester = xTaskGetCurrentTaskHandle(); + // Wait on OnSrpClientNotification which confirms the clearing is done. + // It will notify this current task with NotifySrpClearAllComplete. + // However, we won't wait more than 2s. + ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(2000)); + mSrpClearAllRequester = nullptr; + } +} + +void ThreadStackManagerImpl::_NotifySrpClearAllComplete() +{ + if (mSrpClearAllRequester) + { + xTaskNotifyGive(mSrpClearAllRequester); + } +} +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + void ThreadStackManagerImpl::_ProcessThreadActivity() { // Intentionally empty. diff --git a/src/platform/ESP32/ThreadStackManagerImpl.h b/src/platform/ESP32/ThreadStackManagerImpl.h index 46795d658d6535..1287e7a5f3a1ba 100644 --- a/src/platform/ESP32/ThreadStackManagerImpl.h +++ b/src/platform/ESP32/ThreadStackManagerImpl.h @@ -68,10 +68,21 @@ class ThreadStackManagerImpl final : public ThreadStackManager, void _OnCHIPoBLEAdvertisingStart(); void _OnCHIPoBLEAdvertisingStop(); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + void _WaitOnSrpClearAllComplete(); + void _NotifySrpClearAllComplete(); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + // ===== Methods that override the GenericThreadStackMa + private: friend ThreadStackManager & ::chip::DeviceLayer::ThreadStackMgr(void); friend ThreadStackManagerImpl & ::chip::DeviceLayer::ThreadStackMgrImpl(void); static ThreadStackManagerImpl sInstance; + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + TaskHandle_t mSrpClearAllRequester = nullptr; +#endif + ThreadStackManagerImpl() = default; }; diff --git a/src/platform/FreeRTOS/GenericThreadStackManagerImpl_FreeRTOS.h b/src/platform/FreeRTOS/GenericThreadStackManagerImpl_FreeRTOS.h index 870fcf2ed80657..059b701f6bda05 100644 --- a/src/platform/FreeRTOS/GenericThreadStackManagerImpl_FreeRTOS.h +++ b/src/platform/FreeRTOS/GenericThreadStackManagerImpl_FreeRTOS.h @@ -64,6 +64,10 @@ class GenericThreadStackManagerImpl_FreeRTOS bool _TryLockThreadStack(void); void _UnlockThreadStack(void); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + void _WaitOnSrpClearAllComplete(); + void _NotifySrpClearAllComplete(); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT // ===== Members available to the implementation subclass. SemaphoreHandle_t mThreadStackLock; @@ -88,6 +92,10 @@ class GenericThreadStackManagerImpl_FreeRTOS #if defined(CHIP_CONFIG_FREERTOS_USE_STATIC_SEMAPHORE) && CHIP_CONFIG_FREERTOS_USE_STATIC_SEMAPHORE StaticSemaphore_t mThreadStackLockMutex; #endif + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + TaskHandle_t mSrpClearAllRequester = nullptr; +#endif }; // Instruct the compiler to instantiate the template only when explicitly told to do so. diff --git a/src/platform/FreeRTOS/GenericThreadStackManagerImpl_FreeRTOS.hpp b/src/platform/FreeRTOS/GenericThreadStackManagerImpl_FreeRTOS.hpp index 4dbee81b23af01..9008258989375e 100644 --- a/src/platform/FreeRTOS/GenericThreadStackManagerImpl_FreeRTOS.hpp +++ b/src/platform/FreeRTOS/GenericThreadStackManagerImpl_FreeRTOS.hpp @@ -101,6 +101,32 @@ void GenericThreadStackManagerImpl_FreeRTOS::_UnlockThreadStack(void) xSemaphoreGive(mThreadStackLock); } +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT +template +void GenericThreadStackManagerImpl_FreeRTOS::_WaitOnSrpClearAllComplete() +{ + // Only 1 task can be blocked on a srpClearAll request + if (mSrpClearAllRequester == nullptr) + { + mSrpClearAllRequester = xTaskGetCurrentTaskHandle(); + // Wait on OnSrpClientNotification which confirms the slearing is done. + // It will notify this current task with NotifySrpClearAllComplete. + // However, we won't wait more than 2s. + ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(2000)); + mSrpClearAllRequester = nullptr; + } +} + +template +void GenericThreadStackManagerImpl_FreeRTOS::_NotifySrpClearAllComplete() +{ + if (mSrpClearAllRequester) + { + xTaskNotifyGive(mSrpClearAllRequester); + } +} +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + template void GenericThreadStackManagerImpl_FreeRTOS::SignalThreadActivityPending() { diff --git a/src/platform/Infineon/CYW30739/ThreadStackManagerImpl.cpp b/src/platform/Infineon/CYW30739/ThreadStackManagerImpl.cpp index f0393a795ef63a..21297d75cf5252 100644 --- a/src/platform/Infineon/CYW30739/ThreadStackManagerImpl.cpp +++ b/src/platform/Infineon/CYW30739/ThreadStackManagerImpl.cpp @@ -54,6 +54,14 @@ CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack() VerifyOrExit(result == WICED_SUCCESS, err = CHIP_ERROR_INTERNAL); otSysInit(0, NULL); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + mSrpClearAllSemaphore = wiced_rtos_create_mutex(); + VerifyOrExit(mSrpClearAllSemaphore != nullptr, err = CHIP_ERROR_NO_MEMORY); + + result = wiced_rtos_init_mutex(mSrpClearAllSemaphore); + VerifyOrExit(result == WICED_SUCCESS, err = CHIP_ERROR_INTERNAL); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + err = GenericThreadStackManagerImpl_OpenThread::DoInit(NULL); exit: @@ -95,6 +103,21 @@ void ThreadStackManagerImpl::_UnlockThreadStack() VerifyOrReturn(result == WICED_SUCCESS || result == WICED_NOT_OWNED, ChipLogError(DeviceLayer, "%s %x", __func__, result)); } +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT +void ThreadStackManagerImpl::_WaitOnSrpClearAllComplete() +{ + const wiced_result_t result = wiced_rtos_lock_mutex(mSrpClearAllSemaphore); + VerifyOrReturn(result == WICED_SUCCESS, ChipLogError(DeviceLayer, "%s %x", __func__, result)); +} + +void ThreadStackManagerImpl::_NotifySrpClearAllComplete() +{ + const wiced_result_t result = wiced_rtos_unlock_mutex(mSrpClearAllSemaphore); + VerifyOrReturn(result == WICED_SUCCESS || result == WICED_NOT_OWNED, ChipLogError(DeviceLayer, "%s %x", __func__, result)); +} +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT +// ===== Methods that override the GenericThreadStackMa + void ThreadStackManagerImpl::ThreadTaskMain(void) { while (true) diff --git a/src/platform/Infineon/CYW30739/ThreadStackManagerImpl.h b/src/platform/Infineon/CYW30739/ThreadStackManagerImpl.h index cdb2cb8ee65fdc..5cd3fef1c60239 100644 --- a/src/platform/Infineon/CYW30739/ThreadStackManagerImpl.h +++ b/src/platform/Infineon/CYW30739/ThreadStackManagerImpl.h @@ -58,6 +58,11 @@ class ThreadStackManagerImpl final : public ThreadStackManager, bool _TryLockThreadStack(); void _UnlockThreadStack(); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + void _WaitOnSrpClearAllComplete(); + void _NotifySrpClearAllComplete(); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + // ===== Methods that override the GenericThreadStackMa private: // ===== Members for internal use by the following friends. @@ -67,6 +72,9 @@ class ThreadStackManagerImpl final : public ThreadStackManager, wiced_thread_t * mThread; EventFlags mEventFlags; wiced_mutex_t * mMutex; +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + wiced_mutex_t * mSrpClearAllSemaphore; +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT static ThreadStackManagerImpl sInstance; // ===== Private members for use by this class only. diff --git a/src/platform/Linux/BLEManagerImpl.cpp b/src/platform/Linux/BLEManagerImpl.cpp index 83cd939dc05f0d..d5129a983f092d 100644 --- a/src/platform/Linux/BLEManagerImpl.cpp +++ b/src/platform/Linux/BLEManagerImpl.cpp @@ -43,6 +43,10 @@ #include "bluez/BluezEndpoint.h" +#if !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION +#include +#endif + using namespace ::nl; using namespace ::chip::Ble; @@ -650,8 +654,23 @@ void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) { ChipLogProgress(Ble, "Got notification regarding chip connection closure"); #if CHIP_DEVICE_CONFIG_ENABLE_WPA && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION - // In Non-Concurrent mode start the Wi-Fi, as BLE has been stopped - DeviceLayer::ConnectivityMgrImpl().StartNonConcurrentWiFiManagement(); + if (mState == kState_NotInitialized) + { + // Close BLE GATT connections to disconnect BlueZ + CloseConnection(conId); + // In Non-Concurrent mode start the Wi-Fi, as BLE has been stopped + DeviceLayer::ConnectivityMgrImpl().StartNonConcurrentWiFiManagement(); + } +#endif // CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION +} + +void BLEManagerImpl::CheckNonConcurrentBleClosing() +{ +#if CHIP_DEVICE_CONFIG_ENABLE_WPA && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION + if (mState == kState_Disconnecting) + { + DeviceLayer::DeviceControlServer::DeviceControlSvr().PostCloseAllBLEConnectionsToOperationalNetworkEvent(); + } #endif } diff --git a/src/platform/Linux/BLEManagerImpl.h b/src/platform/Linux/BLEManagerImpl.h index 1441f2e6573573..61d2dff02757c7 100644 --- a/src/platform/Linux/BLEManagerImpl.h +++ b/src/platform/Linux/BLEManagerImpl.h @@ -133,6 +133,7 @@ class BLEManagerImpl final : public BLEManager, // ===== Members that implement virtual methods on BleApplicationDelegate. void NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) override; + void CheckNonConcurrentBleClosing() override; // ===== Members that implement virtual methods on BleConnectionDelegate. diff --git a/src/platform/Linux/ConnectivityManagerImpl.cpp b/src/platform/Linux/ConnectivityManagerImpl.cpp index a2566d20f35560..eef7ce883f0042 100644 --- a/src/platform/Linux/ConnectivityManagerImpl.cpp +++ b/src/platform/Linux/ConnectivityManagerImpl.cpp @@ -98,15 +98,6 @@ namespace DeviceLayer { ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; -#if CHIP_DEVICE_CONFIG_ENABLE_WIFI -char ConnectivityManagerImpl::sWiFiIfName[]; -#endif - -WiFiDriver::ScanCallback * ConnectivityManagerImpl::mpScanCallback; -NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * ConnectivityManagerImpl::mpConnectCallback; -uint8_t ConnectivityManagerImpl::sInterestedSSID[Internal::kMaxWiFiSSIDLength]; -uint8_t ConnectivityManagerImpl::sInterestedSSIDLen; - CHIP_ERROR ConnectivityManagerImpl::_Init() { #if CHIP_DEVICE_CONFIG_ENABLE_WPA @@ -166,12 +157,6 @@ void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) #if CHIP_DEVICE_CONFIG_ENABLE_WPA -bool ConnectivityManagerImpl::mAssociationStarted = false; -BitFlags::ConnectivityFlags> - ConnectivityManagerImpl::mConnectivityFlag; -struct GDBusWpaSupplicant ConnectivityManagerImpl::mWpaSupplicant; -std::mutex ConnectivityManagerImpl::mWpaSupplicantMutex; - ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode() { if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled) @@ -313,7 +298,7 @@ CHIP_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val) ChipLogProgress(DeviceLayer, "WiFi AP mode change: %s -> %s", WiFiAPModeToStr(mWiFiAPMode), WiFiAPModeToStr(val)); mWiFiAPMode = val; - DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, nullptr); + DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveAPState(); }); } exit: @@ -326,7 +311,7 @@ void ConnectivityManagerImpl::_DemandStartWiFiAP() { ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand start WiFi AP"); mLastAPDemandTime = System::SystemClock().GetMonotonicTimestamp(); - DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, nullptr); + DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveAPState(); }); } else { @@ -340,7 +325,7 @@ void ConnectivityManagerImpl::_StopOnDemandWiFiAP() { ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand stop WiFi AP"); mLastAPDemandTime = System::Clock::kZero; - DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, nullptr); + DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveAPState(); }); } else { @@ -362,7 +347,7 @@ void ConnectivityManagerImpl::_MaintainOnDemandWiFiAP() void ConnectivityManagerImpl::_SetWiFiAPIdleTimeout(System::Clock::Timeout val) { mWiFiAPIdleTimeout = val; - DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, nullptr); + DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveAPState(); }); } void ConnectivityManagerImpl::UpdateNetworkStatus() @@ -391,12 +376,11 @@ void ConnectivityManagerImpl::UpdateNetworkStatus() MakeOptional(GetDisconnectReason())); } -void ConnectivityManagerImpl::_OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Interface * proxy, GVariant * changed_properties, - const gchar * const * invalidated_properties, gpointer user_data) +void ConnectivityManagerImpl::_OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Interface * proxy, GVariant * changedProperties) { std::lock_guard lock(mWpaSupplicantMutex); - if (g_variant_n_children(changed_properties) > 0) + if (g_variant_n_children(changedProperties) > 0) { GAutoPtr iter; const gchar * key; @@ -404,7 +388,7 @@ void ConnectivityManagerImpl::_OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Inte WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate(); - g_variant_get(changed_properties, "a{sv}", &MakeUniquePointerReceiver(iter).Get()); + g_variant_get(changedProperties, "a{sv}", &MakeUniquePointerReceiver(iter).Get()); while (g_variant_iter_loop(iter.get(), "{&sv}", &key, &value)) { @@ -424,6 +408,7 @@ void ConnectivityManagerImpl::_OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Inte if (delegate) { + chip::DeviceLayer::StackLock stackLock; delegate->OnDisconnectionDetected(reason); delegate->OnConnectionStatusChanged(static_cast(ConnectionStatusEnum::kConnected)); } @@ -453,7 +438,7 @@ void ConnectivityManagerImpl::_OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Inte break; } - DeviceLayer::SystemLayer().ScheduleLambda([reason]() { + DeviceLayer::SystemLayer().ScheduleLambda([this, reason]() { if (mpConnectCallback != nullptr) { mpConnectCallback->OnResult(NetworkCommissioning::Status::kUnknownError, CharSpan(), reason); @@ -463,6 +448,7 @@ void ConnectivityManagerImpl::_OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Inte if (delegate) { + chip::DeviceLayer::StackLock stackLock; delegate->OnAssociationFailureDetected(associationFailureCause, status); } } @@ -475,6 +461,7 @@ void ConnectivityManagerImpl::_OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Inte { if (delegate) { + chip::DeviceLayer::StackLock stackLock; delegate->OnConnectionStatusChanged(static_cast(ConnectionStatusEnum::kNotConnected)); } @@ -484,7 +471,7 @@ void ConnectivityManagerImpl::_OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Inte { if (mAssociationStarted) { - DeviceLayer::SystemLayer().ScheduleLambda([]() { + DeviceLayer::SystemLayer().ScheduleLambda([this]() { if (mpConnectCallback != nullptr) { mpConnectCallback->OnResult(NetworkCommissioning::Status::kSuccess, CharSpan(), 0); @@ -500,7 +487,7 @@ void ConnectivityManagerImpl::_OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Inte } } -void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data) +void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * sourceObject, GAsyncResult * res) { // When creating D-Bus proxy object, the thread default context must be initialized. Otherwise, // all D-Bus signals will be delivered to the GLib global default main context. @@ -525,8 +512,17 @@ void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * source_object, mWpaSupplicant.state = GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED; ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant interface proxy"); - g_signal_connect(mWpaSupplicant.iface, "properties-changed", G_CALLBACK(_OnWpaPropertiesChanged), NULL); - g_signal_connect(mWpaSupplicant.iface, "scan-done", G_CALLBACK(_OnWpaInterfaceScanDone), NULL); + g_signal_connect( + mWpaSupplicant.iface, "properties-changed", + G_CALLBACK(+[](WpaFiW1Wpa_supplicant1Interface * proxy, GVariant * properties, ConnectivityManagerImpl * self) { + return self->_OnWpaPropertiesChanged(proxy, properties); + }), + this); + g_signal_connect(mWpaSupplicant.iface, "scan-done", + G_CALLBACK(+[](WpaFiW1Wpa_supplicant1Interface * proxy, gboolean success, ConnectivityManagerImpl * self) { + return self->_OnWpaInterfaceScanDone(proxy, success); + }), + this); } else { @@ -537,7 +533,7 @@ void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * source_object, } // We need to stop auto scan or it will block our network scan. - DeviceLayer::SystemLayer().ScheduleLambda([]() { + DeviceLayer::SystemLayer().ScheduleLambda([this]() { CHIP_ERROR errInner = StopAutoScan(); if (errInner != CHIP_NO_ERROR) { @@ -546,7 +542,7 @@ void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * source_object, }); } -void ConnectivityManagerImpl::_OnWpaBssProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data) +void ConnectivityManagerImpl::_OnWpaBssProxyReady(GObject * sourceObject, GAsyncResult * res) { // When creating D-Bus proxy object, the thread default context must be initialized. Otherwise, // all D-Bus signals will be delivered to the GLib global default main context. @@ -577,7 +573,7 @@ void ConnectivityManagerImpl::_OnWpaBssProxyReady(GObject * source_object, GAsyn } } -void ConnectivityManagerImpl::_OnWpaInterfaceReady(GObject * source_object, GAsyncResult * res, gpointer user_data) +void ConnectivityManagerImpl::_OnWpaInterfaceReady(GObject * sourceObject, GAsyncResult * res) { // When creating D-Bus proxy object, the thread default context must be initialized. Otherwise, // all D-Bus signals will be delivered to the GLib global default main context. @@ -594,12 +590,21 @@ void ConnectivityManagerImpl::_OnWpaInterfaceReady(GObject * source_object, GAsy mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH; ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface: %s", mWpaSupplicant.interfacePath); - wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, - mWpaSupplicant.interfacePath, nullptr, _OnWpaInterfaceProxyReady, - nullptr); - - wpa_fi_w1_wpa_supplicant1_bss_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, - mWpaSupplicant.interfacePath, nullptr, _OnWpaBssProxyReady, nullptr); + wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus( + G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr, + reinterpret_cast( + +[](GObject * sourceObject_, GAsyncResult * res_, ConnectivityManagerImpl * self) { + return self->_OnWpaInterfaceProxyReady(sourceObject_, res_); + }), + this); + + wpa_fi_w1_wpa_supplicant1_bss_proxy_new_for_bus( + G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr, + reinterpret_cast( + +[](GObject * sourceObject_, GAsyncResult * res_, ConnectivityManagerImpl * self) { + return self->_OnWpaBssProxyReady(sourceObject_, res_); + }), + this); } else { @@ -626,12 +631,21 @@ void ConnectivityManagerImpl::_OnWpaInterfaceReady(GObject * source_object, GAsy Platform::CopyString(sWiFiIfName, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME); - wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, - kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr, - _OnWpaInterfaceProxyReady, nullptr); - - wpa_fi_w1_wpa_supplicant1_bss_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, - mWpaSupplicant.interfacePath, nullptr, _OnWpaBssProxyReady, nullptr); + wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus( + G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr, + reinterpret_cast( + +[](GObject * sourceObject_, GAsyncResult * res_, ConnectivityManagerImpl * self) { + return self->_OnWpaInterfaceProxyReady(sourceObject_, res_); + }), + this); + + wpa_fi_w1_wpa_supplicant1_bss_proxy_new_for_bus( + G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr, + reinterpret_cast( + +[](GObject * sourceObject_, GAsyncResult * res_, ConnectivityManagerImpl * self) { + return self->_OnWpaBssProxyReady(sourceObject_, res_); + }), + this); } else { @@ -649,8 +663,7 @@ void ConnectivityManagerImpl::_OnWpaInterfaceReady(GObject * source_object, GAsy } } -void ConnectivityManagerImpl::_OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties, - gpointer user_data) +void ConnectivityManagerImpl::_OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const char * path, GVariant * properties) { // When creating D-Bus proxy object, the thread default context must be initialized. Otherwise, // all D-Bus signals will be delivered to the GLib global default main context. @@ -669,17 +682,25 @@ void ConnectivityManagerImpl::_OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * prox mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH; ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface added: %s", mWpaSupplicant.interfacePath); - wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, - mWpaSupplicant.interfacePath, nullptr, _OnWpaInterfaceProxyReady, - nullptr); - - wpa_fi_w1_wpa_supplicant1_bss_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, - mWpaSupplicant.interfacePath, nullptr, _OnWpaBssProxyReady, nullptr); + wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus( + G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr, + reinterpret_cast( + +[](GObject * sourceObject_, GAsyncResult * res_, ConnectivityManagerImpl * self) { + return self->_OnWpaInterfaceProxyReady(sourceObject_, res_); + }), + this); + + wpa_fi_w1_wpa_supplicant1_bss_proxy_new_for_bus( + G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr, + reinterpret_cast( + +[](GObject * sourceObject_, GAsyncResult * res_, ConnectivityManagerImpl * self) { + return self->_OnWpaBssProxyReady(sourceObject_, res_); + }), + this); } } -void ConnectivityManagerImpl::_OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties, - gpointer user_data) +void ConnectivityManagerImpl::_OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const char * path, GVariant * properties) { std::lock_guard lock(mWpaSupplicantMutex); @@ -716,7 +737,7 @@ void ConnectivityManagerImpl::_OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * pr } } -void ConnectivityManagerImpl::_OnWpaProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data) +void ConnectivityManagerImpl::_OnWpaProxyReady(GObject * sourceObject, GAsyncResult * res) { // When creating D-Bus proxy object, the thread default context must be initialized. Otherwise, // all D-Bus signals will be delivered to the GLib global default main context. @@ -732,11 +753,24 @@ void ConnectivityManagerImpl::_OnWpaProxyReady(GObject * source_object, GAsyncRe mWpaSupplicant.state = GDBusWpaSupplicant::WPA_CONNECTED; ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant proxy"); - g_signal_connect(mWpaSupplicant.proxy, "interface-added", G_CALLBACK(_OnWpaInterfaceAdded), NULL); - - g_signal_connect(mWpaSupplicant.proxy, "interface-removed", G_CALLBACK(_OnWpaInterfaceRemoved), NULL); - - wpa_fi_w1_wpa_supplicant1_call_get_interface(mWpaSupplicant.proxy, sWiFiIfName, nullptr, _OnWpaInterfaceReady, nullptr); + g_signal_connect( + mWpaSupplicant.proxy, "interface-added", + G_CALLBACK(+[](WpaFiW1Wpa_supplicant1 * proxy, const char * path, GVariant * properties, + ConnectivityManagerImpl * self) { return self->_OnWpaInterfaceAdded(proxy, path, properties); }), + this); + g_signal_connect( + mWpaSupplicant.proxy, "interface-removed", + G_CALLBACK(+[](WpaFiW1Wpa_supplicant1 * proxy, const char * path, GVariant * properties, + ConnectivityManagerImpl * self) { return self->_OnWpaInterfaceRemoved(proxy, path, properties); }), + this); + + wpa_fi_w1_wpa_supplicant1_call_get_interface( + mWpaSupplicant.proxy, sWiFiIfName, nullptr, + reinterpret_cast( + +[](GObject * sourceObject_, GAsyncResult * res_, ConnectivityManagerImpl * self) { + return self->_OnWpaInterfaceReady(sourceObject_, res_); + }), + this); } else { @@ -753,7 +787,8 @@ void ConnectivityManagerImpl::StartWiFiManagement() mConnectivityFlag.ClearAll(); mWpaSupplicant = GDBusWpaSupplicant{}; - CHIP_ERROR err = PlatformMgrImpl().GLibMatterContextInvokeSync(_StartWiFiManagement, this); + CHIP_ERROR err = PlatformMgrImpl().GLibMatterContextInvokeSync( + +[](ConnectivityManagerImpl * self) { return self->_StartWiFiManagement(); }, this); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "Failed to start WiFi management")); } @@ -774,7 +809,7 @@ void ConnectivityManagerImpl::StartNonConcurrentWiFiManagement() { if (IsWiFiManagementStarted()) { - DeviceControlServer::DeviceControlSvr().PostWiFiDeviceAvailableNetworkEvent(); + DeviceControlServer::DeviceControlSvr().PostOperationalNetworkStartedEvent(); ChipLogProgress(DeviceLayer, "Non-concurrent mode Wi-Fi Management Started."); return; } @@ -829,7 +864,7 @@ void ConnectivityManagerImpl::DriveAPState() // Compute the amount of idle time before the AP should be deactivated and // arm a timer to fire at that time. System::Clock::Timeout apTimeout = (mLastAPDemandTime + mWiFiAPIdleTimeout) - now; - err = DeviceLayer::SystemLayer().StartTimer(apTimeout, DriveAPState, nullptr); + err = DeviceLayer::SystemLayer().StartTimer(apTimeout, DriveAPState, this); SuccessOrExit(err); ChipLogProgress(DeviceLayer, "Next WiFi AP timeout in %" PRIu32 " s", std::chrono::duration_cast(apTimeout).count()); @@ -916,7 +951,7 @@ CHIP_ERROR ConnectivityManagerImpl::ConfigureWiFiAP() // Clean up current network if exists if (mWpaSupplicant.networkPath) { - g_object_unref(mWpaSupplicant.networkPath); + g_free(mWpaSupplicant.networkPath); mWpaSupplicant.networkPath = nullptr; } @@ -956,7 +991,7 @@ CHIP_ERROR ConnectivityManagerImpl::ConfigureWiFiAP() if (mWpaSupplicant.networkPath) { - g_object_unref(mWpaSupplicant.networkPath); + g_free(mWpaSupplicant.networkPath); mWpaSupplicant.networkPath = nullptr; } @@ -977,7 +1012,7 @@ void ConnectivityManagerImpl::ChangeWiFiAPState(WiFiAPState newState) void ConnectivityManagerImpl::DriveAPState(::chip::System::Layer * aLayer, void * aAppState) { - sInstance.DriveAPState(); + reinterpret_cast(aAppState)->DriveAPState(); } CHIP_ERROR @@ -1030,8 +1065,14 @@ ConnectivityManagerImpl::_ConnectWiFiNetworkAsync(GVariant * args, wpa_fi_w1_wpa_supplicant1_interface_call_disconnect_sync(mWpaSupplicant.iface, nullptr, nullptr); ChipLogProgress(DeviceLayer, "wpa_supplicant: added network: %s", mWpaSupplicant.networkPath); - wpa_fi_w1_wpa_supplicant1_interface_call_select_network(mWpaSupplicant.iface, mWpaSupplicant.networkPath, nullptr, - _ConnectWiFiNetworkAsyncCallback, this); + wpa_fi_w1_wpa_supplicant1_interface_call_select_network( + mWpaSupplicant.iface, mWpaSupplicant.networkPath, nullptr, + reinterpret_cast( + +[](GObject * sourceObject_, GAsyncResult * res_, ConnectivityManagerImpl * self) { + return self->_ConnectWiFiNetworkAsyncCallback(sourceObject_, res_); + }), + this); + mpConnectCallback = apCallback; } else @@ -1040,7 +1081,7 @@ ConnectivityManagerImpl::_ConnectWiFiNetworkAsync(GVariant * args, if (mWpaSupplicant.networkPath) { - g_object_unref(mWpaSupplicant.networkPath); + g_free(mWpaSupplicant.networkPath); mWpaSupplicant.networkPath = nullptr; } @@ -1191,9 +1232,8 @@ CHIP_ERROR ConnectivityManagerImpl::ConnectWiFiNetworkWithPDCAsync( } #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI_PDC -void ConnectivityManagerImpl::_ConnectWiFiNetworkAsyncCallback(GObject * source_object, GAsyncResult * res, gpointer user_data) +void ConnectivityManagerImpl::_ConnectWiFiNetworkAsyncCallback(GObject * sourceObject, GAsyncResult * res) { - ConnectivityManagerImpl * this_ = reinterpret_cast(user_data); GAutoPtr err; std::lock_guard lock(mWpaSupplicantMutex); @@ -1204,12 +1244,12 @@ void ConnectivityManagerImpl::_ConnectWiFiNetworkAsyncCallback(GObject * source_ if (!result) { ChipLogError(DeviceLayer, "Failed to perform connect network: %s", err == nullptr ? "unknown error" : err->message); - DeviceLayer::SystemLayer().ScheduleLambda([this_]() { + DeviceLayer::SystemLayer().ScheduleLambda([this]() { if (mpConnectCallback != nullptr) { // TODO(#14175): Replace this with actual thread attach result. - this_->mpConnectCallback->OnResult(NetworkCommissioning::Status::kUnknownError, CharSpan(), 0); - this_->mpConnectCallback = nullptr; + mpConnectCallback->OnResult(NetworkCommissioning::Status::kUnknownError, CharSpan(), 0); + mpConnectCallback = nullptr; } mpConnectCallback = nullptr; }); @@ -1796,7 +1836,7 @@ bool ConnectivityManagerImpl::_GetBssInfo(const gchar * bssPath, NetworkCommissi return true; } -void ConnectivityManagerImpl::_OnWpaInterfaceScanDone(GObject * source_object, GAsyncResult * res, gpointer user_data) +void ConnectivityManagerImpl::_OnWpaInterfaceScanDone(WpaFiW1Wpa_supplicant1Interface * proxy, gboolean success) { std::lock_guard lock(mWpaSupplicantMutex); @@ -1806,7 +1846,7 @@ void ConnectivityManagerImpl::_OnWpaInterfaceScanDone(GObject * source_object, G if (bsss == nullptr) { ChipLogProgress(DeviceLayer, "wpa_supplicant: no network found"); - DeviceLayer::SystemLayer().ScheduleLambda([]() { + DeviceLayer::SystemLayer().ScheduleLambda([this]() { if (mpScanCallback != nullptr) { mpScanCallback->OnFinished(Status::kSuccess, CharSpan(), nullptr); @@ -1833,7 +1873,7 @@ void ConnectivityManagerImpl::_OnWpaInterfaceScanDone(GObject * source_object, G } } - DeviceLayer::SystemLayer().ScheduleLambda([networkScanned]() { + DeviceLayer::SystemLayer().ScheduleLambda([this, networkScanned]() { // Note: We cannot post a event in ScheduleLambda since std::vector is not trivial copiable. This results in the use of // const_cast but should be fine for almost all cases, since we actually handled the ownership of this element to this // lambda. @@ -1850,15 +1890,19 @@ void ConnectivityManagerImpl::_OnWpaInterfaceScanDone(GObject * source_object, G g_strfreev(oldBsss); } -CHIP_ERROR ConnectivityManagerImpl::_StartWiFiManagement(ConnectivityManagerImpl * self) +CHIP_ERROR ConnectivityManagerImpl::_StartWiFiManagement() { // When creating D-Bus proxy object, the thread default context must be initialized. Otherwise, // all D-Bus signals will be delivered to the GLib global default main context. VerifyOrDie(g_main_context_get_thread_default() != nullptr); ChipLogProgress(DeviceLayer, "wpa_supplicant: Start WiFi management"); - wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, - kWpaSupplicantObjectPath, nullptr, self->_OnWpaProxyReady, nullptr); + wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus( + G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, kWpaSupplicantObjectPath, nullptr, + reinterpret_cast(+[](GObject * sourceObject_, GAsyncResult * res_, ConnectivityManagerImpl * self) { + return self->_OnWpaProxyReady(sourceObject_, res_); + }), + this); return CHIP_NO_ERROR; } diff --git a/src/platform/Linux/ConnectivityManagerImpl.h b/src/platform/Linux/ConnectivityManagerImpl.h index 930b84fb4d455b..26d6172ad438eb 100644 --- a/src/platform/Linux/ConnectivityManagerImpl.h +++ b/src/platform/Linux/ConnectivityManagerImpl.h @@ -155,14 +155,14 @@ class ConnectivityManagerImpl final : public ConnectivityManager, CHIP_ERROR _ConnectWiFiNetworkAsync(GVariant * networkArgs, NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * connectCallback) CHIP_REQUIRES(mWpaSupplicantMutex); - static void _ConnectWiFiNetworkAsyncCallback(GObject * source_object, GAsyncResult * res, gpointer user_data); + void _ConnectWiFiNetworkAsyncCallback(GObject * sourceObject, GAsyncResult * res); #endif public: const char * GetEthernetIfName() { return (mEthIfName[0] == '\0') ? nullptr : mEthIfName; } #if CHIP_DEVICE_CONFIG_ENABLE_WIFI - static const char * GetWiFiIfName() { return (sWiFiIfName[0] == '\0') ? nullptr : sWiFiIfName; } + const char * GetWiFiIfName() { return (sWiFiIfName[0] == '\0') ? nullptr : sWiFiIfName; } #endif private: @@ -205,29 +205,27 @@ class ConnectivityManagerImpl final : public ConnectivityManager, System::Clock::Timeout _GetWiFiAPIdleTimeout(); void _SetWiFiAPIdleTimeout(System::Clock::Timeout val); void UpdateNetworkStatus(); - static CHIP_ERROR StopAutoScan(); - - static void _OnWpaProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data); - static void _OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties, - gpointer user_data); - static void _OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties, gpointer user_data); - static void _OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Interface * proxy, GVariant * changed_properties, - const gchar * const * invalidated_properties, gpointer user_data); - static void _OnWpaInterfaceReady(GObject * source_object, GAsyncResult * res, gpointer user_data); - static void _OnWpaInterfaceProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data); - static void _OnWpaBssProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data); - static void _OnWpaInterfaceScanDone(GObject * source_object, GAsyncResult * res, gpointer user_data); - - static bool _GetBssInfo(const gchar * bssPath, NetworkCommissioning::WiFiScanResponse & result); - - static CHIP_ERROR _StartWiFiManagement(ConnectivityManagerImpl * self); - - static bool mAssociationStarted; - static BitFlags mConnectivityFlag; - static GDBusWpaSupplicant mWpaSupplicant CHIP_GUARDED_BY(mWpaSupplicantMutex); + CHIP_ERROR StopAutoScan(); + + void _OnWpaProxyReady(GObject * sourceObject, GAsyncResult * res); + void _OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const char * path, GVariant * properties); + void _OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const char * path, GVariant * properties); + void _OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Interface * proxy, GVariant * properties); + void _OnWpaInterfaceScanDone(WpaFiW1Wpa_supplicant1Interface * proxy, gboolean success); + void _OnWpaInterfaceReady(GObject * sourceObject, GAsyncResult * res); + void _OnWpaInterfaceProxyReady(GObject * sourceObject, GAsyncResult * res); + void _OnWpaBssProxyReady(GObject * sourceObject, GAsyncResult * res); + + bool _GetBssInfo(const gchar * bssPath, NetworkCommissioning::WiFiScanResponse & result); + + CHIP_ERROR _StartWiFiManagement(); + + bool mAssociationStarted = false; + BitFlags mConnectivityFlag; + GDBusWpaSupplicant mWpaSupplicant CHIP_GUARDED_BY(mWpaSupplicantMutex); // Access to mWpaSupplicant has to be protected by a mutex because it is accessed from // the CHIP event loop thread and dedicated D-Bus thread started by platform manager. - static std::mutex mWpaSupplicantMutex; + std::mutex mWpaSupplicantMutex; NetworkCommissioning::Internal::BaseDriver::NetworkStatusChangeCallback * mpStatusChangeCallback = nullptr; #endif @@ -262,13 +260,15 @@ class ConnectivityManagerImpl final : public ConnectivityManager, #endif #if CHIP_DEVICE_CONFIG_ENABLE_WIFI - static char sWiFiIfName[IFNAMSIZ]; + char sWiFiIfName[IFNAMSIZ]; #endif - static uint8_t sInterestedSSID[Internal::kMaxWiFiSSIDLength]; - static uint8_t sInterestedSSIDLen; - static NetworkCommissioning::WiFiDriver::ScanCallback * mpScanCallback; - static NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * mpConnectCallback; +#if CHIP_DEVICE_CONFIG_ENABLE_WPA + uint8_t sInterestedSSID[Internal::kMaxWiFiSSIDLength]; + uint8_t sInterestedSSIDLen; +#endif + NetworkCommissioning::WiFiDriver::ScanCallback * mpScanCallback; + NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * mpConnectCallback; }; #if CHIP_DEVICE_CONFIG_ENABLE_WPA diff --git a/src/platform/Linux/PlatformManagerImpl.cpp b/src/platform/Linux/PlatformManagerImpl.cpp index 0098eb01ae96eb..401d72bbe413bd 100644 --- a/src/platform/Linux/PlatformManagerImpl.cpp +++ b/src/platform/Linux/PlatformManagerImpl.cpp @@ -108,13 +108,13 @@ gboolean WiFiIPChangeListener(GIOChannel * ch, GIOCondition /* condition */, voi continue; } - if (ConnectivityManagerImpl::GetWiFiIfName() == nullptr) + if (ConnectivityMgrImpl().GetWiFiIfName() == nullptr) { ChipLogDetail(DeviceLayer, "No wifi interface name. Ignoring IP update event."); continue; } - if (strcmp(name, ConnectivityManagerImpl::GetWiFiIfName()) != 0) + if (strcmp(name, ConnectivityMgrImpl().GetWiFiIfName()) != 0) { continue; } diff --git a/src/platform/Linux/ThreadStackManagerImpl.h b/src/platform/Linux/ThreadStackManagerImpl.h index 977c6b94d0027f..e262837dd84c76 100755 --- a/src/platform/Linux/ThreadStackManagerImpl.h +++ b/src/platform/Linux/ThreadStackManagerImpl.h @@ -57,6 +57,11 @@ class ThreadStackManagerImpl : public ThreadStackManager bool _TryLockThreadStack() { return false; } // Intentionally left blank void _UnlockThreadStack() {} // Intentionally left blank +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + void _WaitOnSrpClearAllComplete() {} + void _NotifySrpClearAllComplete() {} +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + bool _HaveRouteToAddress(const Inet::IPAddress & destAddr); void _OnPlatformEvent(const ChipDeviceEvent * event); diff --git a/src/platform/Linux/bluez/BluezAdvertisement.cpp b/src/platform/Linux/bluez/BluezAdvertisement.cpp index db74da8bec1ec4..1b95aae41a4f11 100644 --- a/src/platform/Linux/bluez/BluezAdvertisement.cpp +++ b/src/platform/Linux/bluez/BluezAdvertisement.cpp @@ -65,7 +65,7 @@ BluezLEAdvertisement1 * BluezAdvertisement::CreateLEAdvertisement() // Bluez to set "BR/EDR Not Supported" flag. Bluez doesn't provide API to do that explicitly // and the flag is necessary to force using LE transport. bluez_leadvertisement1_set_discoverable(adv, TRUE); - bluez_leadvertisement1_set_discoverable_timeout(adv, 0 /* infinite */); + // empty discoverable timeout for infinite discoverability // empty includes bluez_leadvertisement1_set_local_name(adv, mAdvName); diff --git a/src/platform/Linux/dbus/bluez/DbusBluez.xml b/src/platform/Linux/dbus/bluez/DbusBluez.xml index 00887dc5e147a9..0a42da708d50a9 100644 --- a/src/platform/Linux/dbus/bluez/DbusBluez.xml +++ b/src/platform/Linux/dbus/bluez/DbusBluez.xml @@ -108,6 +108,10 @@ + @@ -115,6 +119,10 @@ + @@ -152,6 +160,10 @@ + @@ -172,6 +184,10 @@ + @@ -183,13 +199,33 @@ + - - - + + + diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h index 161c2b202a8310..8ce0805182dcaa 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h @@ -121,6 +121,7 @@ class GenericThreadStackManagerImpl_OpenThread CHIP_ERROR _RemoveSrpService(const char * aInstanceName, const char * aName); CHIP_ERROR _InvalidateAllSrpServices(); CHIP_ERROR _RemoveInvalidSrpServices(); + CHIP_ERROR _ClearAllSrpHostAndServices(); CHIP_ERROR _SetupSrpHost(const char * aHostName); CHIP_ERROR _ClearSrpHost(const char * aHostName); @@ -203,6 +204,8 @@ class GenericThreadStackManagerImpl_OpenThread SrpClient mSrpClient; + bool mIsSrpClearAllRequested = false; + static void OnSrpClientNotification(otError aError, const otSrpClientHostInfo * aHostInfo, const otSrpClientService * aServices, const otSrpClientService * aRemovedServices, void * aContext); static void OnSrpClientStateChange(const otSockAddr * aServerSockAddr, void * aContext); diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp index acc0c78d0c8eb7..21c44dd00279e3 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp @@ -1307,6 +1307,12 @@ void GenericThreadStackManagerImpl_OpenThread::OnSrpClientNotificatio ThreadStackMgrImpl().mSrpClient.mIsInitialized = true; ThreadStackMgrImpl().mSrpClient.mInitializedCallback(ThreadStackMgrImpl().mSrpClient.mCallbackContext, CHIP_NO_ERROR); + + if (ThreadStackMgrImpl().mIsSrpClearAllRequested) + { + ThreadStackMgrImpl().NotifySrpClearAllComplete(); + ThreadStackMgrImpl().mIsSrpClearAllRequested = false; + } } } @@ -1618,6 +1624,35 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_RemoveInvalidSr return error; } +/* + * @brief This is a utility function to remove all Thread client srp host and services + * established between the device and the srp server (in most cases the OTBR). + * The calling task is blocked until OnSrpClientNotification which confims the client received the request. + * The blocking mechanism is defined by the platform implementation of `WaitOnSrpClearAllComplete` and `NotifySrpClearAllComplete` + * + * Note: This function is meant to be used during the factory reset sequence. + * + */ +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_ClearAllSrpHostAndServices() +{ + CHIP_ERROR error = CHIP_NO_ERROR; + Impl()->LockThreadStack(); + if (!mIsSrpClearAllRequested) + { + error = + MapOpenThreadError(otSrpClientRemoveHostAndServices(mOTInst, true /*aRemoveKeyLease*/, true /*aSendUnregToServer*/)); + mIsSrpClearAllRequested = true; + Impl()->UnlockThreadStack(); + Impl()->WaitOnSrpClearAllComplete(); + } + else + { + Impl()->UnlockThreadStack(); + } + return error; +} + template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetupSrpHost(const char * aHostName) { diff --git a/src/platform/Tizen/ThreadStackManagerImpl.cpp b/src/platform/Tizen/ThreadStackManagerImpl.cpp index 47a4548507e332..e6252d92926190 100644 --- a/src/platform/Tizen/ThreadStackManagerImpl.cpp +++ b/src/platform/Tizen/ThreadStackManagerImpl.cpp @@ -646,6 +646,16 @@ CHIP_ERROR ThreadStackManagerImpl::_RemoveInvalidSrpServices() return CHIP_NO_ERROR; } +CHIP_ERROR ThreadStackManagerImpl::_ClearAllSrpHostAndServices() +{ + for (auto it = mSrpClientServices.begin(); it != mSrpClientServices.end();) + { + ReturnErrorOnFailure(_RemoveSrpService(it->mInstanceName, it->mName)); + it = mSrpClientServices.erase(it); + } + return CHIP_NO_ERROR; +} + void ThreadStackManagerImpl::_ThreadIpAddressCb(int index, char * ipAddr, thread_ipaddr_type_e ipAddrType, void * userData) { VerifyOrReturn(ipAddr != nullptr, ChipLogError(DeviceLayer, "FAIL: Invalid argument: Thread ipAddr not found")); diff --git a/src/platform/Tizen/ThreadStackManagerImpl.h b/src/platform/Tizen/ThreadStackManagerImpl.h index 05b300f574114b..07092f43b320eb 100644 --- a/src/platform/Tizen/ThreadStackManagerImpl.h +++ b/src/platform/Tizen/ThreadStackManagerImpl.h @@ -57,6 +57,11 @@ class ThreadStackManagerImpl : public ThreadStackManager bool _TryLockThreadStack() { return false; } // Intentionally left blank void _UnlockThreadStack() {} // Intentionally left blank +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + void _WaitOnSrpClearAllComplete() {} + void _NotifySrpClearAllComplete() {} +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + bool _HaveRouteToAddress(const Inet::IPAddress & destAddr); void _OnPlatformEvent(const ChipDeviceEvent * event); @@ -115,6 +120,7 @@ class ThreadStackManagerImpl : public ThreadStackManager CHIP_ERROR _RemoveSrpService(const char * aInstanceName, const char * aName); CHIP_ERROR _InvalidateAllSrpServices(); CHIP_ERROR _RemoveInvalidSrpServices(); + CHIP_ERROR _ClearAllSrpHostAndServices(); CHIP_ERROR _SetupSrpHost(const char * aHostName); CHIP_ERROR _ClearSrpHost(const char * aHostName); CHIP_ERROR _SetSrpDnsCallbacks(DnsAsyncReturnCallback aInitCallback, DnsAsyncReturnCallback aErrorCallback, void * aContext); diff --git a/src/platform/Zephyr/ThreadStackManagerImpl.cpp b/src/platform/Zephyr/ThreadStackManagerImpl.cpp index 3cfcfe3b7888b2..95bdfc8ea7044a 100644 --- a/src/platform/Zephyr/ThreadStackManagerImpl.cpp +++ b/src/platform/Zephyr/ThreadStackManagerImpl.cpp @@ -66,6 +66,10 @@ CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack() return MapOpenThreadError(otError); }); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + k_sem_init(&mSrpClearAllSemaphore, 0, 1); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + return CHIP_NO_ERROR; } @@ -85,5 +89,17 @@ void ThreadStackManagerImpl::_UnlockThreadStack() openthread_api_mutex_unlock(openthread_get_default_context()); } +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT +void ThreadStackManagerImpl::_WaitOnSrpClearAllComplete() +{ + k_sem_take(&mSrpClearAllSemaphore, K_SECONDS(2)); +} + +void ThreadStackManagerImpl::_NotifySrpClearAllComplete() +{ + k_sem_give(&mSrpClearAllSemaphore); +} +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/Zephyr/ThreadStackManagerImpl.h b/src/platform/Zephyr/ThreadStackManagerImpl.h index c0c66b492c6b1d..ec9feb8b121d3e 100644 --- a/src/platform/Zephyr/ThreadStackManagerImpl.h +++ b/src/platform/Zephyr/ThreadStackManagerImpl.h @@ -71,6 +71,10 @@ class ThreadStackManagerImpl final : public ThreadStackManager, bool _TryLockThreadStack(); void _UnlockThreadStack(); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + void _WaitOnSrpClearAllComplete(); + void _NotifySrpClearAllComplete(); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT // ===== Methods that override the GenericThreadStackManagerImpl_OpenThread abstract interface. void _ProcessThreadActivity() {} @@ -83,6 +87,10 @@ class ThreadStackManagerImpl final : public ThreadStackManager, friend ThreadStackManager & ::chip::DeviceLayer::ThreadStackMgr(void); friend ThreadStackManagerImpl & ::chip::DeviceLayer::ThreadStackMgrImpl(void); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + k_sem mSrpClearAllSemaphore; +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + static ThreadStackManagerImpl sInstance; // ===== Private members for use by this class only. diff --git a/src/platform/cc13xx_26xx/cc13x4_26x4/crypto/aes_alt.c b/src/platform/cc13xx_26xx/cc13x4_26x4/crypto/aes_alt.c index b6b790489a9916..91e9004dffdbac 100644 --- a/src/platform/cc13xx_26xx/cc13x4_26x4/crypto/aes_alt.c +++ b/src/platform/cc13xx_26xx/cc13x4_26x4/crypto/aes_alt.c @@ -26,6 +26,7 @@ #include #include +#include /* * number of active contexts, used for power on/off of the crypto core @@ -111,8 +112,11 @@ int mbedtls_aes_setkey_dec(mbedtls_aes_context * ctx, const unsigned char * key, int mbedtls_aes_crypt_ecb(mbedtls_aes_context * ctx, int mode, const unsigned char input[16], unsigned char output[16]) { int statusCrypto; + uint32_t key; AESECB_Operation operationOneStepEncrypt; + key = HwiP_disable(); + /* run it through the authentication + encryption, pass the ccmLVal = 2 */ AESECB_Operation_init(&operationOneStepEncrypt); @@ -125,9 +129,10 @@ int mbedtls_aes_crypt_ecb(mbedtls_aes_context * ctx, int mode, const unsigned ch if (CryptoKey_STATUS_SUCCESS != statusCrypto) { + HwiP_restore(key); return MBEDTLS_ERR_AES_HW_ACCEL_FAILED; } - + HwiP_restore(key); return 0; } #endif diff --git a/src/platform/cc13xx_26xx/cc13x4_26x4/crypto/cc13x4_26x4-mbedtls-config.h b/src/platform/cc13xx_26xx/cc13x4_26x4/crypto/cc13x4_26x4-mbedtls-config.h index 2ac87444764fd6..ce09760f8bf3dc 100644 --- a/src/platform/cc13xx_26xx/cc13x4_26x4/crypto/cc13x4_26x4-mbedtls-config.h +++ b/src/platform/cc13xx_26xx/cc13x4_26x4/crypto/cc13x4_26x4-mbedtls-config.h @@ -38,7 +38,7 @@ /* Enable Hardware Acceleration */ -// #define MBEDTLS_AES_ALT +#define MBEDTLS_AES_ALT // #define MBEDTLS_ECDH_COMPUTE_SHARED_ALT // #define MBEDTLS_ECDH_GEN_PUBLIC_ALT #define MBEDTLS_ECDSA_SIGN_ALT diff --git a/src/platform/silabs/ConfigurationManagerImpl.cpp b/src/platform/silabs/ConfigurationManagerImpl.cpp index a3e1778c11ac3f..8412075de3a914 100644 --- a/src/platform/silabs/ConfigurationManagerImpl.cpp +++ b/src/platform/silabs/ConfigurationManagerImpl.cpp @@ -272,7 +272,7 @@ void ConfigurationManagerImpl::DoFactoryReset(intptr_t arg) #if CHIP_DEVICE_CONFIG_ENABLE_THREAD #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT - ThreadStackMgrImpl().RemoveAllSrpServices(); + ThreadStackMgr().ClearAllSrpHostAndServices(); #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT ChipLogProgress(DeviceLayer, "Clearing Thread provision"); ThreadStackMgr().ErasePersistentInfo(); diff --git a/src/platform/silabs/SilabsConfig.cpp b/src/platform/silabs/SilabsConfig.cpp index d15fef86b7985c..f98ced75a3e1d8 100644 --- a/src/platform/silabs/SilabsConfig.cpp +++ b/src/platform/silabs/SilabsConfig.cpp @@ -33,6 +33,7 @@ #include #include +#ifndef SIWX_917 // 917soc/wifi-sdk implements the same nvm3 lock/unlock mechanism and it currently can't be overide. #include #include // Substitute the GSDK weak nvm3_lockBegin and nvm3_lockEnd @@ -57,6 +58,7 @@ void nvm3_lockEnd(void) VerifyOrDie(nvm3_Sem != NULL); xSemaphoreGive(nvm3_Sem); } +#endif // !SIWX_917 namespace chip { namespace DeviceLayer { @@ -76,9 +78,9 @@ CHIP_ERROR SilabsConfig::Init() void SilabsConfig::DeInit() { -#ifndef BRD4325A // TODO: fix semaphore usage in nvm3_lock for siwx917. use weak implementation for that board instead +#ifndef SIWX_917 vSemaphoreDelete(nvm3_Sem); -#endif // not BRD4325A +#endif // !SIWX_917 nvm3_close(nvm3_defaultHandle); } diff --git a/src/platform/silabs/ThreadStackManagerImpl.h b/src/platform/silabs/ThreadStackManagerImpl.h index b1436b3b75b27e..c56990fb0d3712 100644 --- a/src/platform/silabs/ThreadStackManagerImpl.h +++ b/src/platform/silabs/ThreadStackManagerImpl.h @@ -72,19 +72,11 @@ class ThreadStackManagerImpl final : public ThreadStackManager, using ThreadStackManager::InitThreadStack; CHIP_ERROR InitThreadStack(otInstance * otInst); -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT - void RemoveAllSrpServices(); -#endif private: // ===== Methods that implement the ThreadStackManager abstract interface. CHIP_ERROR _InitThreadStack(void); -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT - static void OnSrpClientRemoveCallback(otError aError, const otSrpClientHostInfo * aHostInfo, - const otSrpClientService * aServices, const otSrpClientService * aRemovedServices, - void * aContext); -#endif // ===== Members for internal use by the following friends. friend ThreadStackManager & ::chip::DeviceLayer::ThreadStackMgr(void); @@ -94,9 +86,6 @@ class ThreadStackManagerImpl final : public ThreadStackManager, static ThreadStackManagerImpl sInstance; static bool IsInitialized(); -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT - TaskHandle_t srpRemoveRequester = nullptr; -#endif // ===== Private members for use by this class only. diff --git a/src/platform/silabs/efr32/ThreadStackManagerImpl.cpp b/src/platform/silabs/efr32/ThreadStackManagerImpl.cpp index c4556036034e78..83767f9a0e1fb8 100644 --- a/src/platform/silabs/efr32/ThreadStackManagerImpl.cpp +++ b/src/platform/silabs/efr32/ThreadStackManagerImpl.cpp @@ -66,58 +66,6 @@ bool ThreadStackManagerImpl::IsInitialized() return sInstance.mThreadStackLock != NULL; } -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT -/* - * @brief Notifies `RemoveAllSrpServices` that the Srp Client removal has completed - * and unblock the calling task. - * - * No data is processed. - */ -void ThreadStackManagerImpl::OnSrpClientRemoveCallback(otError aError, const otSrpClientHostInfo * aHostInfo, - const otSrpClientService * aServices, - const otSrpClientService * aRemovedServices, void * aContext) -{ - if (ThreadStackMgrImpl().srpRemoveRequester) - { - xTaskNotifyGive(ThreadStackMgrImpl().srpRemoveRequester); - } -} - -/* - * @brief This is a utility function to remove all Thread client Srp services - * established between the device and the srp server (in most cases the OTBR). - * The calling task is blocked until OnSrpClientRemoveCallback. - * - * Note: This function is meant to be used during the factory reset sequence. - * It overrides the generic SrpClient callback `OnSrpClientNotification` with - * OnSrpClientRemoveCallback which doesn't process any of the callback data. - * - * If there is a usecase where this function would be needed in a non-Factory reset context, - * OnSrpClientRemoveCallback should be extended and tied back with the GenericThreadStackManagerImpl_OpenThread - * management of the srp clients. - */ -void ThreadStackManagerImpl::RemoveAllSrpServices() -{ - // This check ensure that only one srp services removal is running - if (ThreadStackMgrImpl().srpRemoveRequester == nullptr) - { - srpRemoveRequester = xTaskGetCurrentTaskHandle(); - otSrpClientSetCallback(OTInstance(), &OnSrpClientRemoveCallback, nullptr); - InvalidateAllSrpServices(); - if (RemoveInvalidSrpServices() == CHIP_NO_ERROR) - { - // Wait for the OnSrpClientRemoveCallback. - ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(2000)); - } - else - { - ChipLogError(DeviceLayer, "Failed to remove srp services"); - } - ThreadStackMgrImpl().srpRemoveRequester = nullptr; - } -} -#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT - } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/telink/ThreadStackManagerImpl.cpp b/src/platform/telink/ThreadStackManagerImpl.cpp index e66735b1de68f2..13ba8be424563b 100644 --- a/src/platform/telink/ThreadStackManagerImpl.cpp +++ b/src/platform/telink/ThreadStackManagerImpl.cpp @@ -68,6 +68,10 @@ CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack() return MapOpenThreadError(otError); }); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + k_sem_init(&mSrpClearAllSemaphore, 0, 1); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + return CHIP_NO_ERROR; } @@ -87,6 +91,18 @@ void ThreadStackManagerImpl::_UnlockThreadStack() openthread_api_mutex_unlock(openthread_get_default_context()); } +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT +void ThreadStackManagerImpl::_WaitOnSrpClearAllComplete() +{ + k_sem_take(&mSrpClearAllSemaphore, K_SECONDS(2)); +} + +void ThreadStackManagerImpl::_NotifySrpClearAllComplete() +{ + k_sem_give(&mSrpClearAllSemaphore); +} +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + CHIP_ERROR ThreadStackManagerImpl::_AttachToThreadNetwork(const Thread::OperationalDataset & dataset, NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback) diff --git a/src/platform/telink/ThreadStackManagerImpl.h b/src/platform/telink/ThreadStackManagerImpl.h index d1040542f3c616..21db9972f62dec 100644 --- a/src/platform/telink/ThreadStackManagerImpl.h +++ b/src/platform/telink/ThreadStackManagerImpl.h @@ -74,6 +74,10 @@ class ThreadStackManagerImpl final : public ThreadStackManager, bool _TryLockThreadStack(); void _UnlockThreadStack(); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + void _WaitOnSrpClearAllComplete(); + void _NotifySrpClearAllComplete(); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT // ===== Methods that override the GenericThreadStackManagerImpl_OpenThread abstract interface. void _ProcessThreadActivity() {} @@ -95,6 +99,10 @@ class ThreadStackManagerImpl final : public ThreadStackManager, bool mRadioBlocked; bool mReadyToAttach; +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + k_sem mSrpClearAllSemaphore; +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + NetworkCommissioning::ThreadDriver::ScanCallback * mpScanCallback; }; diff --git a/src/platform/webos/ThreadStackManagerImpl.h b/src/platform/webos/ThreadStackManagerImpl.h index 876c339cceb6ae..a21d4cbf551251 100644 --- a/src/platform/webos/ThreadStackManagerImpl.h +++ b/src/platform/webos/ThreadStackManagerImpl.h @@ -50,6 +50,11 @@ class ThreadStackManagerImpl : public ThreadStackManager bool _TryLockThreadStack() { return false; } // Intentionally left blank void _UnlockThreadStack() {} // Intentionally left blank +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + void _WaitOnSrpClearAllComplete() {} + void _NotifySrpClearAllComplete() {} +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + bool _HaveRouteToAddress(const Inet::IPAddress & destAddr); void _OnPlatformEvent(const ChipDeviceEvent * event); diff --git a/src/protocols/interaction_model/StatusCodeList.h b/src/protocols/interaction_model/StatusCodeList.h index 3b79e4a698b7b5..5538478d76ce52 100644 --- a/src/protocols/interaction_model/StatusCodeList.h +++ b/src/protocols/interaction_model/StatusCodeList.h @@ -22,7 +22,10 @@ * include this file, then undefine the macro. */ -/// WARNING: If you touch this list, please also update src/controller/python/chip/interaction_model/__init__.py +/// WARNING: If you touch this list, +/// please update src/controller/python/chip/interaction_model/__init__.py +/// please update src/controller/java/src/chip/devicecontroller/model/Status.java +/// please update src/controller/java/src/matter/controller/model/Status.kt // clang-format off CHIP_IM_STATUS_CODE(Success , SUCCESS , 0x0) diff --git a/src/protocols/secure_channel/RendezvousParameters.h b/src/protocols/secure_channel/RendezvousParameters.h index a82628a483b2e9..e5e366d3b3b704 100644 --- a/src/protocols/secure_channel/RendezvousParameters.h +++ b/src/protocols/secure_channel/RendezvousParameters.h @@ -32,8 +32,8 @@ namespace chip { // The largest supported value for Rendezvous discriminators const uint16_t kMaxRendezvousDiscriminatorValue = 0xFFF; -// The largest supported value for sleepy idle interval and sleepy active interval -inline constexpr uint32_t kMaxSleepyInterval = 3600000; +// The largest supported value for session idle interval and session active interval +inline constexpr uint32_t kMaxSessionIdleInterval = 3600000; class RendezvousParameters { diff --git a/src/python_testing/TC_CNET_4_4.py b/src/python_testing/TC_CNET_4_4.py new file mode 100644 index 00000000000000..12407e6c5fd6b0 --- /dev/null +++ b/src/python_testing/TC_CNET_4_4.py @@ -0,0 +1,132 @@ +# +# 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. +# + +import logging +import random +import string +from typing import Optional + +import chip.clusters as Clusters +from chip.clusters.Types import NullValue +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main, type_matches +from mobly import asserts + + +class TC_CNET_4_4(MatterBaseTest): + def steps_TC_CNET_4_4(self): + return [TestStep("precondition", "TH is commissioned", is_commissioning=True), + TestStep(1, 'TH reads from the DUT the Network Commissioning Cluster FeatureMap. If the FeatureMap does not include the WI flag (bit 0), skip the remaining steps in this test case'), + TestStep(2, 'TH reads from the DUT the SupportedWifiBands attribute and saves as supported_wifi_bands'), + TestStep(3, 'TH reads from the DUT the Networks attribute.'), + TestStep(4, 'TH sends ScanNetworks command to the DUT with the SSID field set to null and Breadcrumb field set to 1'), + TestStep(5, 'TH reads from the DUT the Breadcrumb attribute from the General Commissioning Cluster'), + TestStep(6, 'TH sends ScanNetworks Command to the DUT with SSID field set to known_ssid and Breadcrumb field set to 2'), + TestStep(7, 'TH reads Breadcrumb attribute from the General Commissioning Cluster'), + TestStep(8, 'TH sends ScanNetworks Command to the DUT with SSID field set to a string of 31 random alphabetical characters and Breadcrumb field set to 2')] + + def def_TC_CNET_4_4(self): + return '[TC-CNET-4.4] [Wi-Fi] Verification for ScanNetworks command [DUT-Server]' + + def pics_TC_CNET_4_4(self): + return ['CNET.S'] + + @async_test_body + async def test_TC_CNET_4_4(self): + # Commissioning is already done + self.step("precondition") + + cnet = Clusters.NetworkCommissioning + attr = cnet.Attributes + + self.step(1) + feature_map = await self.read_single_attribute_check_success(cluster=cnet, attribute=attr.FeatureMap) + if not (feature_map & cnet.Bitmaps.Feature.kWiFiNetworkInterface): + logging.info('Device does not support WiFi on endpoint, skipping remaining steps') + self.skip_all_remaining_steps(2) + return + + self.step(2) + supported_wifi_bands = await self.read_single_attribute_check_success(cluster=cnet, attribute=attr.SupportedWiFiBands) + + self.step(3) + networks = await self.read_single_attribute_check_success(cluster=cnet, attribute=attr.Networks) + connected = [network for network in networks if network.connected is True] + asserts.assert_greater_equal(len(connected), 1, "Did not find any connected networks on a commissioned device") + known_ssid = connected[0].networkID + + async def scan_and_check(ssid_to_scan: Optional[bytes], breadcrumb: int, expect_results: bool = True): + all_security = 0 + for security_bitmask in cnet.Bitmaps.WiFiSecurityBitmap: + all_security |= security_bitmask + + ssid = ssid_to_scan if ssid_to_scan is not None else NullValue + cmd = cnet.Commands.ScanNetworks(ssid=ssid, breadcrumb=breadcrumb) + scan_results = await self.send_single_cmd(cmd=cmd) + asserts.assert_true(type_matches(scan_results, cnet.Commands.ScanNetworksResponse), + "Unexpected value returned from scan network") + logging.info(f"Scan results: {scan_results}") + + if scan_results.debugText: + debug_text_len = len(scan_results.debug_text) + asserts.assert_less_equal(debug_text_len, 512, f"DebugText length {debug_text_len} was out of range") + + if expect_results: + asserts.assert_equal(scan_results.networkingStatus, cnet.Enums.NetworkCommissioningStatusEnum.kSuccess, + f"ScanNetworks was expected to have succeeded, got {scan_results.networkingStatus} instead") + asserts.assert_greater_equal(len(scan_results.wiFiScanResults), 1, "No responses returned from ScanNetwork command") + else: + asserts.assert_equal(scan_results.networkingStatus, cnet.Enums.NetworkCommissioningStatusEnum.kNetworkNotFound, + f"ScanNetworks was expected to received NetworkNotFound(5), got {scan_results.networkingStatus} instead") + return + + for network in scan_results.wiFiScanResults: + asserts.assert_true((network.security & ~all_security) == 0, "Unexpected bitmap in the security field") + asserts.assert_less_equal(len(network.ssid), 32, f"Returned SSID {network.ssid} is too long") + if ssid_to_scan is not None: + asserts.assert_equal(network.ssid, ssid_to_scan, "Unexpected SSID returned in directed scan") + asserts.assert_true(type_matches(network.bssid, bytes), "Incorrect type for BSSID") + asserts.assert_equal(len(network.bssid), 6, "Unexpected length of BSSID") + # TODO: this is inherited from the old test plan, but we should match the channel to the supported band. This range is unreasonably large. + asserts.assert_less_equal(network.channel, 65535, "Unexpected channel value") + if network.wiFiBand: + asserts.assert_true(network.wiFiBand in supported_wifi_bands, + "Listed wiFiBand is not in supported_wifi_bands") + if network.rssi: + asserts.assert_greater_equal(network.rssi, -120, "RSSI out of range") + asserts.assert_less_equal(network.rssi, 0, "RSSI out of range") + + self.step(4) + await scan_and_check(ssid_to_scan=None, breadcrumb=1, expect_results=True) + + self.step(5) + breadcrumb = await self.read_single_attribute_check_success(cluster=Clusters.GeneralCommissioning, attribute=Clusters.GeneralCommissioning.Attributes.Breadcrumb, endpoint=0) + asserts.assert_equal(breadcrumb, 1, "Incorrect breadcrumb value") + + self.step(6) + await scan_and_check(ssid_to_scan=known_ssid, breadcrumb=2, expect_results=True) + + self.step(7) + breadcrumb = await self.read_single_attribute_check_success(cluster=Clusters.GeneralCommissioning, attribute=Clusters.GeneralCommissioning.Attributes.Breadcrumb, endpoint=0) + asserts.assert_equal(breadcrumb, 2, "Incorrect breadcrumb value") + + self.step(8) + random_ssid = ''.join(random.choice(string.ascii_letters) for _ in range(31)).encode("utf-8") + await scan_and_check(ssid_to_scan=random_ssid, breadcrumb=2, expect_results=False) + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_DeviceBasicComposition.py b/src/python_testing/TC_DeviceBasicComposition.py index 409ae97c1a4106..5bfbc5c44e839b 100644 --- a/src/python_testing/TC_DeviceBasicComposition.py +++ b/src/python_testing/TC_DeviceBasicComposition.py @@ -23,7 +23,11 @@ import chip.clusters.ClusterObjects import chip.tlv from basic_composition_support import BasicCompositionTests +from chip import ChipUtility from chip.clusters.Attribute import ValueDecodeFailure +from chip.clusters.ClusterObjects import ClusterAttributeDescriptor, ClusterObjectFieldDescriptor +from chip.interaction_model import InteractionModelError, Status +from chip.tlv import uint from global_attribute_ids import GlobalAttributeIds from matter_testing_support import (AttributePathLocation, ClusterPathLocation, CommandPathLocation, MatterBaseTest, async_test_body, default_matter_test_main) @@ -165,7 +169,41 @@ def test_TC_DT_1_1(self): if not success: self.fail_current_test("At least one endpoint was missing the descriptor cluster.") - def test_TC_IDM_10_1(self): + async def _read_non_standard_attribute_check_unsupported_read(self, endpoint_id, cluster_id, attribute_id) -> bool: + @dataclass + class TempAttribute(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return cluster_id + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return attribute_id + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=uint) + + @ChipUtility.classproperty + def standard_attribute(cls) -> bool: + return False + + value: 'uint' = 0 + + result = await self.default_controller.Read(nodeid=self.dut_node_id, attributes=[(endpoint_id, TempAttribute)]) + try: + attr_ret = result.tlvAttributes[endpoint_id][cluster_id][attribute_id] + except KeyError: + attr_ret = None + + error_type_ok = attr_ret is not None and isinstance( + attr_ret, Clusters.Attribute.ValueDecodeFailure) and isinstance(attr_ret.Reason, InteractionModelError) + + got_expected_error = error_type_ok and attr_ret.Reason.status == Status.UnsupportedRead + return got_expected_error + + @async_test_body + async def test_TC_IDM_10_1(self): self.print_step(1, "Perform a wildcard read of attributes on all endpoints - already done") @dataclass @@ -222,6 +260,10 @@ class RequiredMandatoryAttribute: problem=f"Failed validation of value on {location.as_string(self.cluster_mapper)}: {str(e)}", spec_location="Global Elements") success = False continue + except KeyError: + # A KeyError here means the attribute does not exist. This problem was already recorded in step 2, + # but we don't assert until the end of the test, so ignore this and don't re-record the error. + continue self.print_step(4, "Validate the attribute list exactly matches the set of reported attributes") if success: @@ -236,15 +278,19 @@ class RequiredMandatoryAttribute: logging.debug( f"Checking presence of claimed supported {attribute_string} on {location.as_cluster_string(self.cluster_mapper)}: {'found' if has_attribute else 'not_found'}") - # Check attribute is actually present. if not has_attribute: - # TODO: Handle detecting write-only attributes from schema. - if "WriteOnly" in attribute_string: - continue - - self.record_error(self.get_test_name(), location=location, - problem=f"Did not find {attribute_string} on {location.as_cluster_string(self.cluster_mapper)} when it was claimed in AttributeList ({attribute_list})", spec_location="AttributeList Attribute") - success = False + # Check if this is a write-only attribute by trying to read it. + # If it's present and write-only it should return an UNSUPPORTED_READ error. All other errors are a failure. + # Because these can be MEI attributes, we need to build the ClusterAttributeDescriptor manually since it's + # not guaranteed to be generated. Since we expect an error back anyway, the type doesn't matter. + + write_only_attribute = await self._read_non_standard_attribute_check_unsupported_read( + endpoint_id=endpoint_id, cluster_id=cluster_id, attribute_id=attribute_id) + + if not write_only_attribute: + self.record_error(self.get_test_name(), location=location, + problem=f"Did not find {attribute_string} on {location.as_cluster_string(self.cluster_mapper)} when it was claimed in AttributeList ({attribute_list})", spec_location="AttributeList Attribute") + success = False continue attribute_value = cluster[attribute_id] diff --git a/src/python_testing/TC_MWOCTRL_2_2.py b/src/python_testing/TC_MWOCTRL_2_2.py index abe02d8237a8db..a5484c586067c6 100644 --- a/src/python_testing/TC_MWOCTRL_2_2.py +++ b/src/python_testing/TC_MWOCTRL_2_2.py @@ -42,6 +42,7 @@ def steps_TC_MWOCTRL_2_2(self) -> list[TestStep]: TestStep(2, "Read the PowerSetting attribute"), TestStep(3, "Send the SetCookingParameters command"), TestStep(4, "Read and verify the PowerSetting attribute"), + TestStep(5, "Cause constraint error response"), ] return steps @@ -89,6 +90,14 @@ async def test_TC_MWOCTRL_2_2(self): powerValue = await self.read_mwoctrl_attribute_expect_success(endpoint=endpoint, attribute=attributes.PowerSetting) asserts.assert_true(powerValue == newPowerValue, "PowerSetting was not correctly set") + self.step(5) + newPowerValue = 125 + try: + await self.send_single_cmd(cmd=commands.SetCookingParameters(powerSetting=newPowerValue), endpoint=endpoint) + asserts.assert_fail("Expected an exception but received none.") + except InteractionModelError as e: + asserts.assert_equal(e.status, Status.ConstraintError, "Expected ConstraintError but received a different error.") + if __name__ == "__main__": default_matter_test_main() diff --git a/src/python_testing/TC_MWOCTRL_2_3.py b/src/python_testing/TC_MWOCTRL_2_3.py index 0d34c5b3ee8fde..20a1e730ab620a 100644 --- a/src/python_testing/TC_MWOCTRL_2_3.py +++ b/src/python_testing/TC_MWOCTRL_2_3.py @@ -45,6 +45,7 @@ def steps_TC_MWOCTRL_2_3(self) -> list[TestStep]: TestStep(5, "Read the PowerSetting attribute"), TestStep(6, "Send the SetCookingParameters command"), TestStep(7, "Read and verify the PowerSetting attribute"), + TestStep(8, "Cause constraint error response"), ] return steps @@ -109,6 +110,14 @@ async def test_TC_MWOCTRL_2_3(self): powerValue = await self.read_mwoctrl_attribute_expect_success(endpoint=endpoint, attribute=attributes.PowerSetting) asserts.assert_true(powerValue == newPowerValue, "PowerSetting was not correctly set") + self.step(8) + newPowerValue = maxPowerValue+1 + try: + await self.send_single_cmd(cmd=commands.SetCookingParameters(powerSetting=newPowerValue), endpoint=endpoint) + asserts.assert_fail("Expected an exception but received none.") + except InteractionModelError as e: + asserts.assert_equal(e.status, Status.ConstraintError, "Expected ConstraintError but received a different response.") + if __name__ == "__main__": default_matter_test_main() diff --git a/src/python_testing/TC_PWRTL_2_1.py b/src/python_testing/TC_PWRTL_2_1.py new file mode 100644 index 00000000000000..bd839cd5f072f4 --- /dev/null +++ b/src/python_testing/TC_PWRTL_2_1.py @@ -0,0 +1,69 @@ +# +# 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. +# + +import logging + +import chip.clusters as Clusters +from chip.clusters.Types import NullValue +from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_PWRTL_2_1(MatterBaseTest): + + def pics_TC_PWRTL_2_1(self) -> list[str]: + return ["PWRTL.S"] + + @async_test_body + async def test_TC_PWRTL_2_1(self): + + attributes = Clusters.PowerTopology.Attributes + + endpoint = self.user_params.get("endpoint", 1) + + self.print_step(1, "Commissioning, already done") + + if not self.check_pics("PWRTL.S.A0000"): + logging.info("Test skipped because PICS PWRTL.S.A0000 is not set") + return + + self.print_step(2, "Read AvailableAttributes attribute") + available_endpoints = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=Clusters.Objects.PowerTopology, attribute=attributes.AvailableEndpoints) + + if available_endpoints == NullValue: + logging.info("AvailableEndpoints is null") + else: + logging.info("AvailableEndpoints: %s" % (available_endpoints)) + + asserts.assert_less_equal(len(available_endpoints), 21, + "AvailableEndpoints length %d must be less than 21!" % len(available_endpoints)) + + if not self.check_pics("PWRTL.S.A0001"): + logging.info("Test skipped because PICS PWRTL.S.A0001 is not set") + return + + self.print_step(3, "Read ActiveEndpoints attribute") + active_endpoints = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=Clusters.Objects.PowerTopology, attribute=attributes.ActiveEndpoints) + logging.info("ActiveEndpoints: %s" % (active_endpoints)) + + if available_endpoints == NullValue: + asserts.assert_true(active_endpoints == NullValue, + "ActiveEndpoints should be null when AvailableEndpoints is null: %s" % active_endpoints) + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_RVCCLEANM_2_1.py b/src/python_testing/TC_RVCCLEANM_2_1.py index d000f0d5af697d..6ef91d89a06729 100644 --- a/src/python_testing/TC_RVCCLEANM_2_1.py +++ b/src/python_testing/TC_RVCCLEANM_2_1.py @@ -16,6 +16,7 @@ # import logging +from time import sleep import chip.clusters as Clusters from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main, type_matches @@ -56,6 +57,9 @@ async def send_run_change_to_mode_cmd(self, newMode) -> Clusters.Objects.RvcRunM def write_to_app_pipe(self, command): with open(self.app_pipe, "w") as app_pipe: app_pipe.write(command + "\n") + # Delay for pipe command to be processed (otherwise tests are flaky) + # TODO(#31239): centralize pipe write logic and remove the need of sleep + sleep(0.001) def pics_TC_RVCCLEANM_2_1(self) -> list[str]: return ["RVCCLEANM.S"] diff --git a/src/python_testing/TC_RVCCLEANM_2_2.py b/src/python_testing/TC_RVCCLEANM_2_2.py index ae5c268d7a9668..7e1fa6aaf2667e 100644 --- a/src/python_testing/TC_RVCCLEANM_2_2.py +++ b/src/python_testing/TC_RVCCLEANM_2_2.py @@ -15,6 +15,8 @@ # limitations under the License. # +from time import sleep + import chip.clusters as Clusters from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main from mobly import asserts @@ -70,6 +72,9 @@ def pics_TC_RVCCLEANM_2_2(self) -> list[str]: def write_to_app_pipe(self, command): with open(self.app_pipe, "w") as app_pipe: app_pipe.write(command + "\n") + # Delay for pipe command to be processed (otherwise tests are flaky) + # TODO(#31239): centralize pipe write logic and remove the need of sleep + sleep(0.001) @async_test_body async def test_TC_RVCCLEANM_2_2(self): diff --git a/src/python_testing/TC_RVCOPSTATE_2_1.py b/src/python_testing/TC_RVCOPSTATE_2_1.py index b0d753ad216164..e9dd4659059fa0 100644 --- a/src/python_testing/TC_RVCOPSTATE_2_1.py +++ b/src/python_testing/TC_RVCOPSTATE_2_1.py @@ -16,6 +16,7 @@ # import logging +from time import sleep import chip.clusters as Clusters from chip.clusters.Types import NullValue @@ -63,6 +64,9 @@ async def send_pause_cmd(self) -> Clusters.Objects.RvcOperationalState.Commands. def write_to_app_pipe(self, command): with open(self.app_pipe, "w") as app_pipe: app_pipe.write(command + "\n") + # Allow some time for the command to take effect. + # This removes the test flakyness which is very annoying for everyone in CI. + sleep(0.001) def TC_RVCOPSTATE_2_1(self) -> list[str]: return ["RVCOPSTATE.S"] diff --git a/src/python_testing/TC_RVCOPSTATE_2_3.py b/src/python_testing/TC_RVCOPSTATE_2_3.py index 4d275ac5adc5b9..aa755315fb7d46 100644 --- a/src/python_testing/TC_RVCOPSTATE_2_3.py +++ b/src/python_testing/TC_RVCOPSTATE_2_3.py @@ -130,6 +130,9 @@ async def send_run_change_to_mode_cmd(self, new_mode) -> Clusters.Objects.RvcRun def write_to_app_pipe(self, command): with open(self.app_pipe, "w") as app_pipe: app_pipe.write(command + "\n") + # Delay for pipe command to be processed (otherwise tests are flaky) + # TODO(#31239): centralize pipe write logic and remove the need of sleep + sleep(0.001) # Prints the instruction and waits for a user input to continue def print_instruction(self, step_number, instruction): diff --git a/src/python_testing/TC_RVCOPSTATE_2_4.py b/src/python_testing/TC_RVCOPSTATE_2_4.py index 3314eaade876bb..7352fbd089f172 100644 --- a/src/python_testing/TC_RVCOPSTATE_2_4.py +++ b/src/python_testing/TC_RVCOPSTATE_2_4.py @@ -16,6 +16,7 @@ # import logging +from time import sleep import chip.clusters as Clusters from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main, type_matches @@ -81,6 +82,9 @@ async def send_run_change_to_mode_cmd(self, new_mode): def write_to_app_pipe(self, command): with open(self.app_pipe, "w") as app_pipe: app_pipe.write(command + "\n") + # Delay for pipe command to be processed (otherwise tests are flaky) + # TODO(#31239): centralize pipe write logic and remove the need of sleep + sleep(0.001) def pics_TC_RVCOPSTATE_2_4(self) -> list[str]: return ["RVCOPSTATE.S"] diff --git a/src/python_testing/TC_RVCRUNM_2_1.py b/src/python_testing/TC_RVCRUNM_2_1.py index a9b4c44ba4f88c..1f3bccb528f137 100644 --- a/src/python_testing/TC_RVCRUNM_2_1.py +++ b/src/python_testing/TC_RVCRUNM_2_1.py @@ -16,6 +16,7 @@ # import logging +from time import sleep import chip.clusters as Clusters from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main, type_matches @@ -51,6 +52,9 @@ async def send_change_to_mode_cmd(self, newMode) -> Clusters.Objects.RvcRunMode. def write_to_app_pipe(self, command): with open(self.app_pipe, "w") as app_pipe: app_pipe.write(command + "\n") + # Delay for pipe command to be processed (otherwise tests are flaky) + # TODO(#31239): centralize pipe write logic and remove the need of sleep + sleep(0.001) def pics_TC_RVCRUNM_2_1(self) -> list[str]: return ["RVCRUNM.S"] diff --git a/src/python_testing/TC_RVCRUNM_2_2.py b/src/python_testing/TC_RVCRUNM_2_2.py index 4868865c367d19..d85d1ae53cb928 100644 --- a/src/python_testing/TC_RVCRUNM_2_2.py +++ b/src/python_testing/TC_RVCRUNM_2_2.py @@ -15,6 +15,8 @@ # limitations under the License. # +from time import sleep + import chip.clusters as Clusters from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main from mobly import asserts @@ -91,6 +93,9 @@ async def read_op_state_operational_state(self) -> Clusters.Objects.RvcOperation def write_to_app_pipe(self, command): with open(self.app_pipe, "w") as app_pipe: app_pipe.write(command + "\n") + # Delay for pipe command to be processed (otherwise tests are flaky) + # TODO(#31239): centralize pipe write logic and remove the need of sleep + sleep(0.001) def pics_TC_RVCRUNM_2_2(self) -> list[str]: return ["RVCRUNM.S"] diff --git a/src/python_testing/TestSpecParsingSupport.py b/src/python_testing/TestSpecParsingSupport.py index ed790fb4bf4629..2ff80e55244648 100644 --- a/src/python_testing/TestSpecParsingSupport.py +++ b/src/python_testing/TestSpecParsingSupport.py @@ -19,9 +19,10 @@ import chip.clusters as Clusters from global_attribute_ids import GlobalAttributeIds -from matter_testing_support import MatterBaseTest, default_matter_test_main +from matter_testing_support import MatterBaseTest, ProblemNotice, default_matter_test_main from mobly import asserts -from spec_parsing_support import ClusterParser, XmlCluster +from spec_parsing_support import (ClusterParser, XmlCluster, add_cluster_data_from_xml, check_clusters_for_unknown_commands, + combine_derived_clusters_with_base) # TODO: improve the test coverage here # https://github.com/project-chip/connectedhomeip/issues/30958 @@ -77,6 +78,120 @@ def get_access_enum_from_string(access_str: str) -> Clusters.AccessControl.Enums asserts.fail("Unknown access string") +BASE_CLUSTER_XML_STR = ( + '' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + '') + +DERIVED_CLUSTER_XML_STR = ( + '' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + '' +) + +CLUSTER_WITH_UNKNOWN_COMMAND = ( + '' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + '' +) + + class TestSpecParsingSupport(MatterBaseTest): def test_spec_parsing_access(self): strs = [None, 'view', 'operate', 'manage', 'admin'] @@ -106,6 +221,81 @@ def test_write_optional(self): asserts.assert_equal(xml_cluster.attributes[ATTRIBUTE_ID].write_optional, write_support == 'optional', "Unexpected write_optional value") + def test_derived_clusters(self): + clusters: dict[int, XmlCluster] = {} + pure_base_clusters: dict[str, XmlCluster] = {} + ids_by_name: dict[str, int] = {} + problems: list[ProblemNotice] = [] + base_cluster_xml = ElementTree.fromstring(BASE_CLUSTER_XML_STR) + derived_cluster_xml = ElementTree.fromstring(DERIVED_CLUSTER_XML_STR) + expected_global_attrs = [GlobalAttributeIds.FEATURE_MAP_ID, GlobalAttributeIds.ATTRIBUTE_LIST_ID, + GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID, GlobalAttributeIds.GENERATED_COMMAND_LIST_ID, GlobalAttributeIds.CLUSTER_REVISION_ID] + + add_cluster_data_from_xml(base_cluster_xml, clusters, pure_base_clusters, ids_by_name, problems) + add_cluster_data_from_xml(derived_cluster_xml, clusters, pure_base_clusters, ids_by_name, problems) + + asserts.assert_equal(len(clusters), 1, "Unexpected number of clusters") + asserts.assert_equal(len(pure_base_clusters), 1, "Unexpected number of pure base clusters") + asserts.assert_equal(len(ids_by_name), 1, "Unexpected number of IDs per name") + asserts.assert_equal(len(problems), 0, "Unexpected number of problems") + asserts.assert_equal(ids_by_name["Test Derived"], 0xFFFF, "Test derived name not added to IDs") + + asserts.assert_true(0xFFFF in clusters, "Derived ID not found in clusters") + asserts.assert_equal(set(clusters[0xFFFF].attributes.keys()), set( + [0, 2, 3] + expected_global_attrs), "Unexpected attribute list") + asserts.assert_equal(set(clusters[0xFFFF].accepted_commands.keys()), set([]), "Unexpected accepted commands") + asserts.assert_equal(set(clusters[0xFFFF].generated_commands.keys()), set([]), "Unexpected generated commands") + + asserts.assert_true("Test Base" in pure_base_clusters, "Base ID not found in derived clusters") + asserts.assert_equal(set(pure_base_clusters["Test Base"].attributes.keys()), set( + [0, 1, 2, 3] + expected_global_attrs), "Unexpected attribute list") + asserts.assert_equal(set(pure_base_clusters["Test Base"].accepted_commands.keys()), + set([0]), "Unexpected accepted commands") + asserts.assert_equal(set(pure_base_clusters["Test Base"].generated_commands.keys()), + set([1]), "Unexpected generated commands") + asserts.assert_equal(str(pure_base_clusters["Test Base"].accepted_commands[0].conformance), + "M", "Unexpected conformance on base accepted command") + asserts.assert_equal(str(pure_base_clusters["Test Base"].generated_commands[1].conformance), + "M", "Unexpected conformance on base generated command") + + asserts.assert_equal(len(pure_base_clusters["Test Base"].unknown_commands), + 0, "Unexpected number of unknown commands in base") + asserts.assert_equal(len(clusters[0xFFFF].unknown_commands), 2, "Unexpected number of unknown commands in derived cluster") + + combine_derived_clusters_with_base(clusters, pure_base_clusters, ids_by_name) + # Ensure the base-only attribute (1) was added to the derived cluster + asserts.assert_equal(set(clusters[0xFFFF].attributes.keys()), set( + [0, 1, 2, 3] + expected_global_attrs), "Unexpected attribute list") + # Ensure the conformance overrides from the derived cluster are on the attributes + asserts.assert_equal(str(clusters[0xFFFF].attributes[0].conformance), "M", "Unexpected conformance on attribute 0") + asserts.assert_equal(str(clusters[0xFFFF].attributes[1].conformance), "M", "Unexpected conformance on attribute 1") + asserts.assert_equal(str(clusters[0xFFFF].attributes[2].conformance), "X", "Unexpected conformance on attribute 2") + asserts.assert_equal(str(clusters[0xFFFF].attributes[3].conformance), "X", "Unexpected conformance on attribute 3") + + # Ensure both the accepted and generated command overrides work + asserts.assert_true(set(clusters[0xFFFF].accepted_commands.keys()), + set([0]), "Unexpected accepted command list after merge") + asserts.assert_true(set(clusters[0xFFFF].generated_commands.keys()), set([1]), + "Unexpected generated command list after merge") + asserts.assert_equal(str(clusters[0xFFFF].accepted_commands[0].conformance), + "X", "Unexpected conformance on accepted commands") + asserts.assert_equal(str(clusters[0xFFFF].generated_commands[1].conformance), + "X", "Unexpected conformance on generated commands") + asserts.assert_equal(len(clusters[0xFFFF].unknown_commands), 0, "Unexpected number of unknown commands after merge") + + def test_missing_command_direction(self): + clusters: dict[int, XmlCluster] = {} + pure_base_clusters: dict[str, XmlCluster] = {} + ids_by_name: dict[str, int] = {} + problems: list[ProblemNotice] = [] + cluster_xml = ElementTree.fromstring(CLUSTER_WITH_UNKNOWN_COMMAND) + + add_cluster_data_from_xml(cluster_xml, clusters, pure_base_clusters, ids_by_name, problems) + check_clusters_for_unknown_commands(clusters, problems) + asserts.assert_equal(len(problems), 1, "Unexpected number of problems found") + asserts.assert_equal(problems[0].location.cluster_id, 0xFFFE, "Unexpected problem location (cluster id)") + asserts.assert_equal(problems[0].location.command_id, 0, "Unexpected problem location (command id)") + if __name__ == "__main__": default_matter_test_main() diff --git a/src/python_testing/basic_composition_support.py b/src/python_testing/basic_composition_support.py index 8a6494eccea42f..4a516f67ecbc97 100644 --- a/src/python_testing/basic_composition_support.py +++ b/src/python_testing/basic_composition_support.py @@ -105,24 +105,10 @@ async def setup_class_helper(self, default_to_pase: bool = True): dump_device_composition_path: Optional[str] = self.user_params.get("dump_device_composition_path", None) if do_test_over_pase: - info = self.get_setup_payload_info() - - commissionable_nodes = dev_ctrl.DiscoverCommissionableNodes( - info.filter_type, info.filter_value, stopOnFirst=True, timeoutSecond=15) - logging.info(f"Commissionable nodes: {commissionable_nodes}") - # TODO: Support BLE - if commissionable_nodes is not None and len(commissionable_nodes) > 0: - commissionable_node = commissionable_nodes[0] - instance_name = f"{commissionable_node.instanceName}._matterc._udp.local" - vid = f"{commissionable_node.vendorId}" - pid = f"{commissionable_node.productId}" - address = f"{commissionable_node.addresses[0]}" - logging.info(f"Found instance {instance_name}, VID={vid}, PID={pid}, Address={address}") - - node_id = 1 - dev_ctrl.EstablishPASESessionIP(address, info.passcode, node_id) - else: - asserts.fail("Failed to find the DUT according to command line arguments.") + setupCode = self.matter_test_config.qr_code_content if self.matter_test_config.qr_code_content is not None else self.matter_test_config.manual_code + asserts.assert_true(setupCode, "Require either --qr-code or --manual-code.") + node_id = self.dut_node_id + dev_ctrl.EstablishPASESession(setupCode, node_id) else: # Using the already commissioned node node_id = self.dut_node_id diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index 1515f0310d3302..7efe5ab948966b 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -60,6 +60,7 @@ from chip.setup_payload import SetupPayload from chip.storage import PersistentStorage from chip.tracing import TracingContext +from global_attribute_ids import GlobalAttributeIds from mobly import asserts, base_test, signals, utils from mobly.config_parser import ENV_MOBLY_LOGPATH, TestRunConfig from mobly.test_runner import TestRunner @@ -412,6 +413,9 @@ def get_cluster_string(self, cluster_id: int) -> str: return f"Cluster {name} ({cluster_id}, 0x{cluster_id:04X})" def get_attribute_string(self, cluster_id: int, attribute_id) -> str: + global_attrs = [item.value for item in GlobalAttributeIds] + if attribute_id in global_attrs: + return f"Attribute {GlobalAttributeIds(attribute_id).to_name()} {attribute_id}, 0x{attribute_id:04X}" mapping = self._mapping._CLUSTER_ID_DICT.get(cluster_id, None) if not mapping: return f"Attribute Unknown ({attribute_id}, 0x{attribute_id:08X})" @@ -1014,16 +1018,24 @@ def skip_step(self, step): self.step(step) self.mark_current_step_skipped() - def skip_all_remaining_steps(self, starting_step): + def skip_all_remaining_steps(self, starting_step_number): ''' Skips all remaining test steps starting with provided starting step - starting_step must be provided, and is not derived intentionally. By providing argument + starting_step_number gives the first step to be skipped, as defined in the TestStep.test_plan_number + starting_step_number must be provided, and is not derived intentionally. By providing argument test is more deliberately identifying where test skips are starting from, making it easier to validate against the test plan for correctness. ''' - last_step = len(self.get_test_steps(self.current_test_info.name)) + 1 - for index in range(starting_step, last_step): - self.skip_step(index) + steps = self.get_test_steps(self.current_test_info.name) + for idx, step in enumerate(steps): + if step.test_plan_number == starting_step_number: + starting_step_idx = idx + break + else: + asserts.fail("skip_all_remaining_steps was provided with invalid starting_step_num") + remaining = steps[starting_step_idx:] + for step in remaining: + self.skip_step(step.test_plan_number) def step(self, step: typing.Union[int, str]): test_name = self.current_test_info.name diff --git a/src/python_testing/spec_parsing_support.py b/src/python_testing/spec_parsing_support.py index c58f38e9a5ac89..6a9d1f87ae3442 100644 --- a/src/python_testing/spec_parsing_support.py +++ b/src/python_testing/spec_parsing_support.py @@ -76,6 +76,7 @@ def __str__(self): @dataclass class XmlCommand: + id: int name: str conformance: Callable[[uint], ConformanceDecision] @@ -100,6 +101,7 @@ class XmlCluster: attributes: dict[uint, XmlAttribute] accepted_commands: dict[uint, XmlCommand] generated_commands: dict[uint, XmlCommand] + unknown_commands: list[XmlCommand] events: dict[uint, XmlEvent] pics: str @@ -107,6 +109,35 @@ class XmlCluster: class CommandType(Enum): ACCEPTED = auto() GENERATED = auto() + # This will happen for derived clusters, where the direction isn't noted. On normal clusters, this is a problem. + UNKNOWN = auto() + + +# workaround for aliased clusters not appearing in the xml. Remove this once https://github.com/csa-data-model/projects/issues/373 is addressed +CONC_CLUSTERS = {0x040C: ('Carbon Monoxide Concentration Measurement', 'CMOCONC'), + 0x040D: ('Carbon Dioxide Concentration Measurement', 'CDOCONC'), + 0x0413: ('Nitrogen Dioxide Concentration Measurement', 'NDOCONC'), + 0x0415: ('Ozone Concentration Measurement', 'OZCONC'), + 0x042A: ('PM2.5 Concentration Measurement', 'PMICONC'), + 0x042B: ('Formaldehyde Concentration Measurement', 'FLDCONC'), + 0x042C: ('PM1 Concentration Measurement', 'PMHCONC'), + 0x042D: ('PM10 Concentration Measurement', 'PMKCONC'), + 0x042E: ('Total Volatile Organic Compounds Concentration Measurement', 'TVOCCONC'), + 0x042F: ('Radon Concentration Measurement', 'RNCONC')} +CONC_BASE_NAME = 'Concentration Measurement Clusters' +RESOURCE_CLUSTERS = {0x0071: ('HEPA Filter Monitoring', 'HEPAFREMON'), + 0x0072: ('Activated Carbon Filter Monitoring', 'ACFREMON')} +RESOURCE_BASE_NAME = 'Resource Monitoring Clusters' +WATER_CLUSTER = {0x0405: ('Relative Humidity Measurement', 'RH')} +WATER_BASE_NAME = 'Water Content Measurement Clusters' +CLUSTER_ALIASES = {CONC_BASE_NAME: CONC_CLUSTERS, RESOURCE_BASE_NAME: RESOURCE_CLUSTERS, WATER_BASE_NAME: WATER_CLUSTER} + + +def is_alias(id: uint): + for base, alias in CLUSTER_ALIASES.items(): + if id in alias: + return True + return False class ClusterParser: @@ -317,17 +348,32 @@ def parse_attributes(self) -> dict[uint, XmlAttribute]: ), read_access=Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kView, write_access=Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kUnknownEnumValue, write_optional=False) return attributes - def parse_commands(self, command_type: CommandType) -> dict[uint, XmlAttribute]: - commands = {} + def get_command_type(self, element: ElementTree.Element) -> CommandType: + try: + if element.attrib['direction'].lower() == 'responsefromserver': + return CommandType.GENERATED + if element.attrib['direction'].lower() == 'commandtoclient': + return CommandType.UNKNOWN + if element.attrib['direction'].lower() == 'commandtoserver': + return CommandType.ACCEPTED + raise Exception(f"Unknown direction: {element.attrib['direction']}") + except KeyError: + return CommandType.ACCEPTED + + def parse_unknown_commands(self) -> list[XmlCommand]: + commands = [] for element, conformance_xml, access_xml in self.command_elements: + if self.get_command_type(element) != CommandType.UNKNOWN: + continue code = int(element.attrib['id'], 0) - dir = CommandType.ACCEPTED - try: - if element.attrib['direction'].lower() == 'responsefromserver': - dir = CommandType.GENERATED - except KeyError: - pass - if dir != command_type: + conformance = self.parse_conformance(conformance_xml) + commands.append(XmlCommand(id=code, name=element.attrib['name'], conformance=conformance)) + return commands + + def parse_commands(self, command_type: CommandType) -> dict[uint, XmlCommand]: + commands = {} + for element, conformance_xml, access_xml in self.command_elements: + if self.get_command_type(element) != command_type: continue code = int(element.attrib['id'], 0) conformance = self.parse_conformance(conformance_xml) @@ -335,7 +381,7 @@ def parse_commands(self, command_type: CommandType) -> dict[uint, XmlAttribute]: continue if code in commands: conformance = or_operation([conformance, commands[code].conformance]) - commands[code] = XmlCommand(name=element.attrib['name'], conformance=conformance) + commands[code] = XmlCommand(id=code, name=element.attrib['name'], conformance=conformance) return commands def parse_events(self) -> dict[uint, XmlAttribute]: @@ -362,96 +408,71 @@ def create_cluster(self) -> XmlCluster: attributes=self.parse_attributes(), accepted_commands=self.parse_commands(CommandType.ACCEPTED), generated_commands=self.parse_commands(CommandType.GENERATED), + unknown_commands=self.parse_unknown_commands(), events=self.parse_events(), pics=self._pics) def get_problems(self) -> list[ProblemNotice]: return self._problems -def build_xml_clusters() -> tuple[list[XmlCluster], list[ProblemNotice]]: - # workaround for aliased clusters not appearing in the xml. Remove this once https://github.com/csa-data-model/projects/issues/373 is addressed - conc_clusters = {0x040C: ('Carbon Monoxide Concentration Measurement', 'CMOCONC'), - 0x040D: ('Carbon Dioxide Concentration Measurement', 'CDOCONC'), - 0x0413: ('Nitrogen Dioxide Concentration Measurement', 'NDOCONC'), - 0x0415: ('Ozone Concentration Measurement', 'OZCONC'), - 0x042A: ('PM2.5 Concentration Measurement', 'PMICONC'), - 0x042B: ('Formaldehyde Concentration Measurement', 'FLDCONC'), - 0x042C: ('PM1 Concentration Measurement', 'PMHCONC'), - 0x042D: ('PM10 Concentration Measurement', 'PMKCONC'), - 0x042E: ('Total Volatile Organic Compounds Concentration Measurement', 'TVOCCONC'), - 0x042F: ('Radon Concentration Measurement', 'RNCONC')} - conc_base_name = 'Concentration Measurement Clusters' - resource_clusters = {0x0071: ('HEPA Filter Monitoring', 'HEPAFREMON'), - 0x0072: ('Activated Carbon Filter Monitoring', 'ACFREMON')} - resource_base_name = 'Resource Monitoring Clusters' - water_clusters = {0x0405: ('Relative Humidity Measurement', 'RH')} - water_base_name = 'Water Content Measurement Clusters' - aliases = {conc_base_name: conc_clusters, resource_base_name: resource_clusters, water_base_name: water_clusters} - - def is_alias(id: uint): - for base, alias in aliases.items(): - if id in alias: - return True - return False +def add_cluster_data_from_xml(xml: ElementTree.Element, clusters: dict[int, XmlCluster], pure_base_clusters: dict[str, XmlCluster], ids_by_name: dict[str, int], problems: list[ProblemNotice]) -> None: + ''' Adds cluster data to the supplied dicts as appropriate + + xml: XML element read from from the XML cluster file + clusters: dict of id -> XmlCluster. This function will append new clusters as appropriate to this dict. + pure_base_clusters: dict of base name -> XmlCluster. This data structure is used to hold pure base clusters that don't have + an ID. This function will append new pure base clusters as approrpriate to this dict. + ids_by_name: dict of cluster name -> ID. This function will append new IDs as appropriate to this dict. + problems: list of any problems encountered during spec parsing. This function will append problems as appropriate to this list. + ''' + cluster = xml.iter('cluster') + for c in cluster: + name = c.attrib['name'] + if not c.attrib['id']: + # Fully derived clusters have no id, but also shouldn't appear on a device. + # We do need to keep them, though, because we need to update the derived + # clusters. We keep them in a special dict by name, so they can be thrown + # away later. + cluster_id = None + else: + cluster_id = int(c.attrib['id'], 0) + ids_by_name[name] = cluster_id - def combine_attributes(base: dict[uint, XmlAttribute], derived: dict[uint, XmlAttribute], cluster_id: uint) -> dict[uint, XmlAttribute]: - ret = deepcopy(base) - extras = {k: v for k, v in derived.items() if k not in base.keys()} - overrides = {k: v for k, v in derived.items() if k in base.keys()} - ret.update(extras) - for id, override in overrides.items(): - if override.conformance: - ret[id].conformance = override.conformance - if override.read_access: - ret[id].read_access = override.read_access - if override.write_access: - ret[id].write_access = override.write_access - if ret[id].read_access is None and ret[id].write_access is None: - location = AttributePathLocation(endpoint_id=0, cluster_id=cluster_id, attribute_id=id) - problems.append(ProblemNotice(test_name='Spec XML parsing', location=location, - severity=ProblemSeverity.WARNING, problem='Unable to find access element')) - if ret[id].read_access is None: - ret[id].read_access == Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kUnknownEnumValue - if ret[id].write_access is None: - ret[id].write_access = Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kUnknownEnumValue - return ret + parser = ClusterParser(c, cluster_id, name, is_alias(cluster_id)) + new = parser.create_cluster() + problems = problems + parser.get_problems() + + if cluster_id: + clusters[cluster_id] = new + else: + pure_base_clusters[name] = new + + +def check_clusters_for_unknown_commands(clusters: dict[int, XmlCluster], problems: list[ProblemNotice]): + for id, cluster in clusters.items(): + for cmd in cluster.unknown_commands: + problems.append(ProblemNotice(test_name="Spec XML parsing", location=CommandPathLocation( + endpoint_id=0, cluster_id=id, command_id=cmd.id), severity=ProblemSeverity.WARNING, problem="Command with unknown direction")) + +def build_xml_clusters() -> tuple[list[XmlCluster], list[ProblemNotice]]: dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', '..', 'data_model', 'clusters') clusters: dict[int, XmlCluster] = {} - derived_clusters: dict[str, XmlCluster] = {} - ids_by_name = {} - problems = [] + pure_base_clusters: dict[str, XmlCluster] = {} + ids_by_name: dict[str, int] = {} + problems: list[ProblemNotice] = [] for xml in glob.glob(f"{dir}/*.xml"): logging.info(f'Parsing file {xml}') tree = ElementTree.parse(f'{xml}') root = tree.getroot() - cluster = root.iter('cluster') - for c in cluster: - name = c.attrib['name'] - if not c.attrib['id']: - # Fully derived clusters have no id, but also shouldn't appear on a device. - # We do need to keep them, though, because we need to update the derived - # clusters. We keep them in a special dict by name, so they can be thrown - # away later. - cluster_id = None - else: - cluster_id = int(c.attrib['id'], 0) - ids_by_name[name] = cluster_id - - parser = ClusterParser(c, cluster_id, name, is_alias(cluster_id)) - new = parser.create_cluster() - problems = problems + parser.get_problems() - - if cluster_id: - clusters[cluster_id] = new - else: - derived_clusters[name] = new + add_cluster_data_from_xml(root, clusters, pure_base_clusters, ids_by_name, problems) # There are a few clusters where the conformance columns are listed as desc. These clusters need specific, targeted tests # to properly assess conformance. Here, we list them as Optional to allow these for the general test. Targeted tests are described below. # Descriptor - TagList feature - this feature is mandated when the duplicate condition holds for the endpoint. It is tested in DESC-2.2 # Actions cluster - all commands - these need to be listed in the ActionsList attribute to be supported. # We do not currently have a test for this. Please see https://github.com/CHIP-Specifications/chip-test-plans/issues/3646. + def remove_problem(location: typing.Union[CommandPathLocation, FeaturePathLocation]): nonlocal problems problems = [p for p in problems if p.location != location] @@ -466,40 +487,11 @@ def remove_problem(location: typing.Union[CommandPathLocation, FeaturePathLocati clusters[action_id].accepted_commands[c].conformance = optional() remove_problem(CommandPathLocation(endpoint_id=0, cluster_id=action_id, command_id=c)) - # We have the information now about which clusters are derived, so we need to fix them up. Apply first the base cluster, - # then add the specific cluster overtop - for id, c in clusters.items(): - if c.derived: - base_name = c.derived - if base_name in ids_by_name: - base = clusters[ids_by_name[c.derived]] - else: - base = derived_clusters[base_name] + combine_derived_clusters_with_base(clusters, pure_base_clusters, ids_by_name) - feature_map = deepcopy(base.feature_map) - feature_map.update(c.feature_map) - attribute_map = deepcopy(base.attribute_map) - attribute_map.update(c.attribute_map) - command_map = deepcopy(base.command_map) - command_map.update(c.command_map) - features = deepcopy(base.features) - features.update(c.features) - attributes = combine_attributes(base.attributes, c.attributes, id) - accepted_commands = deepcopy(base.accepted_commands) - accepted_commands.update(c.accepted_commands) - generated_commands = deepcopy(base.generated_commands) - generated_commands.update(c.generated_commands) - events = deepcopy(base.events) - events.update(c.events) - new = XmlCluster(revision=c.revision, derived=c.derived, name=c.name, - feature_map=feature_map, attribute_map=attribute_map, command_map=command_map, - features=features, attributes=attributes, accepted_commands=accepted_commands, - generated_commands=generated_commands, events=events, pics=c.pics) - clusters[id] = new - - for alias_base_name, aliased_clusters in aliases.items(): + for alias_base_name, aliased_clusters in CLUSTER_ALIASES.items(): for id, (alias_name, pics) in aliased_clusters.items(): - base = derived_clusters[alias_base_name] + base = pure_base_clusters[alias_base_name] new = deepcopy(base) new.derived = alias_base_name new.name = alias_name @@ -507,6 +499,33 @@ def remove_problem(location: typing.Union[CommandPathLocation, FeaturePathLocati clusters[id] = new # TODO: All these fixups should be removed BEFORE SVE if at all possible + # Workaround for Color Control cluster - the spec uses a non-standard conformance. Set all to optional now, will need + # to implement either arithmetic conformance handling (once spec changes land here) or specific test + # https://github.com/CHIP-Specifications/connectedhomeip-spec/pull/7808 for spec changes. + # see 3.2.8. Defined Primaries Information Attribute Set, affects Primary<#>X/Y/Intensity attributes. + cc_id = Clusters.ColorControl.id + cc_attr = Clusters.ColorControl.Attributes + affected_attributes = [cc_attr.Primary1X, + cc_attr.Primary1Y, + cc_attr.Primary1Intensity, + cc_attr.Primary2X, + cc_attr.Primary2Y, + cc_attr.Primary2Intensity, + cc_attr.Primary3X, + cc_attr.Primary3Y, + cc_attr.Primary3Intensity, + cc_attr.Primary4X, + cc_attr.Primary4Y, + cc_attr.Primary4Intensity, + cc_attr.Primary5X, + cc_attr.Primary5Y, + cc_attr.Primary5Intensity, + cc_attr.Primary6X, + cc_attr.Primary6Y, + cc_attr.Primary6Intensity, + ] + for a in affected_attributes: + clusters[cc_id].attributes[a.attribute_id].conformance = optional() # Workaround for temp control cluster - this is parsed incorrectly in the DM XML and is missing all its attributes # Remove this workaround when https://github.com/csa-data-model/projects/issues/330 is fixed @@ -523,10 +542,72 @@ def remove_problem(location: typing.Union[CommandPathLocation, FeaturePathLocati 0x05: XmlAttribute(name='SupportedTemperatureLevels', datatype='list', conformance=feature(0x02, 'TL'), read_access=view, write_access=none, write_optional=False), } - # Workaround for incorrect parsing of access control cluster. - # Remove this workaround when https://github.com/csa-data-model/projects/issues/397 is fixed. - acl_id = Clusters.AccessControl.id - clusters[acl_id].attributes[Clusters.AccessControl.Attributes.Acl.attribute_id].write_access = Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kAdminister - clusters[acl_id].attributes[Clusters.AccessControl.Attributes.Extension.attribute_id].write_access = Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kAdminister + check_clusters_for_unknown_commands(clusters, problems) return clusters, problems + + +def combine_derived_clusters_with_base(xml_clusters: dict[int, XmlCluster], pure_base_clusters: dict[str, XmlCluster], ids_by_name: dict[str, int]) -> None: + ''' Overrides base elements with the derived cluster values for derived clusters. ''' + + def combine_attributes(base: dict[uint, XmlAttribute], derived: dict[uint, XmlAttribute], cluster_id: uint) -> dict[uint, XmlAttribute]: + ret = deepcopy(base) + extras = {k: v for k, v in derived.items() if k not in base.keys()} + overrides = {k: v for k, v in derived.items() if k in base.keys()} + ret.update(extras) + for id, override in overrides.items(): + if override.conformance: + ret[id].conformance = override.conformance + if override.read_access: + ret[id].read_access = override.read_access + if override.write_access: + ret[id].write_access = override.write_access + if ret[id].read_access is None and ret[id].write_access is None: + location = AttributePathLocation(endpoint_id=0, cluster_id=cluster_id, attribute_id=id) + problems.append(ProblemNotice(test_name='Spec XML parsing', location=location, + severity=ProblemSeverity.WARNING, problem='Unable to find access element')) + if ret[id].read_access is None: + ret[id].read_access == Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kUnknownEnumValue + if ret[id].write_access is None: + ret[id].write_access = Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kUnknownEnumValue + return ret + + # We have the information now about which clusters are derived, so we need to fix them up. Apply first the base cluster, + # then add the specific cluster overtop + for id, c in xml_clusters.items(): + if c.derived: + base_name = c.derived + if base_name in ids_by_name: + base = xml_clusters[ids_by_name[c.derived]] + else: + base = pure_base_clusters[base_name] + + feature_map = deepcopy(base.feature_map) + feature_map.update(c.feature_map) + attribute_map = deepcopy(base.attribute_map) + attribute_map.update(c.attribute_map) + command_map = deepcopy(base.command_map) + command_map.update(c.command_map) + features = deepcopy(base.features) + features.update(c.features) + attributes = combine_attributes(base.attributes, c.attributes, id) + accepted_commands = deepcopy(base.accepted_commands) + accepted_commands.update(c.accepted_commands) + generated_commands = deepcopy(base.generated_commands) + generated_commands.update(c.generated_commands) + events = deepcopy(base.events) + events.update(c.events) + unknown_commands = deepcopy(base.unknown_commands) + for cmd in c.unknown_commands: + if cmd.id in accepted_commands.keys() and cmd.name == accepted_commands[cmd.id].name: + accepted_commands[cmd.id].conformance = cmd.conformance + elif cmd.id in generated_commands.keys() and cmd.name == generated_commands[cmd.id].name: + generated_commands[cmd.id].conformance = cmd.conformance + else: + unknown_commands.append(cmd) + + new = XmlCluster(revision=c.revision, derived=c.derived, name=c.name, + feature_map=feature_map, attribute_map=attribute_map, command_map=command_map, + features=features, attributes=attributes, accepted_commands=accepted_commands, + generated_commands=generated_commands, unknown_commands=unknown_commands, events=events, pics=c.pics) + xml_clusters[id] = new diff --git a/src/transport/UnauthenticatedSessionTable.h b/src/transport/UnauthenticatedSessionTable.h index 48e2025d10a487..f5ba35df533de5 100644 --- a/src/transport/UnauthenticatedSessionTable.h +++ b/src/transport/UnauthenticatedSessionTable.h @@ -285,17 +285,26 @@ class UnauthenticatedSessionTable return CHIP_NO_ERROR; } -#if !CHIP_SYSTEM_CONFIG_POOL_USE_HEAP +#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP + // permanent failure if heap was insufficient + return CHIP_ERROR_NO_MEMORY; +#else entryToUse = FindLeastRecentUsedEntry(); -#endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP + VerifyOrReturnError(entryToUse != nullptr, CHIP_ERROR_NO_MEMORY); + + // Drop the least recent entry to allow for a new alloc. + mEntries.ReleaseObject(entryToUse); + entryToUse = mEntries.CreateObject(sessionRole, ephemeralInitiatorNodeID, config, *this); + if (entryToUse == nullptr) { - return CHIP_ERROR_NO_MEMORY; + // this is NOT expected: we freed an object to have space + return CHIP_ERROR_INTERNAL; } - mEntries.ResetObject(entryToUse, sessionRole, ephemeralInitiatorNodeID, config, *this); entry = entryToUse; return CHIP_NO_ERROR; +#endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP } CHECK_RETURN_VALUE UnauthenticatedSession * FindEntry(UnauthenticatedSession::SessionRole sessionRole, diff --git a/third_party/libwebsockets/repo b/third_party/libwebsockets/repo index 49bfef2ecd51b8..b71a6621b0b14b 160000 --- a/third_party/libwebsockets/repo +++ b/third_party/libwebsockets/repo @@ -1 +1 @@ -Subproject commit 49bfef2ecd51b854b63e35d913849b6bb518a7f6 +Subproject commit b71a6621b0b14bfc8fcbe804b036a9543af5e910 diff --git a/third_party/mbedtls/repo b/third_party/mbedtls/repo index ede909f99ab6e6..039c903e7b2882 160000 --- a/third_party/mbedtls/repo +++ b/third_party/mbedtls/repo @@ -1 +1 @@ -Subproject commit ede909f99ab6e6a958a41e365251c2a1d2c4ed4d +Subproject commit 039c903e7b2882af8e85ce5e090fd44e6a9d2289 diff --git a/third_party/openthread/repo b/third_party/openthread/repo index b212a0a748070c..33574ad4175ffb 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit b212a0a748070ccbda765c3ebed2aab8b6b08fce +Subproject commit 33574ad4175ffb088bcca047f4c8d5fb240d1495 diff --git a/third_party/ot-br-posix/repo b/third_party/ot-br-posix/repo index c5a7a35e3bd2f3..9bdaa9101663c2 160000 --- a/third_party/ot-br-posix/repo +++ b/third_party/ot-br-posix/repo @@ -1 +1 @@ -Subproject commit c5a7a35e3bd2f3da8cce1e2e2a3bbe5cdeedb729 +Subproject commit 9bdaa9101663c2ce9016fb5e2b5010442b17ca26 diff --git a/third_party/silabs/efr32_sdk.gni b/third_party/silabs/efr32_sdk.gni index bed0a1e43c308d..9868b47efb8a8d 100644 --- a/third_party/silabs/efr32_sdk.gni +++ b/third_party/silabs/efr32_sdk.gni @@ -916,11 +916,11 @@ template("efr32_sdk") { "${efr32_sdk_root}/platform/security/sl_component/sl_mbedtls_support/src/crypto_aes.c", "${efr32_sdk_root}/platform/security/sl_component/sl_protocol_crypto/src/sli_protocol_crypto_crypto.c", "${efr32_sdk_root}/platform/security/sl_component/sl_psa_driver/src/crypto_management.c", + "${efr32_sdk_root}/platform/security/sl_component/sl_psa_driver/src/sli_crypto_driver_trng.c", "${efr32_sdk_root}/platform/security/sl_component/sl_psa_driver/src/sli_crypto_transparent_driver_aead.c", "${efr32_sdk_root}/platform/security/sl_component/sl_psa_driver/src/sli_crypto_transparent_driver_cipher.c", "${efr32_sdk_root}/platform/security/sl_component/sl_psa_driver/src/sli_crypto_transparent_driver_hash.c", "${efr32_sdk_root}/platform/security/sl_component/sl_psa_driver/src/sli_crypto_transparent_driver_mac.c", - "${efr32_sdk_root}/platform/security/sl_component/sl_psa_driver/src/sli_crypto_trng_driver.c", "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_dcdc_s1.c", "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_emu_s1.c", "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_hfxo_s1.c", diff --git a/third_party/silabs/gecko_sdk b/third_party/silabs/gecko_sdk index 124fa19de8c8b3..911f6cdefccbae 160000 --- a/third_party/silabs/gecko_sdk +++ b/third_party/silabs/gecko_sdk @@ -1 +1 @@ -Subproject commit 124fa19de8c8b3961d21c20857f7df32239786da +Subproject commit 911f6cdefccbae03bc66e8c790ceb7e67ca07417 diff --git a/third_party/silabs/matter_support b/third_party/silabs/matter_support index 70800e2f6d5fbc..53f098de9fdc7d 160000 --- a/third_party/silabs/matter_support +++ b/third_party/silabs/matter_support @@ -1 +1 @@ -Subproject commit 70800e2f6d5fbc972d22387fd4969a92568b455b +Subproject commit 53f098de9fdc7db248a72eabbe07d8ce4876daab diff --git a/third_party/silabs/wifi_sdk b/third_party/silabs/wifi_sdk index a63c4cd9c4d5cc..00dd57a85e0982 160000 --- a/third_party/silabs/wifi_sdk +++ b/third_party/silabs/wifi_sdk @@ -1 +1 @@ -Subproject commit a63c4cd9c4d5cc63c0d8c6d89c35c0891fc47bf8 +Subproject commit 00dd57a85e0982f85a41d029e15050479f69256b 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 686147de371a61..a3e74424d0768b 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 @@ -10726,38 +10726,6 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t valu namespace PowerTopology { namespace Attributes { -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::PowerTopology::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) -{ - 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::PowerTopology::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE); -} - -} // namespace FeatureMap - namespace ClusterRevision { Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint16_t * value) 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 fe7cc9a9c4922d..51e19658e9d99d 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 @@ -2113,11 +2113,6 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t valu namespace PowerTopology { namespace Attributes { -namespace FeatureMap { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint32_t * value); // bitmap32 -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value); -} // 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);