diff --git a/.github/workflows/darwin.yaml b/.github/workflows/darwin.yaml index a58617131a035d..2662853b1f790b 100644 --- a/.github/workflows/darwin.yaml +++ b/.github/workflows/darwin.yaml @@ -103,7 +103,8 @@ jobs: # target versions instead? run: | mkdir -p /tmp/darwin/framework-tests - ../../../out/debug/chip-all-clusters-app --interface-id -1 > >(tee /tmp/darwin/framework-tests/all-cluster-app.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-err.log >&2) & + echo "This is a simple log" > /tmp/darwin/framework-tests/end_user_support_log.txt + ../../../out/debug/chip-all-clusters-app --interface-id -1 --end_user_support_log /tmp/darwin/framework-tests/end_user_support_log.txt > >(tee /tmp/darwin/framework-tests/all-cluster-app.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-err.log >&2) & ../../../out/debug/chip-all-clusters-app --interface-id -1 --dac_provider ../../../credentials/development/commissioner_dut/struct_cd_origin_pid_vid_correct/test_case_vector.json --product-id 32768 --discriminator 3839 --secured-device-port 5539 --KVS /tmp/chip-all-clusters-app-kvs2 > >(tee /tmp/darwin/framework-tests/all-cluster-app-origin-vid.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-origin-vid-err.log >&2) & # Disable BLE (CHIP_IS_BLE=NO) because the app does not have the permission to use it and that may crash the CI. diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 69613217033e8b..e0255646dbc487 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -114,7 +114,6 @@ jobs: --known-failure app/util/attribute-table.h \ --known-failure app/util/binding-table.cpp \ --known-failure app/util/binding-table.h \ - --known-failure app/util/common.h \ --known-failure app/util/config.h \ --known-failure app/util/DataModelHandler.cpp \ --known-failure app/util/DataModelHandler.h \ diff --git a/build/chip/chip_codegen.gni b/build/chip/chip_codegen.gni index 02acd08150aae8..08d9f17da6c1be 100644 --- a/build/chip/chip_codegen.gni +++ b/build/chip/chip_codegen.gni @@ -152,7 +152,7 @@ template("_chip_build_time_zapgen") { _output_subdir = "zap-generated" } - pw_python_action("${_name}_zap_pregen") { + pw_python_action("${_name}_zap") { script = "${chip_root}/scripts/tools/zap/generate.py" # TODO: this seems to touch internals. Is this ok? speeds up builds! @@ -165,7 +165,7 @@ template("_chip_build_time_zapgen") { "--templates", _template_path, "--output-dir", - rebase_path(target_gen_dir) + "/zap_pregen/" + _output_subdir, + rebase_path(target_gen_dir) + "/zapgen/" + _output_subdir, # TODO: lock file support should be removed as this serializes zap # (slower), however this is currently done because on Darwin zap startup @@ -188,54 +188,10 @@ template("_chip_build_time_zapgen") { sources = [ _idl_file ] - outputs = [] - foreach(name, invoker.outputs) { - outputs += [ "${target_gen_dir}/zap_pregen/${name}" ] - } - - forward_variables_from(invoker, [ "prune_outputs" ]) - if (defined(prune_outputs)) { - foreach(name, prune_outputs) { - outputs += [ "${target_gen_dir}/zap_pregen/${name}" ] - } - } - } - - # This action ensures that any "extra" files generated by zap codegen - # are actually deleted. - # - # This is to avoid double-codegen of configurations like endpoint config - # or access credentials being generated for both "controller client" and - # application-specific - pw_python_action("${_name}_files") { - # TODO: this seems to touch internals. Is this ok? speeds up builds! - _pw_internal_run_in_venv = false - - script = "${chip_root}/scripts/tools/zap/prune_outputs.py" - - _keep_file = rebase_path("${target_gen_dir}/${_name}.keep.outputs") - write_file(_keep_file, invoker.outputs, "list lines") - - args = [ - "--keep", - _keep_file, - "--input-dir", - rebase_path("${target_gen_dir}/zap_pregen/"), - "--output-dir", - rebase_path("${target_gen_dir}/zapgen/"), - ] - - inputs = [] - foreach(name, invoker.outputs) { - inputs += [ "${target_gen_dir}/zap_pregen/${name}" ] - } - outputs = [] foreach(name, invoker.outputs) { outputs += [ "${target_gen_dir}/zapgen/${name}" ] } - - deps = [ ":${_name}_zap_pregen" ] } source_set(_name) { @@ -255,10 +211,7 @@ template("_chip_build_time_zapgen") { if (!defined(public_deps)) { public_deps = [] } - public_deps += [ - ":${_name}_files", - ":${_name}_zap_pregen", - ] + public_deps += [ ":${_name}_zap" ] } } @@ -420,7 +373,6 @@ template("chip_zapgen") { "input", "outputs", "public_configs", - "prune_outputs", ]) } } else { @@ -482,7 +434,6 @@ template("chip_zapgen") { [ "deps", "public_configs", - "prune_outputs", ]) if (!defined(public_configs)) { public_configs = [] diff --git a/examples/air-quality-sensor-app/linux/README.md b/examples/air-quality-sensor-app/linux/README.md index 73139ef4aeeacb..38a0adfb2fe7bf 100644 --- a/examples/air-quality-sensor-app/linux/README.md +++ b/examples/air-quality-sensor-app/linux/README.md @@ -165,3 +165,21 @@ value. ``` $ echo '{"Name":"NitrogenDioxideConcentrationMeasurement","NewValue":1}' > /tmp/chip_air_quality_fifo_ ``` + +Generate event `Pm1ConcentrationMeasurement`, to change the PM1 value. + +``` +echo '{"Name":"Pm1ConcentrationMeasurement","NewValue":1}' > /tmp/chip_air_quality_fifo_ +``` + +Generate event `Pm25ConcentrationMeasurement`, to change the PM2.5 value. + +``` +echo '{"Name":"Pm25ConcentrationMeasurement","NewValue":2.5}' > /tmp/chip_air_quality_fifo_ +``` + +Generate event `Pm10ConcentrationMeasurement`, to change the PM10 value. + +``` +echo '{"Name":"Pm10ConcentrationMeasurement","NewValue":10}' > /tmp/chip_air_quality_fifo_ +``` diff --git a/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter b/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter index 9a6eeb77ef10f2..fa6101b2586a63 100644 --- a/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter +++ b/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter @@ -1337,6 +1337,10 @@ cluster IcdManagement = 70 { optional octet_string<16> verificationKey = 1; } + request struct StayActiveRequestRequest { + int32u stayActiveDuration = 0; + } + response struct StayActiveResponse = 4 { int32u promisedActiveDuration = 0; } @@ -1346,7 +1350,7 @@ cluster IcdManagement = 70 { /** Unregister a client from an end device */ fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2; /** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ - command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3; + command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3; } endpoint 0 { diff --git a/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter b/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter index 479f8baa86284c..f82f6a9ea079d4 100644 --- a/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter +++ b/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter @@ -1337,6 +1337,10 @@ cluster IcdManagement = 70 { optional octet_string<16> verificationKey = 1; } + request struct StayActiveRequestRequest { + int32u stayActiveDuration = 0; + } + response struct StayActiveResponse = 4 { int32u promisedActiveDuration = 0; } @@ -1346,7 +1350,7 @@ cluster IcdManagement = 70 { /** Unregister a client from an end device */ fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2; /** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ - command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3; + command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3; } endpoint 0 { diff --git a/examples/darwin-framework-tool/commands/bdx/DownloadLogCommand.mm b/examples/darwin-framework-tool/commands/bdx/DownloadLogCommand.mm index b105b6cb3098c8..dd693b4358304b 100644 --- a/examples/darwin-framework-tool/commands/bdx/DownloadLogCommand.mm +++ b/examples/darwin-framework-tool/commands/bdx/DownloadLogCommand.mm @@ -28,7 +28,7 @@ ChipLogProgress(chipTool, "Downloading logs from node 0x" ChipLogFormatX64, ChipLogValueX64(mNodeId)); MTRDeviceController * commissioner = CurrentCommissioner(); - auto * device = [MTRDevice deviceWithNodeID:@(mNodeId) controller:commissioner]; + auto * device = [MTRBaseDevice deviceWithNodeID:@(mNodeId) controller:commissioner]; auto logType = static_cast(mLogType); auto queue = dispatch_queue_create("com.chip.bdx.downloader", DISPATCH_QUEUE_SERIAL); diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.matter b/examples/light-switch-app/light-switch-common/light-switch-app.matter index 87dc1a68cfc2fd..0e59f3fb3eef6b 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/light-switch-app.matter @@ -2033,6 +2033,10 @@ cluster IcdManagement = 70 { optional octet_string<16> verificationKey = 1; } + request struct StayActiveRequestRequest { + int32u stayActiveDuration = 0; + } + response struct StayActiveResponse = 4 { int32u promisedActiveDuration = 0; } @@ -2042,7 +2046,7 @@ cluster IcdManagement = 70 { /** Unregister a client from an end device */ fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2; /** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ - command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3; + command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3; } /** Attributes and commands for scene configuration and manipulation. */ diff --git a/examples/light-switch-app/qpg/zap/switch.matter b/examples/light-switch-app/qpg/zap/switch.matter index b7f217d7221b27..0475721b798fe9 100644 --- a/examples/light-switch-app/qpg/zap/switch.matter +++ b/examples/light-switch-app/qpg/zap/switch.matter @@ -1804,6 +1804,10 @@ cluster IcdManagement = 70 { optional octet_string<16> verificationKey = 1; } + request struct StayActiveRequestRequest { + int32u stayActiveDuration = 0; + } + response struct StayActiveResponse = 4 { int32u promisedActiveDuration = 0; } @@ -1813,7 +1817,7 @@ cluster IcdManagement = 70 { /** Unregister a client from an end device */ fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2; /** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ - command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3; + command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3; } /** Attributes and commands for scene configuration and manipulation. */ diff --git a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter index db80008fef240c..d4b7f3faa245db 100644 --- a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter +++ b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter @@ -1465,6 +1465,10 @@ cluster IcdManagement = 70 { optional octet_string<16> verificationKey = 1; } + request struct StayActiveRequestRequest { + int32u stayActiveDuration = 0; + } + response struct StayActiveResponse = 4 { int32u promisedActiveDuration = 0; } @@ -1474,7 +1478,7 @@ cluster IcdManagement = 70 { /** Unregister a client from an end device */ fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2; /** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ - command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3; + command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3; } endpoint 0 { diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter index 222407b69fb770..d3299627a944b5 100644 --- a/examples/lock-app/lock-common/lock-app.matter +++ b/examples/lock-app/lock-common/lock-app.matter @@ -1869,6 +1869,10 @@ cluster IcdManagement = 70 { optional octet_string<16> verificationKey = 1; } + request struct StayActiveRequestRequest { + int32u stayActiveDuration = 0; + } + response struct StayActiveResponse = 4 { int32u promisedActiveDuration = 0; } @@ -1878,7 +1882,7 @@ cluster IcdManagement = 70 { /** Unregister a client from an end device */ fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2; /** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ - command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3; + command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3; } /** An interface to a generic way to secure a door */ diff --git a/examples/lock-app/lock-common/lock-app.zap b/examples/lock-app/lock-common/lock-app.zap index e8d8441af39797..3f264bb7237148 100644 --- a/examples/lock-app/lock-common/lock-app.zap +++ b/examples/lock-app/lock-common/lock-app.zap @@ -5069,6 +5069,7 @@ "define": "ICD_MANAGEMENT_CLUSTER", "side": "server", "enabled": 1, + "commands": [], "attributes": [ { "name": "IdleModeDuration", diff --git a/examples/lock-app/qpg/zap/lock.matter b/examples/lock-app/qpg/zap/lock.matter index 91ff76970813f1..9815defa7f8cef 100644 --- a/examples/lock-app/qpg/zap/lock.matter +++ b/examples/lock-app/qpg/zap/lock.matter @@ -1481,6 +1481,10 @@ cluster IcdManagement = 70 { optional octet_string<16> verificationKey = 1; } + request struct StayActiveRequestRequest { + int32u stayActiveDuration = 0; + } + response struct StayActiveResponse = 4 { int32u promisedActiveDuration = 0; } @@ -1490,7 +1494,7 @@ cluster IcdManagement = 70 { /** Unregister a client from an end device */ fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2; /** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ - command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3; + command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3; } /** An interface to a generic way to secure a door */ diff --git a/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter b/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter index 6c1938c578ea27..f3188350035291 100644 --- a/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter +++ b/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter @@ -1801,6 +1801,10 @@ cluster IcdManagement = 70 { optional octet_string<16> verificationKey = 1; } + request struct StayActiveRequestRequest { + int32u stayActiveDuration = 0; + } + response struct StayActiveResponse = 4 { int32u promisedActiveDuration = 0; } @@ -1810,7 +1814,7 @@ cluster IcdManagement = 70 { /** Unregister a client from an end device */ fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2; /** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ - command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3; + command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3; } /** This cluster provides an interface for observing and managing the state of smoke and CO alarms. */ diff --git a/examples/thermostat/qpg/src/ThermostaticRadiatorValveManager.cpp b/examples/thermostat/qpg/src/ThermostaticRadiatorValveManager.cpp index 55173272977964..a7375d54dc45ac 100644 --- a/examples/thermostat/qpg/src/ThermostaticRadiatorValveManager.cpp +++ b/examples/thermostat/qpg/src/ThermostaticRadiatorValveManager.cpp @@ -23,7 +23,7 @@ #include "AppConfig.h" #include "AppTask.h" -#include "app/util/common.h" + #include #include diff --git a/examples/window-app/common/window-app.matter b/examples/window-app/common/window-app.matter index 84cc4ebf51304b..3230589afd72ed 100644 --- a/examples/window-app/common/window-app.matter +++ b/examples/window-app/common/window-app.matter @@ -1899,6 +1899,10 @@ cluster IcdManagement = 70 { optional octet_string<16> verificationKey = 1; } + request struct StayActiveRequestRequest { + int32u stayActiveDuration = 0; + } + response struct StayActiveResponse = 4 { int32u promisedActiveDuration = 0; } @@ -1908,7 +1912,7 @@ cluster IcdManagement = 70 { /** Unregister a client from an end device */ fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2; /** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ - command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3; + command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3; } /** Provides an interface for controlling and adjusting automatic window coverings. */ diff --git a/integrations/docker/images/base/chip-build/version b/integrations/docker/images/base/chip-build/version index 7c7cf32a71a021..fe142046be7c1c 100644 --- a/integrations/docker/images/base/chip-build/version +++ b/integrations/docker/images/base/chip-build/version @@ -1 +1 @@ -37 : [NXP] Update Docker image for RW61X SDK +38 : [NXP] Update Docker image for K32W1 SDK diff --git a/integrations/docker/images/stage-2/chip-build-k32w/Dockerfile b/integrations/docker/images/stage-2/chip-build-k32w/Dockerfile index 309bc061d5fc20..908c882da75191 100644 --- a/integrations/docker/images/stage-2/chip-build-k32w/Dockerfile +++ b/integrations/docker/images/stage-2/chip-build-k32w/Dockerfile @@ -24,9 +24,9 @@ RUN set -x \ RUN set -x \ && mkdir -p k32w1 \ - && wget https://cache.nxp.com/lgfiles/bsps/SDK_2_12_6_K32W148-EVK.zip \ - && unzip SDK_2_12_6_K32W148-EVK.zip -d k32w1 \ - && rm -rf SDK_2_12_6_K32W148-EVK.zip + && wget https://cache.nxp.com/lgfiles/bsps/SDK_2_12_7_K32W148-EVK.zip \ + && unzip SDK_2_12_7_K32W148-EVK.zip -d k32w1 \ + && rm -rf SDK_2_12_7_K32W148-EVK.zip FROM ghcr.io/project-chip/chip-build:${VERSION} diff --git a/scripts/py_matter_yamltests/matter_yamltests/hooks.py b/scripts/py_matter_yamltests/matter_yamltests/hooks.py index 575a05d95871ad..9b202c7e94d122 100644 --- a/scripts/py_matter_yamltests/matter_yamltests/hooks.py +++ b/scripts/py_matter_yamltests/matter_yamltests/hooks.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import Optional + from .parser import TestStep @@ -213,6 +215,15 @@ async def step_manual(self): """ pass + def show_prompt(self, + msg: str, + placeholder: Optional[str] = None, + default_value: Optional[str] = None) -> None: + """ + This method is called when the step needs to ask the user to perform some action or provide some value. + """ + pass + class WebSocketRunnerHooks(): def connecting(self, url: str): diff --git a/scripts/tools/zap/prune_outputs.py b/scripts/tools/zap/prune_outputs.py deleted file mode 100644 index 09f92a9378ab33..00000000000000 --- a/scripts/tools/zap/prune_outputs.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2022 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 argparse -import os -import shutil - - -def main(): - parser = argparse.ArgumentParser( - description='Delete files based on an input file listing files to be removed') - - parser.add_argument('--keep', required=True, help="File containing names to keep (copy over)") - parser.add_argument('--output-dir', required=True, help="Output directory to copy files into") - parser.add_argument('--input-dir', required=True, help="Input directory to get the files from") - - args = parser.parse_args() - - with open(args.keep, "rt") as f: - for source in f.readlines(): - source = source.strip() - if not source: - continue - target = os.path.join(args.output_dir, source) - os.makedirs(os.path.dirname(target), exist_ok=True) - shutil.copyfile(os.path.join(args.input_dir, source), target) - - -if __name__ == '__main__': - main() diff --git a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h index 38f04fbfea5857..6985b44ac27da5 100644 --- a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h +++ b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h @@ -302,15 +302,15 @@ { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x7 }, /* ControlMode */ \ \ /* Endpoint: 1, Cluster: Thermostat (server) */ \ - { (uint16_t) 0xA28, (uint16_t) - 0x6AB3, (uint16_t) 0x7FFF }, /* OccupiedCoolingSetpoint */ \ - { (uint16_t) 0x7D0, (uint16_t) - 0x6AB3, (uint16_t) 0x7FFF }, /* OccupiedHeatingSetpoint */ \ - { (uint16_t) 0x2BC, (uint16_t) - 0x6AB3, (uint16_t) 0x7FFF }, /* MinHeatSetpointLimit */ \ - { (uint16_t) 0xBB8, (uint16_t) - 0x6AB3, (uint16_t) 0x7FFF }, /* MaxHeatSetpointLimit */ \ - { (uint16_t) 0x640, (uint16_t) - 0x6AB3, (uint16_t) 0x7FFF }, /* MinCoolSetpointLimit */ \ - { (uint16_t) 0xC80, (uint16_t) - 0x6AB3, (uint16_t) 0x7FFF }, /* MaxCoolSetpointLimit */ \ - { (uint16_t) 0x19, (uint16_t) 0x0, (uint16_t) 0x19 }, /* MinSetpointDeadBand */ \ - { (uint16_t) 0x4, (uint16_t) 0x0, (uint16_t) 0x5 }, /* ControlSequenceOfOperation */ \ - { (uint16_t) 0x1, (uint16_t) 0x0, (uint16_t) 0x9 }, /* SystemMode */ \ + { (uint16_t) 0xA28, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* OccupiedCoolingSetpoint */ \ + { (uint16_t) 0x7D0, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* OccupiedHeatingSetpoint */ \ + { (uint16_t) 0x2BC, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MinHeatSetpointLimit */ \ + { (uint16_t) 0xBB8, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MaxHeatSetpointLimit */ \ + { (uint16_t) 0x640, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MinCoolSetpointLimit */ \ + { (uint16_t) 0xC80, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MaxCoolSetpointLimit */ \ + { (uint16_t) 0x19, (uint16_t) 0x0, (uint16_t) 0x19 }, /* MinSetpointDeadBand */ \ + { (uint16_t) 0x4, (uint16_t) 0x0, (uint16_t) 0x5 }, /* ControlSequenceOfOperation */ \ + { (uint16_t) 0x1, (uint16_t) 0x0, (uint16_t) 0x9 }, /* SystemMode */ \ \ /* Endpoint: 1, Cluster: Fan Control (server) */ \ { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x6 }, /* FanMode */ \ @@ -334,14 +334,14 @@ { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* StartUpColorTemperatureMireds */ \ \ /* Endpoint: 1, Cluster: Unit Testing (server) */ \ - { (uint16_t) 0x46, (uint16_t) 0x14, (uint16_t) 0x64 }, /* range_restricted_int8u */ \ - { (uint16_t) - 0x14, (uint16_t) - 0x28, (uint16_t) 0x32 }, /* range_restricted_int8s */ \ - { (uint16_t) 0xC8, (uint16_t) 0x64, (uint16_t) 0x3E8 }, /* range_restricted_int16u */ \ - { (uint16_t) - 0x64, (uint16_t) - 0x96, (uint16_t) 0xC8 }, /* range_restricted_int16s */ \ - { (uint16_t) 0x46, (uint16_t) 0x14, (uint16_t) 0x64 }, /* nullable_range_restricted_int8u */ \ - { (uint16_t) - 0x14, (uint16_t) - 0x28, (uint16_t) 0x32 }, /* nullable_range_restricted_int8s */ \ - { (uint16_t) 0xC8, (uint16_t) 0x64, (uint16_t) 0x3E8 }, /* nullable_range_restricted_int16u */ \ - { (uint16_t) - 0x64, (uint16_t) - 0x96, (uint16_t) 0xC8 }, /* nullable_range_restricted_int16s */ \ + { (uint16_t) 0x46, (uint16_t) 0x14, (uint16_t) 0x64 }, /* range_restricted_int8u */ \ + { (uint16_t) -0x14, (uint16_t) -0x28, (uint16_t) 0x32 }, /* range_restricted_int8s */ \ + { (uint16_t) 0xC8, (uint16_t) 0x64, (uint16_t) 0x3E8 }, /* range_restricted_int16u */ \ + { (uint16_t) -0x64, (uint16_t) -0x96, (uint16_t) 0xC8 }, /* range_restricted_int16s */ \ + { (uint16_t) 0x46, (uint16_t) 0x14, (uint16_t) 0x64 }, /* nullable_range_restricted_int8u */ \ + { (uint16_t) -0x14, (uint16_t) -0x28, (uint16_t) 0x32 }, /* nullable_range_restricted_int8s */ \ + { (uint16_t) 0xC8, (uint16_t) 0x64, (uint16_t) 0x3E8 }, /* nullable_range_restricted_int16u */ \ + { (uint16_t) -0x64, (uint16_t) -0x96, (uint16_t) 0xC8 }, /* nullable_range_restricted_int16s */ \ \ /* Endpoint: 2, Cluster: On/Off (server) */ \ { \ diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index 42bc2f9b74ad64..a065d833b43846 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -56,20 +56,8 @@ template("chip_data_model") { "zap-generated/endpoint_config.h", ] - # NOTE: these are ALSO auto-generated but handled below: - # "zap-generated/IMClusterCommandHandler.cpp" - # -> contains one large DispatchSingleClusterCommand and DispatchServerCommand - - if (chip_code_pre_generated_directory == "") { - prune_outputs = [] - } - if (!chip_build_controller_dynamic_server) { outputs += [ "zap-generated/IMClusterCommandHandler.cpp" ] - } else { - if (defined(prune_outputs)) { - prune_outputs += [ "zap-generated/IMClusterCommandHandler.cpp" ] - } } if (!defined(deps)) { diff --git a/src/app/clusters/icd-management-server/icd-management-server.cpp b/src/app/clusters/icd-management-server/icd-management-server.cpp index 27ecfe778a33bb..0f71345a38d0f1 100644 --- a/src/app/clusters/icd-management-server/icd-management-server.cpp +++ b/src/app/clusters/icd-management-server/icd-management-server.cpp @@ -364,14 +364,6 @@ void ICDManagementServer::TriggerICDMTableUpdatedEvent() #endif // CHIP_CONFIG_ENABLE_ICD_CIP -Status ICDManagementServer::StayActiveRequest(FabricIndex fabricIndex) -{ - // TODO: Implementent stay awake logic for end device - // https://github.com/project-chip/connectedhomeip/issues/24259 - ICDNotifier::GetInstance().NotifyICDManagementEvent(ICDListener::ICDManagementEvents::kStayActiveRequestReceived); - return InteractionModel::Status::UnsupportedCommand; -} - void ICDManagementServer::Init(PersistentStorageDelegate & storage, Crypto::SymmetricKeystore * symmetricKeystore, ICDConfigurationData & icdConfigurationData) { @@ -433,10 +425,14 @@ bool emberAfIcdManagementClusterUnregisterClientCallback(CommandHandler * comman bool emberAfIcdManagementClusterStayActiveRequestCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, const Commands::StayActiveRequest::DecodableType & commandData) { - ICDManagementServer server; - InteractionModel::Status status = server.StayActiveRequest(commandObj->GetAccessingFabricIndex()); - - commandObj->AddStatus(commandPath, status); +// Note: We only need this #if statement for platform examples that enable the ICD management server without building the sample +// as an ICD. Since this is not spec compliant, we should remove this #if statement once we stop compiling the ICD management +// server in those examples. +#if CHIP_CONFIG_ENABLE_ICD_SERVER + IcdManagement::Commands::StayActiveResponse::Type response; + response.promisedActiveDuration = Server::GetInstance().GetICDManager().StayActiveRequest(commandData.stayActiveDuration); + commandObj->AddResponse(commandPath, response); +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER return true; } diff --git a/src/app/clusters/icd-management-server/icd-management-server.h b/src/app/clusters/icd-management-server/icd-management-server.h index 4462cb96d9c9f2..5c6b838fa9b527 100644 --- a/src/app/clusters/icd-management-server/icd-management-server.h +++ b/src/app/clusters/icd-management-server/icd-management-server.h @@ -68,8 +68,6 @@ class ICDManagementServer const chip::app::Clusters::IcdManagement::Commands::UnregisterClient::DecodableType & commandData); #endif // CHIP_CONFIG_ENABLE_ICD_CIP - chip::Protocols::InteractionModel::Status StayActiveRequest(chip::FabricIndex fabricIndex); - private: #if CHIP_CONFIG_ENABLE_ICD_CIP /** diff --git a/src/app/clusters/identify-server/identify-server.cpp b/src/app/clusters/identify-server/identify-server.cpp index 257adf934a5328..6ea8a34ca4db33 100644 --- a/src/app/clusters/identify-server/identify-server.cpp +++ b/src/app/clusters/identify-server/identify-server.cpp @@ -24,10 +24,7 @@ #include #include #include - #include -#include -#include #include #include #include diff --git a/src/app/icd/server/ICDConfigurationData.h b/src/app/icd/server/ICDConfigurationData.h index 3fb3e9a92d2304..8b87d090f769e1 100644 --- a/src/app/icd/server/ICDConfigurationData.h +++ b/src/app/icd/server/ICDConfigurationData.h @@ -61,6 +61,8 @@ class ICDConfigurationData System::Clock::Milliseconds16 GetActiveModeThreshold() { return mActiveThreshold; } + System::Clock::Milliseconds32 GetGuaranteedStayActiveDuration() { return kGuaranteedStayActiveDuration; } + Protocols::SecureChannel::CheckInCounter & GetICDCounter() { return mICDCounter; } uint16_t GetClientsSupportedPerFabric() { return mFabricClientsSupported; } @@ -123,6 +125,9 @@ class ICDConfigurationData static constexpr System::Clock::Seconds32 kMaxIdleModeDuration = System::Clock::Seconds32(18 * kSecondsPerHour); static constexpr System::Clock::Seconds32 kMinIdleModeDuration = System::Clock::Seconds32(1); + // As defined in the spec, the maximum guaranteed duration for the StayActiveDuration is 30s "Matter Application + // Clusters: 9.17.7.5.1. PromisedActiveDuration Field" + static constexpr System::Clock::Milliseconds32 kGuaranteedStayActiveDuration = System::Clock::Milliseconds32(30000); static_assert((CHIP_CONFIG_ICD_IDLE_MODE_DURATION_SEC) <= kMaxIdleModeDuration.count(), "Spec requires the IdleModeDuration to be equal or inferior to 64800s."); diff --git a/src/app/icd/server/ICDManager.cpp b/src/app/icd/server/ICDManager.cpp index 057cc089e9624f..931737783dde9f 100644 --- a/src/app/icd/server/ICDManager.cpp +++ b/src/app/icd/server/ICDManager.cpp @@ -120,6 +120,22 @@ bool ICDManager::SupportsFeature(Feature feature) #endif // !CONFIG_BUILD_FOR_HOST_UNIT_TEST } +uint32_t ICDManager::StayActiveRequest(uint32_t stayActiveDuration) +{ + // This should only be called when the device is in ActiveMode + VerifyOrReturnValue(mOperationalState == OperationalState::ActiveMode, 0); + + uint32_t promisedActiveDuration = + std::min(ICDConfigurationData::GetInstance().GetGuaranteedStayActiveDuration().count(), stayActiveDuration); + + // If the device is already in ActiveMode, we need to extend the active mode duration + // for whichever is smallest between 30000 milliseconds and stayActiveDuration, taking in account the remaining active time. + ExtendActiveMode(System::Clock::Milliseconds16(promisedActiveDuration)); + promisedActiveDuration = DeviceLayer::SystemLayer().GetRemainingTime(OnActiveModeDone, this).count(); + + return promisedActiveDuration; +} + #if CHIP_CONFIG_ENABLE_ICD_CIP void ICDManager::SendCheckInMsgs() { @@ -366,17 +382,7 @@ void ICDManager::UpdateOperationState(OperationalState state) } else { - Milliseconds16 activeModeThreshold = ICDConfigurationData::GetInstance().GetActiveModeThreshold(); - DeviceLayer::SystemLayer().ExtendTimerTo(activeModeThreshold, OnActiveModeDone, this); - - Milliseconds32 activeModeJitterThreshold = Milliseconds32(ICD_ACTIVE_TIME_JITTER_MS); - activeModeJitterThreshold = - (activeModeThreshold >= activeModeJitterThreshold) ? activeModeThreshold - activeModeJitterThreshold : kZero; - - if (!mTransitionToIdleCalled) - { - DeviceLayer::SystemLayer().ExtendTimerTo(activeModeJitterThreshold, OnTransitionToIdle, this); - } + ExtendActiveMode(ICDConfigurationData::GetInstance().GetActiveModeThreshold()); } } } @@ -521,11 +527,6 @@ void ICDManager::OnICDManagementServerEvent(ICDManagementEvents event) case ICDManagementEvents::kTableUpdated: this->UpdateICDMode(); break; - - case ICDManagementEvents::kStayActiveRequestReceived: - // TODO : Implement the StayActiveRequest - // https://github.com/project-chip/connectedhomeip/issues/24259 - break; default: break; } @@ -540,6 +541,19 @@ void ICDManager::OnSubscriptionReport() this->UpdateOperationState(OperationalState::ActiveMode); } +void ICDManager::ExtendActiveMode(Milliseconds16 extendDuration) +{ + DeviceLayer::SystemLayer().ExtendTimerTo(extendDuration, OnActiveModeDone, this); + + Milliseconds32 activeModeJitterThreshold = Milliseconds32(ICD_ACTIVE_TIME_JITTER_MS); + activeModeJitterThreshold = (extendDuration >= activeModeJitterThreshold) ? extendDuration - activeModeJitterThreshold : kZero; + + if (!mTransitionToIdleCalled) + { + DeviceLayer::SystemLayer().ExtendTimerTo(activeModeJitterThreshold, OnTransitionToIdle, this); + } +} + ICDManager::ObserverPointer * ICDManager::RegisterObserver(ICDStateObserver * observer) { return mStateObserverPool.CreateObject(observer); diff --git a/src/app/icd/server/ICDManager.h b/src/app/icd/server/ICDManager.h index 396e6be20d0606..5e391c1469143c 100644 --- a/src/app/icd/server/ICDManager.h +++ b/src/app/icd/server/ICDManager.h @@ -109,6 +109,14 @@ class ICDManager : public ICDListener void postObserverEvent(ObserverEventType event); OperationalState GetOperationalState() { return mOperationalState; } + /** + * @brief Ensures that the remaining Active Mode duration is at least the smaller of 30000 milliseconds and stayActiveDuration. + * + * @param stayActiveDuration The duration (in milliseconds) requested by the client to stay in Active Mode + * @return The duration (in milliseconds) the device will stay in Active Mode + */ + uint32_t StayActiveRequest(uint32_t stayActiveDuration); + #if CHIP_CONFIG_ENABLE_ICD_CIP void SendCheckInMsgs(); @@ -131,6 +139,12 @@ class ICDManager : public ICDListener void OnSubscriptionReport() override; protected: + /** + * @brief Hepler function that extends the Active Mode duration as well as the Active Mode Jitter timer for the transition to + * iddle mode. + */ + void ExtendActiveMode(System::Clock::Milliseconds16 extendDuration); + friend class TestICDManager; static void OnIdleModeDone(System::Layer * aLayer, void * appState); diff --git a/src/app/icd/server/ICDNotifier.h b/src/app/icd/server/ICDNotifier.h index 1223732e3fc05f..5db14503a296d7 100644 --- a/src/app/icd/server/ICDNotifier.h +++ b/src/app/icd/server/ICDNotifier.h @@ -48,8 +48,7 @@ class ICDListener enum class ICDManagementEvents : uint8_t { - kTableUpdated = 0x01, - kStayActiveRequestReceived = 0x02, + kTableUpdated = 0x01, }; using KeepActiveFlags = BitFlags; diff --git a/src/app/tests/TestICDManager.cpp b/src/app/tests/TestICDManager.cpp index da549ff5062f34..ba311f889989f8 100644 --- a/src/app/tests/TestICDManager.cpp +++ b/src/app/tests/TestICDManager.cpp @@ -540,6 +540,83 @@ class TestICDManager // After the init we should be in Idle mode NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode); } + + /* Test that verifies the logic of the ICDManager when it receives a StayActiveRequest*/ + static void TestICDMStayActive(nlTestSuite * aSuite, void * aContext) + { + TestContext * ctx = static_cast(aContext); + ICDNotifier notifier = ICDNotifier::GetInstance(); + ICDConfigurationData & icdConfigData = ICDConfigurationData::GetInstance(); + + // Verify That ICDManager starts in Idle + NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode); + + // Trigger a subscription report. Put the ICD manager into active mode. + notifier.NotifySubscriptionReport(); + NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); + + // Advance time by the ActiveModeDuration - 1 + AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetActiveModeDuration() - 1_ms32); + // Confirm ICD manager is in active mode + NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); + + uint32_t stayActiveRequestedMs = 20000; + // Send a stay active request for 20 seconds + uint32_t stayActivePromisedMs = ctx->mICDManager.StayActiveRequest(stayActiveRequestedMs); + // confirm the promised time is the same as the requested time + NL_TEST_ASSERT(aSuite, stayActivePromisedMs == stayActiveRequestedMs); + + // Advance time by the duration of the stay stayActiveRequestedMs - 1 ms + AdvanceClockAndRunEventLoop(ctx, System::Clock::Milliseconds32(stayActiveRequestedMs) - 1_ms32); + // Confirm ICD manager is in active mode + NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); + + // Advance time by 1ms and Confirm ICD manager is in idle mode + AdvanceClockAndRunEventLoop(ctx, 1_ms32); + NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode); + + // Trigger a subscription report Put the ICD manager into active mode + notifier.NotifySubscriptionReport(); + NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); + + // Advance time by the duration of the stay active request - 1 ms + AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetActiveModeDuration() - 1_ms32); + stayActiveRequestedMs = 35000; + // Send a stay active request for 35 seconds, which is higher than the maximum stay active duration (30 seconds) + stayActivePromisedMs = ctx->mICDManager.StayActiveRequest(stayActiveRequestedMs); + // confirm the promised time is the maximum stay active duration (30 seconds) + NL_TEST_ASSERT(aSuite, stayActivePromisedMs == 30000); + + // Advance time by the duration of the max stay active duration - 1 ms + AdvanceClockAndRunEventLoop(ctx, System::Clock::Milliseconds32(30000) - 1_ms32); + NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); + + // Advance time by 1ms and Confirm ICD manager is in idle mode + AdvanceClockAndRunEventLoop(ctx, 1_ms32); + NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode); + + // Trigger a subscription report Put the ICD manager into active mode + notifier.NotifySubscriptionReport(); + NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); + + // Advance time by the duration of the stay active request - 1 ms + AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetActiveModeDuration() - 1_ms32); + stayActiveRequestedMs = 30000; + // Send a stay active request for 30 seconds + stayActivePromisedMs = ctx->mICDManager.StayActiveRequest(stayActiveRequestedMs); + // confirm the promised time is the same as the requested time + NL_TEST_ASSERT(aSuite, stayActivePromisedMs == 30000); + + // Advance time by the duration of the stay active request - 20000 ms + AdvanceClockAndRunEventLoop(ctx, System::Clock::Milliseconds32(stayActiveRequestedMs) - 20000_ms32); + // Confirm ICD manager is in active mode, we should have 20000 seconds left at that point + NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); + + stayActiveRequestedMs = 10000; + stayActivePromisedMs = ctx->mICDManager.StayActiveRequest(stayActiveRequestedMs); + // confirm the promised time is 20000 since the device is already planing to stay active longer than the requested time + NL_TEST_ASSERT(aSuite, stayActivePromisedMs == 20000); + } }; } // namespace app @@ -556,6 +633,7 @@ static const nlTest sTests[] = { NL_TEST_DEF("TestKeepActivemodeRequests", TestICDManager::TestKeepActivemodeRequests), NL_TEST_DEF("TestICDMRegisterUnregisterEvents", TestICDManager::TestICDMRegisterUnregisterEvents), NL_TEST_DEF("TestICDCounter", TestICDManager::TestICDCounter), + NL_TEST_DEF("TestICDStayActive", TestICDManager::TestICDMStayActive), NL_TEST_SENTINEL(), }; diff --git a/src/app/tests/suites/TestIcdManagementCluster.yaml b/src/app/tests/suites/TestIcdManagementCluster.yaml index d9d275b90faf3c..3d0081504c19bf 100644 --- a/src/app/tests/suites/TestIcdManagementCluster.yaml +++ b/src/app/tests/suites/TestIcdManagementCluster.yaml @@ -372,3 +372,82 @@ tests: value: 102 response: error: NOT_FOUND + + - label: + "Wait for a little bit less than the active mode duration (10000ms)" + cluster: "DelayCommands" + command: "WaitForMs" + arguments: + values: + - name: "ms" + value: 9000 + + - label: + "StayActive Scenario 1: Confirm the promised active duration is + increased to a specific if a value less than 30000ms is requested and + the device does not intend to stay active longer" + command: "StayActiveRequest" + arguments: + values: + - name: "StayActiveDuration" + value: 20000 + response: + values: + - name: "PromisedActiveDuration" + constraints: + type: int32u + minValue: 19500 + maxValue: 20500 + + - label: + "Wait for a little bit less than the new promied active mode duration + (20000ms)" + cluster: "DelayCommands" + command: "WaitForMs" + arguments: + values: + - name: "ms" + value: 19000 + + - label: + "StayActive Scenario 2: Confirm the promised active duration is + reduced to 30000ms if a value greater than 30000ms is requested" + command: "StayActiveRequest" + arguments: + values: + - name: "StayActiveDuration" + value: 35000 + response: + values: + - name: "PromisedActiveDuration" + constraints: + type: int32u + minValue: 29500 + maxValue: 30500 + + - label: + "Wait for a 20000 less than the new promied active mode duration + (30000ms)" + cluster: "DelayCommands" + command: "WaitForMs" + arguments: + values: + - name: "ms" + value: 10000 + + - label: + "StayActive Scenario 3: confirm that the device ignores the request if + the device intends to stay active longer than the requested duration + we should have about 20000ms left here" + command: "StayActiveRequest" + arguments: + values: + - name: "StayActiveDuration" + value: 10000 + response: + values: + - name: "PromisedActiveDuration" + constraints: + type: int32u + minValue: 19500 + maxValue: 20500 diff --git a/src/app/util/attribute-storage.cpp b/src/app/util/attribute-storage.cpp index bd785c5b9682b1..0b94cc8f4c211c 100644 --- a/src/app/util/attribute-storage.cpp +++ b/src/app/util/attribute-storage.cpp @@ -15,12 +15,12 @@ * limitations under the License. */ -#include "app/util/common.h" +#include + #include #include #include #include -#include #include #include #include @@ -36,10 +36,7 @@ using chip::Protocols::InteractionModel::Status; // - zap-generated/callback.h is needed because endpoint_config will call the // corresponding callbacks (via GENERATED_FUNCTION_ARRAYS) and the include // for it is: -// util/common.h -// -> util/af.h -// -> util/config.h -// -> zap-generated/endpoint_config.h +// util/config.h -> zap-generated/endpoint_config.h #include using namespace chip; diff --git a/src/app/util/attribute-table.cpp b/src/app/util/attribute-table.cpp index d16942646ba929..de68b7e6a77f98 100644 --- a/src/app/util/attribute-table.cpp +++ b/src/app/util/attribute-table.cpp @@ -14,13 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// this file contains all the common includes for clusters in the zcl-util +#include #include - -// for pulling in defines dealing with EITHER server or client -#include "app/util/common.h" #include #include #include diff --git a/src/app/util/common.h b/src/app/util/common.h deleted file mode 100644 index c2e42889313ddf..00000000000000 --- a/src/app/util/common.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * - * Copyright (c) 2020 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 - -// App framework -#include -#include -#include -#include diff --git a/src/app/util/util.cpp b/src/app/util/util.cpp index e327673fc3cbf4..e8163547d94d53 100644 --- a/src/app/util/util.cpp +++ b/src/app/util/util.cpp @@ -15,12 +15,14 @@ * limitations under the License. */ -#include "app/util/common.h" +#include + #include #include #include #include #include +#include #include #include #include diff --git a/src/app/zap-templates/zcl/data-model/chip/icd-management-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/icd-management-cluster.xml index a2665916e23204..d68cc30ea95f9c 100644 --- a/src/app/zap-templates/zcl/data-model/chip/icd-management-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/icd-management-cluster.xml @@ -111,6 +111,7 @@ limitations under the License. Request the end device to stay in Active Mode for an additional ActiveModeThreshold + diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 8611f4bdcf62d8..5dece392f3cd97 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -2740,6 +2740,10 @@ cluster IcdManagement = 70 { optional octet_string<16> verificationKey = 1; } + request struct StayActiveRequestRequest { + int32u stayActiveDuration = 0; + } + response struct StayActiveResponse = 4 { int32u promisedActiveDuration = 0; } @@ -2749,7 +2753,7 @@ cluster IcdManagement = 70 { /** Unregister a client from an end device */ fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2; /** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ - command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3; + command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3; } /** This cluster supports creating a simple timer functionality. */ diff --git a/src/controller/java/AndroidCallbacks.cpp b/src/controller/java/AndroidCallbacks.cpp index 01ef820f82c6ed..fb7975262dff57 100644 --- a/src/controller/java/AndroidCallbacks.cpp +++ b/src/controller/java/AndroidCallbacks.cpp @@ -41,6 +41,8 @@ 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; +jobject DecodeGeneralTLVValue(JNIEnv * env, TLV::TLVReader & readerForGeneralValueObject, CHIP_ERROR & err); + GetConnectedDeviceCallback::GetConnectedDeviceCallback(jobject wrapperCallback, jobject javaCallback, const char * callbackClassSignature) : mOnSuccess(OnDeviceConnectedFn, this), @@ -314,20 +316,24 @@ void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPat readerForJavaTLV.Init(*apData); jobject value = nullptr; -#ifdef USE_JAVA_TLV_ENCODE_DECODE TLV::TLVReader readerForJavaObject; readerForJavaObject.Init(*apData); - +#ifdef USE_JAVA_TLV_ENCODE_DECODE value = DecodeAttributeValue(aPath, readerForJavaObject, &err); // If we don't know this attribute, suppress it. if (err == CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB) { - err = CHIP_NO_ERROR; + TLV::TLVReader readerForGeneralValueObject; + readerForGeneralValueObject.Init(*apData); + value = DecodeGeneralTLVValue(env, readerForGeneralValueObject, err); + err = CHIP_NO_ERROR; } VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Fail to decode attribute with error %s", ErrorStr(err)); aPath.LogPath()); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); +#else + value = DecodeGeneralTLVValue(env, readerForJavaObject, err); #endif // Create TLV byte array to pass to Java layer size_t bufferLen = readerForJavaTLV.GetRemainingLength() + readerForJavaTLV.GetLengthRead(); @@ -468,18 +474,23 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV } jobject value = nullptr; -#ifdef USE_JAVA_TLV_ENCODE_DECODE TLV::TLVReader readerForJavaObject; readerForJavaObject.Init(*apData); +#ifdef USE_JAVA_TLV_ENCODE_DECODE value = DecodeEventValue(aEventHeader.mPath, readerForJavaObject, &err); // If we don't know this event, just skip it. if (err == CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB) { - err = CHIP_NO_ERROR; + TLV::TLVReader readerForGeneralValueObject; + readerForGeneralValueObject.Init(*apData); + value = DecodeGeneralTLVValue(env, readerForGeneralValueObject, err); + err = CHIP_NO_ERROR; } VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Fail to decode event with error %s", ErrorStr(err)); aEventHeader.LogPath()); VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); +#else + value = DecodeGeneralTLVValue(env, readerForJavaObject, err); #endif // Create TLV byte array to pass to Java layer @@ -907,6 +918,111 @@ void InvokeCallback::ReportError(const char * message, ChipError::StorageType er VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } +jobject DecodeGeneralTLVValue(JNIEnv * env, TLV::TLVReader & readerForGeneralValueObject, CHIP_ERROR & err) +{ + jobject retValue = nullptr; + + switch (readerForGeneralValueObject.GetType()) + { + case TLV::kTLVType_SignedInteger: { + int64_t signedValue = 0; + VerifyOrReturnValue(readerForGeneralValueObject.Get(signedValue) == CHIP_NO_ERROR, nullptr, + ChipLogProgress(Controller, "Get TLV Value fail!")); + err = JniReferences::GetInstance().CreateBoxedObject("java/lang/Long", "(J)V", static_cast(signedValue), + retValue); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, ChipLogProgress(Controller, "Create Boxed Object fail!")); + return retValue; + } + case TLV::kTLVType_UnsignedInteger: { + uint64_t unsignedValue = 0; + VerifyOrReturnValue(readerForGeneralValueObject.Get(unsignedValue) == CHIP_NO_ERROR, nullptr, + ChipLogProgress(Controller, "Get TLV Value fail!")); + err = JniReferences::GetInstance().CreateBoxedObject("java/lang/Long", "(J)V", static_cast(unsignedValue), + retValue); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, ChipLogProgress(Controller, "Create Boxed Object fail!")); + return retValue; + } + case TLV::kTLVType_Boolean: { + bool booleanValue = false; + VerifyOrReturnValue(readerForGeneralValueObject.Get(booleanValue) == CHIP_NO_ERROR, nullptr, + ChipLogProgress(Controller, "Get TLV Value fail!")); + err = JniReferences::GetInstance().CreateBoxedObject("java/lang/Boolean", "(Z)V", + static_cast(booleanValue), retValue); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, ChipLogProgress(Controller, "Create Boxed Object fail!")); + return retValue; + } + case TLV::kTLVType_FloatingPointNumber: { + double doubleValue = 0.0; + VerifyOrReturnValue(readerForGeneralValueObject.Get(doubleValue) == CHIP_NO_ERROR, nullptr, + ChipLogProgress(Controller, "Get TLV Value fail!")); + err = JniReferences::GetInstance().CreateBoxedObject("java/lang/Double", "(D)V", static_cast(doubleValue), + retValue); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, ChipLogProgress(Controller, "Create Boxed Object fail!")); + return retValue; + } + case TLV::kTLVType_UTF8String: { + uint32_t bufferLen = readerForGeneralValueObject.GetLength(); + std::unique_ptr buffer = std::unique_ptr(new char[bufferLen + 1]); + err = readerForGeneralValueObject.GetString(buffer.get(), bufferLen + 1); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, ChipLogProgress(Controller, "Get TLV Value fail!")); + chip::CharSpan valueSpan(buffer.get(), bufferLen); + chip::JniReferences::GetInstance().CharToStringUTF(valueSpan, retValue); + return retValue; + } + case TLV::kTLVType_ByteString: { + uint32_t bufferLen = readerForGeneralValueObject.GetLength(); + std::unique_ptr buffer = std::unique_ptr(new uint8_t[bufferLen + 1]); + err = readerForGeneralValueObject.GetBytes(buffer.get(), bufferLen + 1); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, ChipLogProgress(Controller, "Get TLV Value fail!")); + + jbyteArray valueByteArray = env->NewByteArray(static_cast(bufferLen)); + env->SetByteArrayRegion(valueByteArray, 0, static_cast(bufferLen), reinterpret_cast(buffer.get())); + + return static_cast(valueByteArray); + } + case TLV::kTLVType_Array: { + TLV::TLVType containerType; + err = readerForGeneralValueObject.EnterContainer(containerType); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, + ChipLogProgress(Controller, "EnterContainer fail! : %" CHIP_ERROR_FORMAT, err.Format())); + err = chip::JniReferences::GetInstance().CreateArrayList(retValue); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, + ChipLogProgress(Controller, "CreateArrayList fail! : %" CHIP_ERROR_FORMAT, err.Format())); + while (readerForGeneralValueObject.Next() == CHIP_NO_ERROR) + { + jobject inValue = DecodeGeneralTLVValue(env, readerForGeneralValueObject, err); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, + ChipLogProgress(Controller, "Can't parse general value : %" CHIP_ERROR_FORMAT, err.Format())); + err = chip::JniReferences::GetInstance().AddToList(retValue, inValue); + } + return retValue; + } + case TLV::kTLVType_List: { + TLV::TLVType containerType; + err = readerForGeneralValueObject.EnterContainer(containerType); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, + ChipLogProgress(Controller, "EnterContainer fail! : %" CHIP_ERROR_FORMAT, err.Format())); + err = chip::JniReferences::GetInstance().CreateArrayList(retValue); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, + ChipLogProgress(Controller, "CreateArrayList fail! : %" CHIP_ERROR_FORMAT, err.Format())); + while (readerForGeneralValueObject.Next() == CHIP_NO_ERROR) + { + jobject inValue = DecodeGeneralTLVValue(env, readerForGeneralValueObject, err); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, + ChipLogProgress(Controller, "Can't parse general value : %" CHIP_ERROR_FORMAT, err.Format())); + err = chip::JniReferences::GetInstance().AddToList(retValue, inValue); + } + return retValue; + } + case TLV::kTLVType_Null: { + return nullptr; + } + default: + err = CHIP_ERROR_WRONG_TLV_TYPE; + return nullptr; + } +} + jlong newConnectedDeviceCallback(JNIEnv * env, jobject self, jobject callback) { chip::DeviceLayer::StackLock lock; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index 7025f3cde37858..c55a45b77aaca8 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -18170,14 +18170,18 @@ public void onResponse(StructType invokeStructValue) { }}, commandId, commandArgs, timedInvokeTimeoutMs); } - public void stayActiveRequest(StayActiveResponseCallback callback) { - stayActiveRequest(callback, 0); + public void stayActiveRequest(StayActiveResponseCallback callback, Long stayActiveDuration) { + stayActiveRequest(callback, stayActiveDuration, 0); } - public void stayActiveRequest(StayActiveResponseCallback callback, int timedInvokeTimeoutMs) { + public void stayActiveRequest(StayActiveResponseCallback callback, Long stayActiveDuration, int timedInvokeTimeoutMs) { final long commandId = 3L; ArrayList elements = new ArrayList<>(); + final long stayActiveDurationFieldID = 0L; + BaseTLVType stayActiveDurationtlvValue = new UIntType(stayActiveDuration); + elements.add(new StructElement(stayActiveDurationFieldID, stayActiveDurationtlvValue)); + StructType commandArgs = new StructType(elements); invoke(new InvokeCallbackImpl(callback) { @Override diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java index a1d43e3a7933a5..3437b8a981e476 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java @@ -5881,6 +5881,23 @@ public static UnregisterClientCommandField value(int id) throws NoSuchFieldError } throw new NoSuchFieldError(); } + }public enum StayActiveRequestCommandField {StayActiveDuration(0),; + private final int id; + StayActiveRequestCommandField(int id) { + this.id = id; + } + + public int getID() { + return id; + } + public static StayActiveRequestCommandField value(int id) throws NoSuchFieldError { + for (StayActiveRequestCommandField field : StayActiveRequestCommandField.values()) { + if (field.getID() == id) { + return field; + } + } + throw new NoSuchFieldError(); + } }@Override public String getAttributeName(long id) throws NoSuchFieldError { return Attribute.value(id).toString(); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index 5162f9766a74da..4ded328fad6ed5 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -23352,10 +23352,16 @@ public Map> getCommandMap() { icdManagementClusterInteractionInfoMap.put("unregisterClient", icdManagementunregisterClientInteractionInfo); Map icdManagementstayActiveRequestCommandParams = new LinkedHashMap(); + + CommandParameterInfo icdManagementstayActiveRequeststayActiveDurationCommandParameterInfo = new CommandParameterInfo("stayActiveDuration", Long.class, Long.class); + icdManagementstayActiveRequestCommandParams.put("stayActiveDuration",icdManagementstayActiveRequeststayActiveDurationCommandParameterInfo); InteractionInfo icdManagementstayActiveRequestInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { ((ChipClusters.IcdManagementCluster) cluster) .stayActiveRequest((ChipClusters.IcdManagementCluster.StayActiveResponseCallback) callback + , (Long) + commandArguments.get("stayActiveDuration") + ); }, () -> new DelegatedIcdManagementClusterStayActiveResponseCallback(), diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt index 9421d92a1742f7..008aa6349da2ce 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt @@ -193,11 +193,17 @@ class IcdManagementCluster( logger.log(Level.FINE, "Invoke command succeeded: ${response}") } - suspend fun stayActiveRequest(timedInvokeTimeout: Duration? = null): StayActiveResponse { + suspend fun stayActiveRequest( + stayActiveDuration: UInt, + timedInvokeTimeout: Duration? = null + ): StayActiveResponse { val commandId: UInt = 3u val tlvWriter = TlvWriter() tlvWriter.startStructure(AnonymousTag) + + val TAG_STAY_ACTIVE_DURATION_REQ: Int = 0 + tlvWriter.put(ContextSpecificTag(TAG_STAY_ACTIVE_DURATION_REQ), stayActiveDuration) tlvWriter.endStructure() val request: InvokeRequest = diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index 853fd1f98c38cd..3bc715829f27db 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -4078,6 +4078,7 @@ class ChipClusters: "commandId": 0x00000003, "commandName": "StayActiveRequest", "args": { + "stayActiveDuration": "int", }, }, }, diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 3f5c116cc5515b..cd411b93d43301 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -14304,8 +14304,11 @@ class StayActiveRequest(ClusterCommand): def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ + ClusterObjectFieldDescriptor(Label="stayActiveDuration", Tag=0, Type=uint), ]) + stayActiveDuration: 'uint' = 0 + @dataclass class StayActiveResponse(ClusterCommand): cluster_id: typing.ClassVar[int] = 0x00000046 diff --git a/src/darwin/Framework/CHIP/MTRBaseDevice.h b/src/darwin/Framework/CHIP/MTRBaseDevice.h index af0a15bd1a6857..1fe9735932a6d0 100644 --- a/src/darwin/Framework/CHIP/MTRBaseDevice.h +++ b/src/darwin/Framework/CHIP/MTRBaseDevice.h @@ -19,6 +19,7 @@ #import #import +#import @class MTRSetupPayload; @class MTRDeviceController; @@ -542,6 +543,26 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) reportHandler:(MTRDeviceResponseHandler)reportHandler subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); + +/** + * Download log of the desired type from the device. + * + * @param type The type of log being requested. This should correspond to a value in the enum MTRDiagnosticLogType. + * @param timeout The timeout for getting the log. If the timeout expires, completion will be called with whatever + * has been retrieved by that point (which might be none or a partial log). + * If the timeout is set to 0, the request will not expire and completion will not be called until + * the log is fully retrieved or an error occurs. + * @param queue The queue on which completion will be called. + * @param completion The completion handler that is called after attempting to retrieve the requested log. + * - In case of success, the completion handler is called with a non-nil URL and a nil error. + * - If there is an error, a non-nil error is used and the url can be non-nil too if some logs have already been downloaded. + */ +- (void)downloadLogOfType:(MTRDiagnosticLogType)type + timeout:(NSTimeInterval)timeout + queue:(dispatch_queue_t)queue + completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion + MTR_NEWLY_AVAILABLE; + @end /** diff --git a/src/darwin/Framework/CHIP/MTRBaseDevice.mm b/src/darwin/Framework/CHIP/MTRBaseDevice.mm index 2a981cdd860fff..13154f8ac97aa2 100644 --- a/src/darwin/Framework/CHIP/MTRBaseDevice.mm +++ b/src/darwin/Framework/CHIP/MTRBaseDevice.mm @@ -2147,6 +2147,19 @@ + (NSDictionary *)eventReportForHeader:(const chip::app::EventHeader &)header an return buffer; } + +- (void)downloadLogOfType:(MTRDiagnosticLogType)type + timeout:(NSTimeInterval)timeout + queue:(dispatch_queue_t)queue + completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion +{ + [_deviceController downloadLogFromNodeWithID:@(_nodeID) + type:type + timeout:timeout + queue:queue + completion:completion]; +} + @end @implementation MTRBaseDevice (Deprecated) diff --git a/src/darwin/Framework/CHIP/MTRDevice.h b/src/darwin/Framework/CHIP/MTRDevice.h index d4641d5dd321b3..23a1ecf51ad56c 100644 --- a/src/darwin/Framework/CHIP/MTRDevice.h +++ b/src/darwin/Framework/CHIP/MTRDevice.h @@ -18,7 +18,6 @@ #import #import #import -#import NS_ASSUME_NONNULL_BEGIN @@ -326,27 +325,6 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) */ - (void)removeClientDataForKey:(NSString *)key endpointID:(NSNumber *)endpointID MTR_UNSTABLE_API; -/** - * Download log of the desired type from the device. - * - * Note: The consumer of this API should move the file that the url points to or open it for reading before the - * completion handler returns. Otherwise, the file will be deleted, and the data will be lost. - * - * @param type The type of log being requested. This should correspond to a value in the enum MTRDiagnosticLogType. - * @param timeout The timeout for getting the log. If the timeout expires, completion will be called with whatever - * has been retrieved by that point (which might be none or a partial log). - * If the timeout is set to 0, the request will not expire and completion will not be called until - * the log is fully retrieved or an error occurs. - * @param queue The queue on which completion will be called. - * @param completion The completion handler that is called after attempting to retrieve the requested log. - * - In case of success, the completion handler is called with a non-nil URL and a nil error. - * - If there is an error, a non-nil error is used and the url can be non-nil too if some logs have already been downloaded. - */ -- (void)downloadLogOfType:(MTRDiagnosticLogType)type - timeout:(NSTimeInterval)timeout - queue:(dispatch_queue_t)queue - completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion - MTR_NEWLY_AVAILABLE; @end MTR_EXTERN NSString * const MTRPreviousDataKey MTR_NEWLY_AVAILABLE; diff --git a/src/darwin/Framework/CHIP/MTRDevice.mm b/src/darwin/Framework/CHIP/MTRDevice.mm index 1b42caecf80c76..dbf1785c9bb6ba 100644 --- a/src/darwin/Framework/CHIP/MTRDevice.mm +++ b/src/darwin/Framework/CHIP/MTRDevice.mm @@ -1713,18 +1713,6 @@ - (void)openCommissioningWindowWithDiscriminator:(NSNumber *)discriminator [baseDevice openCommissioningWindowWithDiscriminator:discriminator duration:duration queue:queue completion:completion]; } -- (void)downloadLogOfType:(MTRDiagnosticLogType)type - timeout:(NSTimeInterval)timeout - queue:(dispatch_queue_t)queue - completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion -{ - [_deviceController downloadLogFromNodeWithID:_nodeID - type:type - timeout:timeout - queue:queue - completion:completion]; -} - #pragma mark - Cache management // assume lock is held diff --git a/src/darwin/Framework/CHIP/MTRDeviceController+XPC.h b/src/darwin/Framework/CHIP/MTRDeviceController+XPC.h index 4316ba65f25198..2c4ec56e180113 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController+XPC.h +++ b/src/darwin/Framework/CHIP/MTRDeviceController+XPC.h @@ -20,6 +20,7 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -183,6 +184,15 @@ typedef void (^MTRValuesHandler)(id _Nullable values, NSError * _Nullable error) attributeId:(NSNumber * _Nullable)attributeId completion:(MTRValuesHandler)completion; +/** + * Requests downloading some logs + */ +- (void)downloadLogWithController:(id _Nullable)controller + nodeId:(uint64_t)nodeId + type:(MTRDiagnosticLogType)type + timeout:(NSTimeInterval)timeout + completion:(void (^)(NSString * _Nullable url, NSError * _Nullable error))completion; + @end /** diff --git a/src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm b/src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm index fa532f19aa833b..87ce5560381cca 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm @@ -220,6 +220,10 @@ + (NSXPCInterface *)xpcInterfaceForServerProtocol forSelector:@selector(readAttributeCacheWithController:nodeId:endpointId:clusterId:attributeId:completion:) argumentIndex:0 ofReply:YES]; + [xpcInterface setClasses:GetXPCAllowedClasses() + forSelector:@selector(downloadLogWithController:nodeId:type:timeout:completion:) + argumentIndex:0 + ofReply:YES]; return xpcInterface; } diff --git a/src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm b/src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm index 36dc5b27410da1..dee3ae86331812 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm @@ -427,6 +427,38 @@ - (void)openCommissioningWindowWithDiscriminator:(NSNumber *)discriminator }); } +- (void)downloadLogOfType:(MTRDiagnosticLogType)type + timeout:(NSTimeInterval)timeout + queue:(dispatch_queue_t)queue + completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion +{ + MTR_LOG_DEBUG("Downloading log ..."); + + __auto_type workBlock = ^(MTRDeviceControllerXPCProxyHandle * _Nullable handle, NSError * _Nullable error) { + if (error != nil) { + completion(nil, error); + return; + } + + [handle.proxy downloadLogWithController:self.controllerID + nodeId:self.nodeID.unsignedLongLongValue + type:type + timeout:timeout + completion:^(NSString * _Nullable url, NSError * _Nullable error) { + dispatch_async(queue, ^{ + MTR_LOG_DEBUG("Download log"); + completion([NSURL URLWithString:url], error); + // The following captures the proxy handle in the closure so that the + // handle won't be released prior to block call. + __auto_type handleRetainer = handle; + (void) handleRetainer; + }); + }]; + }; + + [self fetchProxyHandleWithQueue:queue completion:workBlock]; +} + - (void)fetchProxyHandleWithQueue:(dispatch_queue_t)queue completion:(MTRFetchProxyHandleCompletion)completion { if (self.controllerID != nil) { diff --git a/src/darwin/Framework/CHIP/MTRDiagnosticLogsDownloader.mm b/src/darwin/Framework/CHIP/MTRDiagnosticLogsDownloader.mm index 46226d69357058..8d2832052979e7 100644 --- a/src/darwin/Framework/CHIP/MTRDiagnosticLogsDownloader.mm +++ b/src/darwin/Framework/CHIP/MTRDiagnosticLogsDownloader.mm @@ -165,7 +165,6 @@ - (instancetype)initWithType:(MTRDiagnosticLogType)type // data in the logs that the caller may find useful. For this reason, fileURL is passed in even // when there is an error but fileHandle is not nil. completion(strongSelf->_fileHandle ? fileURL : nil, bdxError); - [strongSelf deleteFile]; done(strongSelf); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 9f7d6f8ffd5c64..6232b6424b8eb1 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -4491,9 +4491,7 @@ MTR_PROVISIONALLY_AVAILABLE * * Request the end device to stay in Active Mode for an additional ActiveModeThreshold */ -- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams * _Nullable)params completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)stayActiveRequestWithCompletion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion - MTR_PROVISIONALLY_AVAILABLE; +- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams *)params completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)readAttributeIdleModeDurationWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)subscribeAttributeIdleModeDurationWithParams:(MTRSubscribeParams *)params diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index 8cca4c8ed5a7d5..b375488f292fc8 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -37049,11 +37049,7 @@ - (void)unregisterClientWithParams:(MTRICDManagementClusterUnregisterClientParam queue:self.callbackQueue completion:responseHandler]; } -- (void)stayActiveRequestWithCompletion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion -{ - [self stayActiveRequestWithParams:nil completion:completion]; -} -- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams * _Nullable)params completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion +- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams *)params completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion { if (params == nil) { params = [[MTRICDManagementClusterStayActiveRequestParams diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h index d8bc6458a2680d..7ce97cfe09442f 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h @@ -2090,9 +2090,7 @@ MTR_PROVISIONALLY_AVAILABLE - (void)registerClientWithParams:(MTRICDManagementClusterRegisterClientParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterRegisterClientResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)unregisterClientWithParams:(MTRICDManagementClusterUnregisterClientParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)stayActiveRequestWithExpectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion - MTR_PROVISIONALLY_AVAILABLE; +- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeIdleModeDurationWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm index 2374d7f3cf9531..db279250cac8bf 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm @@ -6080,11 +6080,7 @@ - (void)unregisterClientWithParams:(MTRICDManagementClusterUnregisterClientParam completion:responseHandler]; } -- (void)stayActiveRequestWithExpectedValues:(NSArray *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion -{ - [self stayActiveRequestWithParams:nil expectedValues:expectedValues expectedValueInterval:expectedValueIntervalMs completion:completion]; -} -- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion +- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams *)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion { if (params == nil) { params = [[MTRICDManagementClusterStayActiveRequestParams diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index 8f2b0705fe3283..ccd23b30f0aceb 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -3697,6 +3697,8 @@ MTR_PROVISIONALLY_AVAILABLE MTR_PROVISIONALLY_AVAILABLE @interface MTRICDManagementClusterStayActiveRequestParams : NSObject + +@property (nonatomic, copy) NSNumber * _Nonnull stayActiveDuration MTR_PROVISIONALLY_AVAILABLE; /** * Controls whether the command is a timed command (using Timed Invoke). * diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index 60757c92d0dfdb..3105c9a9d21f80 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -9783,6 +9783,8 @@ @implementation MTRICDManagementClusterStayActiveRequestParams - (instancetype)init { if (self = [super init]) { + + _stayActiveDuration = @(0); _timedInvokeTimeoutMs = nil; _serverSideProcessingTimeout = nil; } @@ -9793,6 +9795,7 @@ - (id)copyWithZone:(NSZone * _Nullable)zone; { auto other = [[MTRICDManagementClusterStayActiveRequestParams alloc] init]; + other.stayActiveDuration = self.stayActiveDuration; other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; @@ -9801,7 +9804,7 @@ - (id)copyWithZone:(NSZone * _Nullable)zone; - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: >", NSStringFromClass([self class])]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: stayActiveDuration:%@; >", NSStringFromClass([self class]), _stayActiveDuration]; return descriptionString; } @@ -9813,6 +9816,9 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader { chip::app::Clusters::IcdManagement::Commands::StayActiveRequest::Type encodableStruct; ListFreer listFreer; + { + encodableStruct.stayActiveDuration = self.stayActiveDuration.unsignedIntValue; + } auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); if (buffer.IsNull()) { diff --git a/src/darwin/Framework/CHIPTests/MTRXPCListenerSampleTests.m b/src/darwin/Framework/CHIPTests/MTRXPCListenerSampleTests.m index eabd682a5a0d59..3bf727db3dabb3 100644 --- a/src/darwin/Framework/CHIPTests/MTRXPCListenerSampleTests.m +++ b/src/darwin/Framework/CHIPTests/MTRXPCListenerSampleTests.m @@ -167,6 +167,28 @@ - (void)getAnyDeviceControllerWithCompletion:(void (^)(id _Nullable controller, completion(MTRDeviceControllerId, nil); } +- (void)downloadLogWithController:(id)controller + nodeId:(uint64_t)nodeId + type:(MTRDiagnosticLogType)type + timeout:(NSTimeInterval)timeout + completion:(void (^)(NSString * _Nullable url, NSError * _Nullable error))completion +{ + (void) controller; + __auto_type sharedController = sController; + if (sharedController) { + __auto_type device = [MTRBaseDevice deviceWithNodeID:@(nodeId) controller:sharedController]; + [device downloadLogOfType:type + timeout:timeout + queue:dispatch_get_main_queue() + completion:^(NSURL * _Nullable url, NSError * _Nullable error) { + completion([url absoluteString], error); + }]; + } else { + NSLog(@"Failed to get shared controller"); + completion(nil, [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeGeneralError userInfo:nil]); + } +} + - (void)readAttributeWithController:(id)controller nodeId:(uint64_t)nodeId endpointId:(NSNumber * _Nullable)endpointId @@ -1865,6 +1887,30 @@ - (void)test015_MTRDeviceInteraction }, @(NO)); } +- (void)test016_DownloadLog +{ + XCTestExpectation * expectation = + [self expectationWithDescription:@"Download EndUserSupport log"]; + + MTRBaseDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + + [device downloadLogOfType:MTRDiagnosticLogTypeEndUserSupport + timeout:10 + queue:queue + completion:^(NSURL * _Nullable url, NSError * _Nullable error) { + NSLog(@"downloadLogOfType: url: %@, error: %@", url, error); + XCTAssertNil(error); + + NSError * readError; + NSString * fileContent = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&readError]; + XCTAssertNil(readError); + XCTAssertTrue([fileContent isEqualToString:@"This is a simple log\n"]); + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} + - (void)test900_SubscribeClusterStateCache { XCTestExpectation * expectation = [self expectationWithDescription:@"subscribe attributes by cache"]; diff --git a/src/darwin/Framework/CHIPTests/MTRXPCProtocolTests.m b/src/darwin/Framework/CHIPTests/MTRXPCProtocolTests.m index d3d010ff7f0764..f626323cefb162 100644 --- a/src/darwin/Framework/CHIPTests/MTRXPCProtocolTests.m +++ b/src/darwin/Framework/CHIPTests/MTRXPCProtocolTests.m @@ -116,6 +116,8 @@ @interface MTRXPCProtocolTests @property (readwrite, strong) void (^handleReadClusterStateCache) (id controller, NSNumber * nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, NSNumber * _Nullable attributeId, void (^completion)(id _Nullable values, NSError * _Nullable error)); +@property (readwrite, strong) void (^handleDownloadLog)(id controller, NSNumber * nodeId, MTRDiagnosticLogType type, NSTimeInterval timeout, + void (^completion)(NSString * _Nullable url, NSError * _Nullable error)); @end @@ -274,6 +276,18 @@ - (void)readAttributeCacheWithController:(id _Nullable)controller }); } +- (void)downloadLogWithController:(id)controller + nodeId:(uint64_t)nodeId + type:(MTRDiagnosticLogType)type + timeout:(NSTimeInterval)timeout + completion:(void (^)(NSString * _Nullable url, NSError * _Nullable error))completion +{ + dispatch_async(dispatch_get_main_queue(), ^{ + XCTAssertNotNil(self.handleDownloadLog); + self.handleDownloadLog(controller, @(nodeId), type, timeout, completion); + }); +} + - (void)setUp { [self setContinueAfterFailure:NO]; @@ -300,6 +314,44 @@ - (void)tearDown _xpcDisconnectExpectation = nil; } +- (void)testDownloadLogSuccess +{ + uint64_t myNodeId = 9876543210; + NSString * myBdxURL = @"bdx://foo"; + NSTimeInterval myTimeout = 10; + + XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; + XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; + + __auto_type uuid = self.controllerUUID; + _handleDownloadLog = ^(id controller, NSNumber * nodeId, MTRDiagnosticLogType type, NSTimeInterval timeout, + void (^completion)(NSString * _Nullable url, NSError * _Nullable error)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual([nodeId unsignedLongLongValue], myNodeId); + [callExpectation fulfill]; + completion(myBdxURL, nil); + }; + + __auto_type * device = [MTRBaseDevice deviceWithNodeID:@(myNodeId) controller:_remoteDeviceController]; + NSLog(@"Device acquired. Downloading..."); + [device downloadLogOfType:MTRDiagnosticLogTypeEndUserSupport + timeout:myTimeout + queue:dispatch_get_main_queue() + completion:^(NSURL * _Nullable url, NSError * _Nullable error) { + NSLog(@"Read url: %@", url); + XCTAssertNotNil(url); + XCTAssertNil(error); + [responseExpectation fulfill]; + self.xpcDisconnectExpectation = [self expectationWithDescription:@"XPC Disconnected"]; + }]; + + [self waitForExpectations:[NSArray arrayWithObjects:callExpectation, responseExpectation, nil] timeout:kTimeoutInSeconds]; + + // When download is done, connection should have been released + [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + XCTAssertNil(_xpcConnection); +} + - (void)testReadAttributeSuccess { uint64_t myNodeId = 9876543210; diff --git a/src/lib/support/Pool.cpp b/src/lib/support/Pool.cpp index c32b46be45e819..555127a7082d67 100644 --- a/src/lib/support/Pool.cpp +++ b/src/lib/support/Pool.cpp @@ -127,6 +127,46 @@ Loop StaticAllocatorBitmap::ForEachActiveObjectInner(void * context, Lambda lamb return Loop::Finish; } +size_t StaticAllocatorBitmap::FirstActiveIndex() +{ + size_t idx = 0; + for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word) + { + auto & usage = mUsage[word]; + auto value = usage.load(std::memory_order_relaxed); + for (size_t offset = 0; offset < kBitChunkSize && offset + word * kBitChunkSize < Capacity(); ++offset) + { + if ((value & (kBit1 << offset)) != 0) + { + return idx; + } + idx++; + } + } + VerifyOrDie(idx == mCapacity); + return mCapacity; +} + +size_t StaticAllocatorBitmap::NextActiveIndexAfter(size_t start) +{ + size_t idx = 0; + for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word) + { + auto & usage = mUsage[word]; + auto value = usage.load(std::memory_order_relaxed); + for (size_t offset = 0; offset < kBitChunkSize && offset + word * kBitChunkSize < Capacity(); ++offset) + { + if (((value & (kBit1 << offset)) != 0) && (start < idx)) + { + return idx; + } + idx++; + } + } + VerifyOrDie(idx == mCapacity); + return mCapacity; +} + #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP HeapObjectListNode * HeapObjectList::FindNode(void * object) const @@ -159,24 +199,30 @@ Loop HeapObjectList::ForEachNode(void * context, Lambda lambda) p = p->mNext; } --mIterationDepth; - if (mIterationDepth == 0 && mHaveDeferredNodeRemovals) + CleanupDeferredReleases(); + return result; +} + +void HeapObjectList::CleanupDeferredReleases() +{ + if (mIterationDepth != 0 || !mHaveDeferredNodeRemovals) { - // Remove nodes for released objects. - p = mNext; - while (p != this) + return; + } + // Remove nodes for released objects. + HeapObjectListNode * p = mNext; + while (p != this) + { + HeapObjectListNode * next = p->mNext; + if (p->mObject == nullptr) { - HeapObjectListNode * next = p->mNext; - if (p->mObject == nullptr) - { - p->Remove(); - Platform::Delete(p); - } - p = next; + p->Remove(); + Platform::Delete(p); } - - mHaveDeferredNodeRemovals = false; + p = next; } - return result; + + mHaveDeferredNodeRemovals = false; } #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP diff --git a/src/lib/support/Pool.h b/src/lib/support/Pool.h index a3959fd1e868f9..e4fb31769f4193 100644 --- a/src/lib/support/Pool.h +++ b/src/lib/support/Pool.h @@ -36,6 +36,9 @@ namespace chip { +template +class BitmapActiveObjectIterator; + namespace internal { class Statistics @@ -91,6 +94,16 @@ class StaticAllocatorBitmap : public internal::StaticAllocatorBase void * At(size_t index) { return static_cast(mElements) + mElementSize * index; } size_t IndexOf(void * element); + /// Returns the first index that is active (i.e. allocated data). + /// + /// If nothing is active, this will return mCapacity + size_t FirstActiveIndex(); + + /// Returns the next active index after `start`. + /// + /// If nothing else active/allocated, returns mCapacity + size_t NextActiveIndexAfter(size_t start); + using Lambda = Loop (*)(void * context, void * object); Loop ForEachActiveObjectInner(void * context, Lambda lambda); Loop ForEachActiveObjectInner(void * context, Loop lambda(void * context, const void * object)) const @@ -102,6 +115,10 @@ class StaticAllocatorBitmap : public internal::StaticAllocatorBase void * mElements; const size_t mElementSize; std::atomic * mUsage; + + /// allow accessing direct At() calls + template + friend class ::chip::BitmapActiveObjectIterator; }; template @@ -132,9 +149,9 @@ struct HeapObjectListNode mPrev->mNext = mNext; } - void * mObject; - HeapObjectListNode * mNext; - HeapObjectListNode * mPrev; + void * mObject = nullptr; + HeapObjectListNode * mNext = nullptr; + HeapObjectListNode * mPrev = nullptr; }; struct HeapObjectList : HeapObjectListNode @@ -158,6 +175,9 @@ struct HeapObjectList : HeapObjectListNode return const_cast(this)->ForEachNode(context, reinterpret_cast(lambda)); } + /// Cleans up any deferred releases IFF iteration depth is 0 + void CleanupDeferredReleases(); + size_t mIterationDepth = 0; bool mHaveDeferredNodeRemovals = false; }; @@ -166,6 +186,46 @@ struct HeapObjectList : HeapObjectListNode } // namespace internal +/// Provides iteration over active objects in a Bitmap pool. +/// +/// Creating and releasing items within a pool does not invalidate +/// an iterator, however there are no guarantees which objects the +/// iterator will return (i.e. newly created objects while iterating +/// may be visible or not to the iterator depending where they are +/// allocated). +/// +/// You are not prevented from releasing the object the iterator +/// currently points at. In that case, iterator should be advanced. +template +class BitmapActiveObjectIterator +{ +public: + using value_type = T; + using pointer = T *; + using reference = T &; + + explicit BitmapActiveObjectIterator(internal::StaticAllocatorBitmap * pool, size_t idx) : mPool(pool), mIndex(idx) {} + BitmapActiveObjectIterator() {} + + bool operator==(const BitmapActiveObjectIterator & other) const + { + return (AtEnd() && other.AtEnd()) || ((mPool == other.mPool) && (mIndex == other.mIndex)); + } + bool operator!=(const BitmapActiveObjectIterator & other) const { return !(*this == other); } + BitmapActiveObjectIterator & operator++() + { + mIndex = mPool->NextActiveIndexAfter(mIndex); + return *this; + } + T * operator*() const { return static_cast(mPool->At(mIndex)); } + +private: + bool AtEnd() const { return (mPool == nullptr) || (mIndex >= mPool->Capacity()); } + + internal::StaticAllocatorBitmap * mPool = nullptr; // pool that this belongs to + size_t mIndex = std::numeric_limits::max(); +}; + /** * @class ObjectPool * @@ -205,6 +265,9 @@ class BitMapObjectPool : public internal::StaticAllocatorBitmap BitMapObjectPool() : StaticAllocatorBitmap(mData.mMemory, mUsage, N, sizeof(T)) {} ~BitMapObjectPool() { VerifyOrDie(Allocated() == 0); } + BitmapActiveObjectIterator begin() { return BitmapActiveObjectIterator(this, FirstActiveIndex()); } + BitmapActiveObjectIterator end() { return BitmapActiveObjectIterator(this, N); } + template T * CreateObject(Args &&... args) { @@ -331,6 +394,91 @@ class HeapObjectPool : public internal::Statistics, public HeapObjectPoolExitHan #endif // __SANITIZE_ADDRESS__ } + /// Provides iteration over active objects in the pool. + /// + /// NOTE: There is extra logic to allow objects release WHILE the iterator is + /// active while still allowing to advance the iterator. + /// This is done by flagging an iteration depth whenever an active + /// iterator exists. This also means that while a pool iterator exists, releasing + /// of tracking memory objects may be deferred until the last active iterator is + /// released. + class ActiveObjectIterator + { + public: + using value_type = T; + using pointer = T *; + using reference = T &; + + ActiveObjectIterator() {} + ActiveObjectIterator(const ActiveObjectIterator & other) : mCurrent(other.mCurrent), mEnd(other.mEnd) + { + if (mEnd != nullptr) + { + // Iteration depth is used to support `Release` while an iterator is active. + // + // Code was historically using this functionality, so we support it here + // as well: while iteration is active, iteration depth is > 0. When it + // goes to 0, then any deferred `Release()` calls are executed. + mEnd->mIterationDepth++; + } + } + + ActiveObjectIterator & operator=(const ActiveObjectIterator & other) + { + if (mEnd != nullptr) + { + mEnd->mIterationDepth--; + mEnd->CleanupDeferredReleases(); + } + mCurrent = other.mCurrent; + mEnd = other.mEnd; + mEnd->mIterationDepth++; + } + + ~ActiveObjectIterator() + { + if (mEnd != nullptr) + { + mEnd->mIterationDepth--; + mEnd->CleanupDeferredReleases(); + } + } + + bool operator==(const ActiveObjectIterator & other) const + { + // extra current/end compare is to have all "end iterators" + // compare as equal (in particular default active object iterator is the end + // of an iterator) + return (mCurrent == other.mCurrent) || ((mCurrent == mEnd) && (other.mCurrent == other.mEnd)); + } + bool operator!=(const ActiveObjectIterator & other) const { return !(*this == other); } + ActiveObjectIterator & operator++() + { + do + { + mCurrent = mCurrent->mNext; + } while ((mCurrent != mEnd) && (mCurrent->mObject == nullptr)); + return *this; + } + T * operator*() const { return static_cast(mCurrent->mObject); } + + protected: + friend class HeapObjectPool; + + explicit ActiveObjectIterator(internal::HeapObjectListNode * current, internal::HeapObjectList * end) : + mCurrent(current), mEnd(end) + { + mEnd->mIterationDepth++; + } + + private: + internal::HeapObjectListNode * mCurrent = nullptr; + internal::HeapObjectList * mEnd = nullptr; + }; + + ActiveObjectIterator begin() { return ActiveObjectIterator(mObjects.mNext, &mObjects); } + ActiveObjectIterator end() { return ActiveObjectIterator(&mObjects, &mObjects); } + template T * CreateObject(Args &&... args) { @@ -456,6 +604,15 @@ enum class ObjectPoolMem #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP }; +template +struct ObjectPoolIterator; + +template +struct ObjectPoolIterator +{ + using Type = BitmapActiveObjectIterator; +}; + template class ObjectPool; @@ -465,6 +622,13 @@ class ObjectPool : public BitMapObjectPool }; #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP + +template +struct ObjectPoolIterator +{ + using Type = typename HeapObjectPool::ActiveObjectIterator; +}; + template class ObjectPool : public HeapObjectPool { diff --git a/src/lib/support/tests/TestPool.cpp b/src/lib/support/tests/TestPool.cpp index b78d2b3e281107..963a7b3c52f7ea 100644 --- a/src/lib/support/tests/TestPool.cpp +++ b/src/lib/support/tests/TestPool.cpp @@ -234,25 +234,54 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) objIds.insert(i); } + // Default constructor of an iterator should be pointing to the pool end. + { + typename ObjectPoolIterator::Type defaultIterator; + NL_TEST_ASSERT(inSuite, defaultIterator == pool.end()); + } + // Verify that iteration visits all objects. size_t count = 0; - size_t sum = 0; - pool.ForEachActiveObject([&](S * object) { - NL_TEST_ASSERT(inSuite, object != nullptr); - if (object == nullptr) - { - // NL_TEST_ASSERT doesn't stop running the test and we want to avoid nullptr dereference. + { + size_t sum = 0; + pool.ForEachActiveObject([&](S * object) { + NL_TEST_ASSERT(inSuite, object != nullptr); + if (object == nullptr) + { + // NL_TEST_ASSERT doesn't stop running the test and we want to avoid nullptr dereference. + return Loop::Continue; + } + NL_TEST_ASSERT(inSuite, objIds.count(object->mId) == 1); + objIds.erase(object->mId); + ++count; + sum += object->mId; return Loop::Continue; + }); + NL_TEST_ASSERT(inSuite, count == kSize); + NL_TEST_ASSERT(inSuite, sum == kSize * (kSize - 1) / 2); + NL_TEST_ASSERT(inSuite, objIds.size() == 0); + } + + // Test begin/end iteration + { + // re-create the above test environment, this time using iterators + for (size_t i = 0; i < kSize; ++i) + { + objIds.insert(i); } - NL_TEST_ASSERT(inSuite, objIds.count(object->mId) == 1); - objIds.erase(object->mId); - ++count; - sum += object->mId; - return Loop::Continue; - }); - NL_TEST_ASSERT(inSuite, count == kSize); - NL_TEST_ASSERT(inSuite, sum == kSize * (kSize - 1) / 2); - NL_TEST_ASSERT(inSuite, objIds.size() == 0); + count = 0; + size_t sum = 0; + for (auto v = pool.begin(); v != pool.end(); ++v) + { + NL_TEST_ASSERT(inSuite, objIds.count((*v)->mId) == 1); + objIds.erase((*v)->mId); + ++count; + sum += (*v)->mId; + } + NL_TEST_ASSERT(inSuite, count == kSize); + NL_TEST_ASSERT(inSuite, sum == kSize * (kSize - 1) / 2); + NL_TEST_ASSERT(inSuite, objIds.size() == 0); + } // Verify that returning Loop::Break stops iterating. count = 0; @@ -285,6 +314,42 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, count == (kSize - 1) * kSize / 2); NL_TEST_ASSERT(inSuite, objIds.size() == 0); + // Verify that iteration can be nested for iterator types + { + count = 0; + for (auto v : pool) + { + objIds.insert(v->mId); + if (++count == kSize / 2) + { + break; + } + } + + count = 0; + for (auto outer : pool) + { + if (objIds.count(outer->mId) != 1) + { + continue; + } + + for (auto inner : pool) + { + if (inner == outer) + { + objIds.erase(inner->mId); + } + else + { + ++count; + } + } + } + NL_TEST_ASSERT(inSuite, count == (kSize - 1) * kSize / 2); + NL_TEST_ASSERT(inSuite, objIds.size() == 0); + } + count = 0; pool.ForEachActiveObject([&](S * object) { ++count; @@ -334,6 +399,68 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, count >= kSize / 2); NL_TEST_ASSERT(inSuite, count <= kSize); + // Test begin/end iteration + { + count = 0; + for (auto object : pool) + { + ++count; + if ((object->mId % 2) == 0) + { + objArray[object->mId] = nullptr; + // NOTE: this explicitly tests if pool supports releasing while iterating + // this MUST be supported by contract of Pool iterators + pool.ReleaseObject(object); + } + else + { + objIds.insert(object->mId); + } + } + NL_TEST_ASSERT(inSuite, count == kSize); + NL_TEST_ASSERT(inSuite, objIds.size() == kSize / 2); + + // validate we iterate only over active objects + for (auto object : pool) + { + NL_TEST_ASSERT(inSuite, (object->mId % 2) == 1); + } + + for (size_t i = 0; i < kSize; ++i) + { + if ((i % 2) == 0) + { + NL_TEST_ASSERT(inSuite, objArray[i] == nullptr); + } + else + { + NL_TEST_ASSERT(inSuite, objArray[i] != nullptr); + NL_TEST_ASSERT(inSuite, objArray[i]->mId == i); + } + } + + count = 0; + for (auto object : pool) + { + ++count; + if ((object->mId % 2) != 1) + { + continue; + } + size_t id = object->mId - 1; + NL_TEST_ASSERT(inSuite, objArray[id] == nullptr); + objArray[id] = pool.CreateObject(id); + NL_TEST_ASSERT(inSuite, objArray[id] != nullptr); + } + for (size_t i = 0; i < kSize; ++i) + { + NL_TEST_ASSERT(inSuite, objArray[i] != nullptr); + NL_TEST_ASSERT(inSuite, objArray[i]->mId == i); + } + NL_TEST_ASSERT(inSuite, count >= kSize / 2); + NL_TEST_ASSERT(inSuite, count <= kSize); + } + pool.ReleaseAll(); } diff --git a/src/platform/ESP32/ConnectivityManagerImpl_WiFi.cpp b/src/platform/ESP32/ConnectivityManagerImpl_WiFi.cpp index 8fb52e7bb71629..5fefcb5490f059 100644 --- a/src/platform/ESP32/ConnectivityManagerImpl_WiFi.cpp +++ b/src/platform/ESP32/ConnectivityManagerImpl_WiFi.cpp @@ -1119,8 +1119,8 @@ void ConnectivityManagerImpl::OnStationIPv6AddressAvailable(const ip_event_got_i { uint8_t dig1 = (station_mac[i] & 0xF0) >> 4; uint8_t dig2 = station_mac[i] & 0x0F; - station_mac_str[2 * i] = dig1 > 9 ? ('A' + dig1 - 0xA) : ('0' + dig1); - station_mac_str[2 * i + 1] = dig2 > 9 ? ('A' + dig2 - 0xA) : ('0' + dig2); + station_mac_str[2 * i] = static_cast(dig1 > 9 ? ('A' + dig1 - 0xA) : ('0' + dig1)); + station_mac_str[2 * i + 1] = static_cast(dig2 > 9 ? ('A' + dig2 - 0xA) : ('0' + dig2)); } if (sEndpointQueueFilter.SetMdnsHostName(chip::CharSpan(station_mac_str)) == CHIP_NO_ERROR) { diff --git a/src/platform/ESP32/ESP32EndpointQueueFilter.h b/src/platform/ESP32/ESP32EndpointQueueFilter.h index e7d154dcf458af..031ea29b64d798 100644 --- a/src/platform/ESP32/ESP32EndpointQueueFilter.h +++ b/src/platform/ESP32/ESP32EndpointQueueFilter.h @@ -103,7 +103,7 @@ class ESP32EndpointQueueFilter : public EndpointQueueFilter { if (hostNameLowerCase[i] <= 'F' && hostNameLowerCase[i] >= 'A') { - hostNameLowerCase[i] = 'a' + hostNameLowerCase[i] - 'A'; + hostNameLowerCase[i] = static_cast('a' + hostNameLowerCase[i] - 'A'); } } return PayloadContains(payload, ByteSpan(mHostNameBuffer)) || PayloadContains(payload, ByteSpan(hostNameLowerCase)); diff --git a/src/platform/silabs/rs911x/rsi_ble_config.h b/src/platform/silabs/rs911x/rsi_ble_config.h index bf40cad514dada..72f830b423ef9d 100644 --- a/src/platform/silabs/rs911x/rsi_ble_config.h +++ b/src/platform/silabs/rs911x/rsi_ble_config.h @@ -14,9 +14,7 @@ * sections of the MSLA applicable to Source Code. * ******************************************************************************/ - -#ifndef RSI_BLE_CONFIG_H -#define RSI_BLE_CONFIG_H +#pragma once #include "rsi_ble_apis.h" #if (SIWX_917 | EXP_BOARD) @@ -315,6 +313,4 @@ typedef struct rsi_ble_s uint16_t DATA_ix; uint16_t att_rec_list_count; rsi_ble_att_list_t att_rec_list[NO_OF_VAL_ATT]; -} rsi_ble_t; - -#endif \ No newline at end of file +} rsi_ble_t; \ No newline at end of file diff --git a/src/python_testing/TC_RVCOPSTATE_2_4.py b/src/python_testing/TC_RVCOPSTATE_2_4.py index 7352fbd089f172..9c07fd15de042f 100644 --- a/src/python_testing/TC_RVCOPSTATE_2_4.py +++ b/src/python_testing/TC_RVCOPSTATE_2_4.py @@ -119,47 +119,51 @@ async def test_TC_RVCOPSTATE_2_4(self): self.write_to_app_pipe('{"Name": "Reset"}') if self.check_pics("RVCOPSTATE.S.M.ST_ERROR"): - self.print_step(2, "Manually put the device in the ERROR operational state") + step_name = "Manually put the device in the ERROR operational state" + self.print_step(2, step_name) if self.is_ci: self.write_to_app_pipe('{"Name": "ErrorEvent", "Error": "UnableToStartOrResume"}') else: - input("Press Enter when done.\n") + self.wait_for_user_input(step_name) await self.read_operational_state_with_check(3, op_states.kError) await self.send_go_home_cmd_with_check(4, op_errors.kCommandInvalidInState) if self.check_pics("RVCOPSTATE.S.M.ST_CHARGING"): - self.print_step(5, "Manually put the device in the CHARGING operational state") + step_name = "Manually put the device in the CHARGING operational state" + self.print_step(5, step_name) if self.is_ci: self.write_to_app_pipe('{"Name": "Reset"}') self.write_to_app_pipe('{"Name": "Docked"}') self.write_to_app_pipe('{"Name": "Charging"}') else: - input("Press Enter when done.\n") + self.wait_for_user_input(step_name) await self.read_operational_state_with_check(6, rvc_op_states.kCharging) await self.send_go_home_cmd_with_check(7, op_errors.kCommandInvalidInState) if self.check_pics("RVCOPSTATE.S.M.ST_DOCKED"): - self.print_step(8, "Manually put the device in the DOCKED operational state") + step_name = "Manually put the device in the DOCKED operational state" + self.print_step(8, step_name) if self.is_ci: self.write_to_app_pipe('{"Name": "Charged"}') else: - input("Press Enter when done.\n") + self.wait_for_user_input(step_name) await self.read_operational_state_with_check(9, rvc_op_states.kDocked) await self.send_go_home_cmd_with_check(10, op_errors.kCommandInvalidInState) if self.check_pics("PICS_M_ST_SEEKING_CHARGER"): - self.print_step(8, "Manually put the device in the SEEKING CHARGER operational state") + step_name = "Manually put the device in the SEEKING CHARGER operational state" + self.print_step(8, step_name) if self.is_ci: await self.send_run_change_to_mode_cmd(rvc_app_run_mode_cleaning) await self.send_run_change_to_mode_cmd(rvc_app_run_mode_idle) else: - input("Press Enter when done.\n") + self.wait_for_user_input(step_name) await self.read_operational_state_with_check(9, rvc_op_states.kSeekingCharger) diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index 7efe5ab948966b..aee09dd1b93f09 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -346,6 +346,12 @@ def step_unknown(self): """ pass + def show_prompt(self, + msg: str, + placeholder: Optional[str] = None, + default_value: Optional[str] = None) -> None: + pass + @dataclass class MatterTestConfig: @@ -1091,6 +1097,28 @@ def get_setup_payload_info(self) -> SetupPayloadInfo: return info + def wait_for_user_input(self, + prompt_msg: str, + input_msg: str = "Press Enter when done.\n", + prompt_msg_placeholder: str = "Submit anything to continue", + default_value: str = "y") -> str: + """Ask for user input and wait for it. + + Args: + prompt_msg (str): Message for TH UI prompt. Indicates what is expected from the user. + input_msg (str, optional): Prompt for input function, used when running tests manually. Defaults to "Press Enter when done.\n". + prompt_msg_placeholder (str, optional): TH UI prompt input placeholder. Defaults to "Submit anything to continue". + default_value (str, optional): TH UI prompt default value. Defaults to "y". + + Returns: + str: User input + """ + if self.runner_hook: + self.runner_hook.show_prompt(msg=prompt_msg, + placeholder=prompt_msg_placeholder, + default_value=default_value) + return input(input_msg) + def generate_mobly_test_config(matter_test_config: MatterTestConfig): test_run_config = TestRunConfig() diff --git a/src/system/SystemLayer.h b/src/system/SystemLayer.h index 427bf00c99c3eb..d91a80d9be8f57 100644 --- a/src/system/SystemLayer.h +++ b/src/system/SystemLayer.h @@ -142,6 +142,9 @@ class DLL_EXPORT Layer * This method searches for the timer matching the provided parameters. * and returns whether it is still "running" and waiting to trigger or not. * + * @note This is used to verify by how long the ExtendTimer method extends the timer, as it may ignore an extension request + * if it is shorter than the current timer's remaining time. + * * @param[in] onComplete A pointer to the function called when timer expires. * @param[in] appState A pointer to the application state object used when timer expires. * @@ -150,6 +153,17 @@ class DLL_EXPORT Layer */ virtual bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) = 0; + /** + * @brief + * This method searches for the timer matching the provided parameters + * and returns the remaining time left before it expires. + * @param[in] onComplete A pointer to the function called when timer expires. + * @param[in] appState A pointer to the application state object used when timer expires. + * + * @return The remaining time left before the timer expires. + */ + virtual Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) = 0; + /** * @brief This method cancels a one-shot timer, started earlier through @p StartTimer(). This method must * be called while in the Matter context (from the Matter event loop, or while holding the Matter diff --git a/src/system/SystemLayerImplFreeRTOS.cpp b/src/system/SystemLayerImplFreeRTOS.cpp index cfc8e091208f86..59265f61d03693 100644 --- a/src/system/SystemLayerImplFreeRTOS.cpp +++ b/src/system/SystemLayerImplFreeRTOS.cpp @@ -96,6 +96,11 @@ bool LayerImplFreeRTOS::IsTimerActive(TimerCompleteCallback onComplete, void * a return (mTimerList.GetRemainingTime(onComplete, appState) > Clock::kZero); } +Clock::Timeout LayerImplFreeRTOS::GetRemainingTime(TimerCompleteCallback onComplete, void * appState) +{ + return mTimerList.GetRemainingTime(onComplete, appState); +} + void LayerImplFreeRTOS::CancelTimer(TimerCompleteCallback onComplete, void * appState) { assertChipStackLockedByCurrentThread(); diff --git a/src/system/SystemLayerImplFreeRTOS.h b/src/system/SystemLayerImplFreeRTOS.h index 2e7401dfce03ce..fe0e9be4bc7e33 100644 --- a/src/system/SystemLayerImplFreeRTOS.h +++ b/src/system/SystemLayerImplFreeRTOS.h @@ -42,6 +42,7 @@ class LayerImplFreeRTOS : public LayerFreeRTOS CHIP_ERROR StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override; CHIP_ERROR ExtendTimerTo(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override; bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) override; + Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) override; void CancelTimer(TimerCompleteCallback onComplete, void * appState) override; CHIP_ERROR ScheduleWork(TimerCompleteCallback onComplete, void * appState) override; diff --git a/src/system/SystemLayerImplSelect.cpp b/src/system/SystemLayerImplSelect.cpp index 7ae25a0a59d134..86ff1cb62da42f 100644 --- a/src/system/SystemLayerImplSelect.cpp +++ b/src/system/SystemLayerImplSelect.cpp @@ -255,6 +255,11 @@ bool LayerImplSelect::IsTimerActive(TimerCompleteCallback onComplete, void * app return timerIsActive; } +Clock::Timeout LayerImplSelect::GetRemainingTime(TimerCompleteCallback onComplete, void * appState) +{ + return mTimerList.GetRemainingTime(onComplete, appState); +} + void LayerImplSelect::CancelTimer(TimerCompleteCallback onComplete, void * appState) { assertChipStackLockedByCurrentThread(); diff --git a/src/system/SystemLayerImplSelect.h b/src/system/SystemLayerImplSelect.h index 060657e77a72ef..1bab3db9b5f39c 100644 --- a/src/system/SystemLayerImplSelect.h +++ b/src/system/SystemLayerImplSelect.h @@ -65,6 +65,7 @@ class LayerImplSelect : public LayerSocketsLoop CHIP_ERROR StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override; CHIP_ERROR ExtendTimerTo(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override; bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) override; + Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) override; void CancelTimer(TimerCompleteCallback onComplete, void * appState) override; CHIP_ERROR ScheduleWork(TimerCompleteCallback onComplete, void * appState) override; diff --git a/third_party/imgui/repo b/third_party/imgui/repo index 536090303a8fca..277ae93c41314b 160000 --- a/third_party/imgui/repo +++ b/third_party/imgui/repo @@ -1 +1 @@ -Subproject commit 536090303a8fca7d896f77d6d63dc59249bc87f4 +Subproject commit 277ae93c41314ba5f4c7444f37c4319cdf07e8cf diff --git a/third_party/mbedtls/repo b/third_party/mbedtls/repo index 039c903e7b2882..36e6bd69265609 160000 --- a/third_party/mbedtls/repo +++ b/third_party/mbedtls/repo @@ -1 +1 @@ -Subproject commit 039c903e7b2882af8e85ce5e090fd44e6a9d2289 +Subproject commit 36e6bd6926560933583dc04a7f92f69bdbafe8bd diff --git a/third_party/nanopb/repo b/third_party/nanopb/repo index 1f0c2e19c661f1..41319af88e569d 160000 --- a/third_party/nanopb/repo +++ b/third_party/nanopb/repo @@ -1 +1 @@ -Subproject commit 1f0c2e19c661f18dd88428858b8e965a26589e03 +Subproject commit 41319af88e569d4af31ea28a08fd2580a1f6655c diff --git a/third_party/openthread/repo b/third_party/openthread/repo index 33574ad4175ffb..f0b6fcea6ef77c 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit 33574ad4175ffb088bcca047f4c8d5fb240d1495 +Subproject commit f0b6fcea6ef77c9a54ab11767593f9a8798e3662 diff --git a/third_party/pigweed/repo b/third_party/pigweed/repo index 5165b9c17a9933..544a7b57c35e11 160000 --- a/third_party/pigweed/repo +++ b/third_party/pigweed/repo @@ -1 +1 @@ -Subproject commit 5165b9c17a9933b8d0714ef701421bf065d5d66a +Subproject commit 544a7b57c35e11690c73c390625a86a9e9a3ae51 diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index fc5a2bd789227b..32b62631ed30fd 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -9794,6 +9794,7 @@ namespace StayActiveRequest { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + encoder.Encode(to_underlying(Fields::kStayActiveDuration), stayActiveDuration); return encoder.Finalize(); } @@ -9807,6 +9808,19 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) { return std::get(__element); } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kStayActiveDuration)) + { + err = DataModel::Decode(reader, stayActiveDuration); + } + else + { + } + + ReturnErrorOnFailure(err); } } } // namespace StayActiveRequest. diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index dfdf2e691686f2..89c36f3c6f147d 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -13302,6 +13302,7 @@ struct DecodableType namespace StayActiveRequest { enum class Fields : uint8_t { + kStayActiveDuration = 0, }; struct Type @@ -13311,6 +13312,8 @@ struct Type static constexpr CommandId GetCommandId() { return Commands::StayActiveRequest::Id; } static constexpr ClusterId GetClusterId() { return Clusters::IcdManagement::Id; } + uint32_t stayActiveDuration = static_cast(0); + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; using ResponseType = Clusters::IcdManagement::Commands::StayActiveResponse::DecodableType; @@ -13324,6 +13327,7 @@ struct DecodableType static constexpr CommandId GetCommandId() { return Commands::StayActiveRequest::Id; } static constexpr ClusterId GetClusterId() { return Clusters::IcdManagement::Id; } + uint32_t stayActiveDuration = static_cast(0); CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace StayActiveRequest diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index 6191eb2aa3ec2d..8a3081edc0dc1b 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -4314,6 +4314,7 @@ class IcdManagementStayActiveRequest : public ClusterCommand IcdManagementStayActiveRequest(CredentialIssuerCommands * credsIssuerConfig) : ClusterCommand("stay-active-request", credsIssuerConfig) { + AddArgument("StayActiveDuration", 0, UINT32_MAX, &mRequest.stayActiveDuration); ClusterCommand::AddArguments(); } diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index 60843e78e103e7..be046cb6155993 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -47653,6 +47653,9 @@ class IcdManagementStayActiveRequest : public ClusterCommand { IcdManagementStayActiveRequest() : ClusterCommand("stay-active-request") { +#if MTR_ENABLE_PROVISIONAL + AddArgument("StayActiveDuration", 0, UINT32_MAX, &mRequest.stayActiveDuration); +#endif // MTR_ENABLE_PROVISIONAL ClusterCommand::AddArguments(); } @@ -47667,6 +47670,9 @@ class IcdManagementStayActiveRequest : public ClusterCommand { __auto_type * cluster = [[MTRBaseClusterICDManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRICDManagementClusterStayActiveRequestParams alloc] init]; params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; +#if MTR_ENABLE_PROVISIONAL + params.stayActiveDuration = [NSNumber numberWithUnsignedInt:mRequest.stayActiveDuration]; +#endif // MTR_ENABLE_PROVISIONAL uint16_t repeatCount = mRepeatCount.ValueOr(1); uint16_t __block responsesNeeded = repeatCount; while (repeatCount--) { @@ -47693,6 +47699,7 @@ class IcdManagementStayActiveRequest : public ClusterCommand { } private: + chip::app::Clusters::IcdManagement::Commands::StayActiveRequest::Type mRequest; }; #endif // MTR_ENABLE_PROVISIONAL