diff --git a/.github/workflows/examples-efr32.yaml b/.github/workflows/examples-efr32.yaml index d9df0bca21637f..b0b4fef50e15df 100644 --- a/.github/workflows/examples-efr32.yaml +++ b/.github/workflows/examples-efr32.yaml @@ -41,7 +41,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: ghcr.io/project-chip/chip-build-efr32:84 + image: ghcr.io/project-chip/chip-build-efr32:85 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/.github/workflows/release_artifacts.yaml b/.github/workflows/release_artifacts.yaml index af90dc316d0f4a..54997b6efa9b39 100644 --- a/.github/workflows/release_artifacts.yaml +++ b/.github/workflows/release_artifacts.yaml @@ -64,7 +64,7 @@ jobs: runs-on: ubuntu-latest container: - image: ghcr.io/project-chip/chip-build-efr32:84 + image: ghcr.io/project-chip/chip-build-efr32:85 steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.gitmodules b/.gitmodules index 3f50d3079d4e03..c2b9a95a5e0345 100644 --- a/.gitmodules +++ b/.gitmodules @@ -213,7 +213,7 @@ [submodule "third_party/silabs/simplicity_sdk"] path = third_party/silabs/simplicity_sdk url = https://github.com/SiliconLabs/simplicity_sdk.git - branch = v2024.6.1-0 + branch = v2024.6.2 platforms = silabs [submodule "third_party/silabs/wiseconnect-wifi-bt-sdk"] path = third_party/silabs/wiseconnect-wifi-bt-sdk diff --git a/docs/development_controllers/chip-tool/chip_tool_guide.md b/docs/development_controllers/chip-tool/chip_tool_guide.md index 8aac8daa121812..81000368a47f0c 100644 --- a/docs/development_controllers/chip-tool/chip_tool_guide.md +++ b/docs/development_controllers/chip-tool/chip_tool_guide.md @@ -9,33 +9,29 @@ the setup payload or performing discovery actions.
-## Source files +## Installation -You can find source files of the CHIP Tool in the `examples/chip-tool` -directory. - -> **Note:** The CHIP Tool caches the configuration state in the -> `/tmp/chip_tool_config.ini` file. Deleting this and other `.ini` files in the -> `/tmp` directory can sometimes resolve issues related to stale configuration. +On Linux distributions +[running snapd](https://snapcraft.io/docs/installing-snapd), such as Ubuntu, the +CHIP Tool can be installed using the +[chip-tool snap](https://snapcraft.io/chip-tool). To do this, run: -> **Note:** To make the configuration persistent (since `/tmp` directory might -> be flushed at each reboot) you can change the directory where CHIP Tool caches -> its configuration by using the option `--storage-directory` +``` +sudo snap install chip-tool +``` -
+## Building from source -## Building and running the CHIP Tool +The source files of the CHIP Tool are available in the `examples/chip-tool` +directory. -Before you can use the CHIP Tool, you must compile it from source on Linux -(amd64/aarch64) or macOS. If you want to run it on Raspberry Pi, it must use a -64-bit OS. +The source can be compiled on Linux (amd64/aarch64) or macOS. If you want to run +it on Raspberry Pi, you must use a 64-bit OS. > **Note:** To ensure compatibility, always build the CHIP Tool and the Matter > device from the same revision of the `connectedhomeip` repository. -### Building the CHIP Tool - -To build and run the CHIP Tool: +To build the CHIP Tool: 1. Install all required packages for Matter and prepare the source code and the build system. Read the [Building Matter](../../guides/BUILDING.md) guide for @@ -50,10 +46,16 @@ To build and run the CHIP Tool: In this command, `BUILD_PATH` specifies where the target binaries are to be placed. -### Running the CHIP Tool +## Running the CHIP Tool + +If you installed the CHIP Tool as a snap, the command to run it would be: + +``` +$ chip-tool +``` -To check if the CHIP Tool runs correctly, execute the following command from the -`BUILD_PATH` directory: +If you compiled the CHIP Tool from source, it can be executed with the following +command from the `BUILD_PATH` directory: ``` $ ./chip-tool @@ -68,6 +70,13 @@ more complex command by appending it with sub-commands. Examples of specific commands and their use cases are described in the [Supported commands and options](#supported-commands-and-options) section. +> **Note:** The CHIP Tool caches the configuration state in the +> `/tmp/chip_tool_config.ini` file. Deleting this and other `.ini` files in the +> `/tmp` directory can sometimes resolve issues related to stale configuration. +> To make the configuration persistent you can change the directory where CHIP +> Tool caches its configuration by using the command line option +> `--storage-directory` +
## CHIP Tool modes diff --git a/examples/all-clusters-app/nxp/common/main/main.cpp b/examples/all-clusters-app/nxp/common/main/main.cpp index b2aadab98ceb8b..26772e9e600659 100644 --- a/examples/all-clusters-app/nxp/common/main/main.cpp +++ b/examples/all-clusters-app/nxp/common/main/main.cpp @@ -32,7 +32,7 @@ uint8_t __attribute__((section(".heap"))) ucHeap[configTOTAL_HEAP_SIZE]; using namespace ::chip::DeviceLayer; -extern "C" int main(int argc, char * argv[]) +int main(int argc, char * argv[]) { TaskHandle_t taskHandle; diff --git a/examples/contact-sensor-app/nxp/common/main.cpp b/examples/contact-sensor-app/nxp/common/main.cpp index d9672b5402c867..ee193927912eeb 100644 --- a/examples/contact-sensor-app/nxp/common/main.cpp +++ b/examples/contact-sensor-app/nxp/common/main.cpp @@ -30,7 +30,7 @@ extern "C" void main_task(void const * argument) chip::NXP::App::GetAppTask().Start(); } #else -extern "C" int main(int argc, char * argv[]) +int main(int argc, char * argv[]) { chip::DeviceLayer::PlatformMgrImpl().HardwareInit(); chip::NXP::App::GetAppTask().Start(); diff --git a/examples/laundry-washer-app/nxp/common/main/main.cpp b/examples/laundry-washer-app/nxp/common/main/main.cpp index b2aadab98ceb8b..26772e9e600659 100644 --- a/examples/laundry-washer-app/nxp/common/main/main.cpp +++ b/examples/laundry-washer-app/nxp/common/main/main.cpp @@ -32,7 +32,7 @@ uint8_t __attribute__((section(".heap"))) ucHeap[configTOTAL_HEAP_SIZE]; using namespace ::chip::DeviceLayer; -extern "C" int main(int argc, char * argv[]) +int main(int argc, char * argv[]) { TaskHandle_t taskHandle; diff --git a/examples/light-switch-app/genio/src/main.cpp b/examples/light-switch-app/genio/src/main.cpp index d545409c706913..564233716d1d9a 100644 --- a/examples/light-switch-app/genio/src/main.cpp +++ b/examples/light-switch-app/genio/src/main.cpp @@ -251,7 +251,7 @@ void vStartTask(void * pvParameters) * Main Function ****************************************************************************/ -extern "C" int main(void) +int main(void) { mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree); diff --git a/examples/light-switch-app/nrfconnect/README.md b/examples/light-switch-app/nrfconnect/README.md index 11e53793463570..02f7b500aa6270 100644 --- a/examples/light-switch-app/nrfconnect/README.md +++ b/examples/light-switch-app/nrfconnect/README.md @@ -638,7 +638,7 @@ same Matter network. To perform the unicast binding process, complete the following steps: 1. Build the CHIP Tool according to the steps from the - [CHIP Tool user guide](../../../docs/development_controllers/chip-tool/chip_tool_guide.md#building-and-running-the-chip-tool). + [CHIP Tool user guide](../../../docs/development_controllers/chip-tool/chip_tool_guide.md#building-from-source). 2. Go to the CHIP Tool build directory. 3. Add an ACL to the development kit that is programmed with the [Lighting Application Example](../../lighting-app/nrfconnect/README.md) by @@ -690,7 +690,7 @@ same Matter network. To perform the unicast binding process, complete the following steps: 1. Build the CHIP Tool according to the steps from the - [CHIP Tool user guide](../../../docs/development_controllers/chip-tool/chip_tool_guide.md#building-and-running-the-chip-tool). + [CHIP Tool user guide](../../../docs/development_controllers/chip-tool/chip_tool_guide.md#building-from-source). 2. Go to the CHIP Tool build directory. 3. Add the light switch device to the multicast group by running the following diff --git a/examples/lighting-app-data-mode-no-unique-id/linux/main.cpp b/examples/lighting-app-data-mode-no-unique-id/linux/main.cpp index 8e586b5cf56d54..56cafc2e527509 100644 --- a/examples/lighting-app-data-mode-no-unique-id/linux/main.cpp +++ b/examples/lighting-app-data-mode-no-unique-id/linux/main.cpp @@ -95,7 +95,7 @@ void ApplicationShutdown() } } -extern "C" int main(int argc, char * argv[]) +int main(int argc, char * argv[]) { if (ChipLinuxAppInit(argc, argv) != 0) { diff --git a/examples/lighting-app/genio/src/main.cpp b/examples/lighting-app/genio/src/main.cpp index 22f654eb5f2f50..2db77457d2e7b1 100644 --- a/examples/lighting-app/genio/src/main.cpp +++ b/examples/lighting-app/genio/src/main.cpp @@ -251,7 +251,7 @@ void vStartTask(void * pvParameters) * Main Function ****************************************************************************/ -extern "C" int main(void) +int main(void) { mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree); diff --git a/examples/lighting-app/linux/main.cpp b/examples/lighting-app/linux/main.cpp index 8e586b5cf56d54..46dea03cdebccb 100644 --- a/examples/lighting-app/linux/main.cpp +++ b/examples/lighting-app/linux/main.cpp @@ -95,7 +95,14 @@ void ApplicationShutdown() } } -extern "C" int main(int argc, char * argv[]) +#ifdef __NuttX__ +// NuttX requires the main function to be defined with C-linkage. However, marking +// the main as extern "C" is not strictly conformant with the C++ standard. Since +// clang >= 20 such code triggers -Wmain warning. +extern "C" { +#endif + +int main(int argc, char * argv[]) { if (ChipLinuxAppInit(argc, argv) != 0) { @@ -124,3 +131,7 @@ extern "C" int main(int argc, char * argv[]) return 0; } + +#ifdef __NuttX__ +} +#endif diff --git a/examples/lighting-app/nxp/common/main.cpp b/examples/lighting-app/nxp/common/main.cpp index d9672b5402c867..ee193927912eeb 100644 --- a/examples/lighting-app/nxp/common/main.cpp +++ b/examples/lighting-app/nxp/common/main.cpp @@ -30,7 +30,7 @@ extern "C" void main_task(void const * argument) chip::NXP::App::GetAppTask().Start(); } #else -extern "C" int main(int argc, char * argv[]) +int main(int argc, char * argv[]) { chip::DeviceLayer::PlatformMgrImpl().HardwareInit(); chip::NXP::App::GetAppTask().Start(); diff --git a/examples/lock-app/genio/src/main.cpp b/examples/lock-app/genio/src/main.cpp index 92b16a39663ee4..36564e13330f93 100644 --- a/examples/lock-app/genio/src/main.cpp +++ b/examples/lock-app/genio/src/main.cpp @@ -251,7 +251,7 @@ void vStartTask(void * pvParameters) * Main Function ****************************************************************************/ -extern "C" int main(void) +int main(void) { mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree); diff --git a/examples/lock-app/nxp/common/main/main.cpp b/examples/lock-app/nxp/common/main/main.cpp index 09de048127518b..8565ca01af32e9 100644 --- a/examples/lock-app/nxp/common/main/main.cpp +++ b/examples/lock-app/nxp/common/main/main.cpp @@ -39,7 +39,7 @@ extern "C" void main_task(void const * argument) chip::NXP::App::GetAppTask().Start(); } #else -extern "C" int main(int argc, char * argv[]) +int main(int argc, char * argv[]) { chip::DeviceLayer::PlatformMgrImpl().HardwareInit(); chip::NXP::App::GetAppTask().Start(); diff --git a/examples/ota-requestor-app/genio/src/main.cpp b/examples/ota-requestor-app/genio/src/main.cpp index e3676c5c9eacbd..6c9f4f16c274f4 100644 --- a/examples/ota-requestor-app/genio/src/main.cpp +++ b/examples/ota-requestor-app/genio/src/main.cpp @@ -281,7 +281,7 @@ void vStartTask(void * pvParameters) * Main Function ****************************************************************************/ -extern "C" int main(void) +int main(void) { mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree); diff --git a/examples/platform/openiotsdk/app/openiotsdk_startup_gcc.cpp b/examples/platform/openiotsdk/app/openiotsdk_startup_gcc.cpp index 9add2ca4e53777..88488ff64763da 100644 --- a/examples/platform/openiotsdk/app/openiotsdk_startup_gcc.cpp +++ b/examples/platform/openiotsdk/app/openiotsdk_startup_gcc.cpp @@ -57,7 +57,7 @@ alignas(8) static uint8_t malloc_mutex_obj[80]; // C runtime import: constructor initialization and main extern "C" void __libc_init_array(void); -extern "C" int main(void); +int main(void); // IOT SDK serial declarations #define STDIN_FILENO 0 diff --git a/examples/shell/genio/src/main.cpp b/examples/shell/genio/src/main.cpp index 7190fd232a0969..fb4b3e068a0d0c 100644 --- a/examples/shell/genio/src/main.cpp +++ b/examples/shell/genio/src/main.cpp @@ -161,7 +161,7 @@ void vStartTask(void * pvParameters) * Main Function ****************************************************************************/ -extern "C" int main(void) +int main(void) { mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree); diff --git a/examples/thermostat/genio/src/main.cpp b/examples/thermostat/genio/src/main.cpp index d545409c706913..564233716d1d9a 100644 --- a/examples/thermostat/genio/src/main.cpp +++ b/examples/thermostat/genio/src/main.cpp @@ -251,7 +251,7 @@ void vStartTask(void * pvParameters) * Main Function ****************************************************************************/ -extern "C" int main(void) +int main(void) { mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree); diff --git a/examples/thermostat/nxp/common/main/main.cpp b/examples/thermostat/nxp/common/main/main.cpp index b2aadab98ceb8b..26772e9e600659 100644 --- a/examples/thermostat/nxp/common/main/main.cpp +++ b/examples/thermostat/nxp/common/main/main.cpp @@ -32,7 +32,7 @@ uint8_t __attribute__((section(".heap"))) ucHeap[configTOTAL_HEAP_SIZE]; using namespace ::chip::DeviceLayer; -extern "C" int main(int argc, char * argv[]) +int main(int argc, char * argv[]) { TaskHandle_t taskHandle; diff --git a/integrations/cloudbuild/smoke-test.yaml b/integrations/cloudbuild/smoke-test.yaml index 24a3029d2fe2f8..824b79d6ce1a22 100644 --- a/integrations/cloudbuild/smoke-test.yaml +++ b/integrations/cloudbuild/smoke-test.yaml @@ -1,5 +1,5 @@ steps: - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" entrypoint: "bash" args: - "-c" @@ -7,7 +7,7 @@ steps: git config --global --add safe.directory "*" python scripts/checkout_submodules.py --shallow --recursive --platform esp32 nrfconnect silabs linux android id: Submodules - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" # NOTE: silabs boostrap is NOT done with the rest as it requests a conflicting # jinja2 version (asks for 3.1.3 when constraints.txt asks for 3.0.3) env: @@ -24,7 +24,7 @@ steps: path: /pwenv timeout: 900s - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" id: ESP32 env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -45,7 +45,7 @@ steps: volumes: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" id: NRFConnect env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -66,7 +66,7 @@ steps: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" id: EFR32 env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -88,7 +88,7 @@ steps: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" id: Linux env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -141,7 +141,7 @@ steps: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:84" + - name: "ghcr.io/project-chip/chip-build-vscode:85" id: Android env: - PW_ENVIRONMENT_ROOT=/pwenv diff --git a/scripts/BUILD.gn b/scripts/BUILD.gn index 0ebcab979112ca..ea1d49662fcb11 100644 --- a/scripts/BUILD.gn +++ b/scripts/BUILD.gn @@ -20,8 +20,8 @@ import("$dir_pw_build/python_dist.gni") # This target creates a single Python package and wheel for yamltests. It will # merge all Python dependencies Matter. The output is located in: -# out/obj/matter_yamltests_distribution/ <- source files here -# out/obj/matter_yamltests_distribution._build_wheel/matter_yamltests-0.0.1-py3-none-any.whl +# out/obj/scripts/matter_yamltests_distribution/ <- source files here +# out/obj/scripts/matter_yamltests_distribution._build_wheel/matter_yamltests-0.0.1-py3-none-any.whl pw_python_distribution("matter_yamltests_distribution") { packages = [ "${chip_root}/scripts/py_matter_yamltests:matter_yamltests" ] generate_setup_cfg = { diff --git a/scripts/build_python.sh b/scripts/build_python.sh index da3fe0cbedf733..7f03815f3fe7e3 100755 --- a/scripts/build_python.sh +++ b/scripts/build_python.sh @@ -175,22 +175,6 @@ tracing_options="matter_log_json_payload_hex=true matter_log_json_payload_decode gn --root="$CHIP_ROOT" gen "$OUTPUT_ROOT" --args="$tracing_options chip_detail_logging=$chip_detail_logging chip_project_config_include_dirs=[\"//config/python\"] $chip_mdns_arg $chip_case_retry_arg $pregen_dir_arg chip_config_network_layer_ble=$enable_ble chip_enable_ble=$enable_ble chip_crypto=\"boringssl\"" -function ninja_target() { - # Print the ninja target required to build a gn label. - local GN_LABEL="$1" - local NINJA_TARGET="$(gn ls "$OUTPUT_ROOT" --as=output "$GN_LABEL")" - echo "$NINJA_TARGET" -} - -function wheel_output_dir() { - # Print the wheel output directory for a pw_python_package or - # pw_python_distribution. The label must end in "._build_wheel". - local GN_LABEL="$1" - local NINJA_TARGET="$(ninja_target "$GN_LABEL")" - local WHEEL_DIR="$OUTPUT_ROOT"/"$(dirname "$NINJA_TARGET")/$(basename -s .stamp "$NINJA_TARGET")" - echo "$WHEEL_DIR" -} - # Compile Python wheels ninja -C "$OUTPUT_ROOT" python_wheels @@ -200,6 +184,11 @@ WHEEL=("$OUTPUT_ROOT"/controller/python/chip*.whl) # Add the matter_testing_infrastructure wheel WHEEL+=("$OUTPUT_ROOT"/python/obj/src/python_testing/matter_testing_infrastructure/chip-testing._build_wheel/chip_testing-*.whl) +if [ "$install_pytest_requirements" = "yes" ]; then + # Add the matter_yamltests_distribution wheel + WHEEL+=("$OUTPUT_ROOT"/obj/scripts/matter_yamltests_distribution._build_wheel/matter_yamltests-*.whl) +fi + if [ -n "$extra_packages" ]; then WHEEL+=("$extra_packages") fi @@ -221,14 +210,7 @@ if [ -n "$install_virtual_env" ]; then "$ENVIRONMENT_ROOT"/bin/python -m pip install --upgrade "${WHEEL[@]}" if [ "$install_pytest_requirements" = "yes" ]; then - YAMLTESTS_GN_LABEL="//scripts:matter_yamltests_distribution._build_wheel" - # Add wheels from pw_python_package or pw_python_distribution templates. - YAMLTEST_WHEEL=( - "$(ls -tr "$(wheel_output_dir "$YAMLTESTS_GN_LABEL")"/*.whl | head -n 1)" - ) - echo_blue "Installing python test dependencies ..." - "$ENVIRONMENT_ROOT"/bin/pip install --upgrade "${YAMLTEST_WHEEL[@]}" "$ENVIRONMENT_ROOT"/bin/pip install -r "$CHIP_ROOT/scripts/tests/requirements.txt" "$ENVIRONMENT_ROOT"/bin/pip install -r "$CHIP_ROOT/src/python_testing/requirements.txt" fi 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 08215244b039aa..ec8cbd60457450 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 @@ -606,84 +606,82 @@ /* Endpoint: 0, Cluster: Unit Localization (server) */ \ { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x2 }, /* TemperatureUnit */ \ \ - /* Endpoint: 1, Cluster: On/Off (server) */ \ - { (uint16_t) 0xFF, (uint16_t) 0x0, (uint16_t) 0x2 }, /* StartUpOnOff */ \ - \ - /* Endpoint: 1, Cluster: Level Control (server) */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x3 }, /* Options */ \ - { (uint16_t) 0x32, (uint16_t) 0x1, (uint16_t) 0xFF }, /* DefaultMoveRate */ \ - \ - /* Endpoint: 1, Cluster: Laundry Washer Controls (server) */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x1F }, /* SpinSpeedCurrent */ \ - \ - /* Endpoint: 1, Cluster: Smoke CO Alarm (server) */ \ - { (uint16_t) 0x1, (uint16_t) 0x0, (uint16_t) 0x2 }, /* SmokeSensitivityLevel */ \ - \ - /* Endpoint: 1, Cluster: Valve Configuration and Control (server) */ \ - { (uint16_t) 0x64, (uint16_t) 0x1, (uint16_t) 0x64 }, /* DefaultOpenLevel */ \ - \ - /* Endpoint: 1, Cluster: Energy EVSE (server) */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFFFE }, /* ApproximateEVEfficiency */ \ - \ - /* Endpoint: 1, Cluster: Window Covering (server) */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xF }, /* Mode */ \ - \ - /* Endpoint: 1, Cluster: Pump Configuration and Control (server) */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x3 }, /* OperationMode */ \ - { (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) 0x7F }, /* 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 */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x64 }, /* PercentSetting */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x64 }, /* SpeedSetting */ \ - \ - /* Endpoint: 1, Cluster: Thermostat User Interface Configuration (server) */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x1 }, /* TemperatureDisplayMode */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x5 }, /* KeypadLockout */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x1 }, /* ScheduleProgrammingVisibility */ \ - \ - /* Endpoint: 1, Cluster: Color Control (server) */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* WhitePointX */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* WhitePointY */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointRX */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointRY */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointGX */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointGY */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointBX */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointBY */ \ - { (uint16_t) 0xFA, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* StartUpColorTemperatureMireds */ \ - \ - /* Endpoint: 1, Cluster: Ballast Configuration (server) */ \ - { (uint16_t) 0x1, (uint16_t) 0x1, (uint16_t) 0xFE }, /* MinLevel */ \ - { (uint16_t) 0xFE, (uint16_t) 0x1, (uint16_t) 0xFE }, /* MaxLevel */ \ - { (uint16_t) 0xFF, (uint16_t) 0x64, (uint16_t) 0xFFFF }, /* BallastFactorAdjustment */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x1 }, /* LampAlarmMode */ \ - \ - /* 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 */ \ + /* Endpoint: 1, Cluster: On/Off (server) */ \ + { (uint16_t) 0xFF, (uint16_t) 0x0, (uint16_t) 0x2 }, /* StartUpOnOff */ \ + \ + /* Endpoint: 1, Cluster: Level Control (server) */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x3 }, /* Options */ \ + { (uint16_t) 0x32, (uint16_t) 0x1, (uint16_t) 0xFF }, /* DefaultMoveRate */ \ + \ + /* Endpoint: 1, Cluster: Laundry Washer Controls (server) */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x1F }, /* SpinSpeedCurrent */ \ + \ + /* Endpoint: 1, Cluster: Smoke CO Alarm (server) */ \ + { (uint16_t) 0x1, (uint16_t) 0x0, (uint16_t) 0x2 }, /* SmokeSensitivityLevel */ \ + \ + /* Endpoint: 1, Cluster: Valve Configuration and Control (server) */ \ + { (uint16_t) 0x64, (uint16_t) 0x1, (uint16_t) 0x64 }, /* DefaultOpenLevel */ \ + \ + /* Endpoint: 1, Cluster: Energy EVSE (server) */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFFFE }, /* ApproximateEVEfficiency */ \ + \ + /* Endpoint: 1, Cluster: Window Covering (server) */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xF }, /* Mode */ \ + \ + /* Endpoint: 1, Cluster: Pump Configuration and Control (server) */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x3 }, /* OperationMode */ \ + { (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) 0x7F }, /* 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 */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x64 }, /* PercentSetting */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x64 }, /* SpeedSetting */ \ + \ + /* Endpoint: 1, Cluster: Thermostat User Interface Configuration (server) */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x1 }, /* TemperatureDisplayMode */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x5 }, /* KeypadLockout */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x1 }, /* ScheduleProgrammingVisibility */ \ + \ + /* Endpoint: 1, Cluster: Color Control (server) */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* WhitePointX */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* WhitePointY */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointRX */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointRY */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointGX */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointGY */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointBX */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* ColorPointBY */ \ + { (uint16_t) 0xFA, (uint16_t) 0x0, (uint16_t) 0xFEFF }, /* StartUpColorTemperatureMireds */ \ + \ + /* Endpoint: 1, Cluster: Ballast Configuration (server) */ \ + { (uint16_t) 0x1, (uint16_t) 0x1, (uint16_t) 0xFE }, /* MinLevel */ \ + { (uint16_t) 0xFE, (uint16_t) 0x1, (uint16_t) 0xFE }, /* MaxLevel */ \ + { (uint16_t) 0xFF, (uint16_t) 0x64, (uint16_t) 0xFFFF }, /* BallastFactorAdjustment */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x1 }, /* LampAlarmMode */ \ + \ + /* 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 */ \ \ /* Endpoint: 2, Cluster: On/Off (server) */ \ - { \ - (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x2 \ - } /* StartUpOnOff */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x2 } /* StartUpOnOff */ \ } // This is an array of EmberAfAttributeMetadata structures. @@ -4394,12 +4392,8 @@ static_assert(ATTRIBUTE_LARGEST <= CHIP_CONFIG_MAX_ATTRIBUTE_STORE_ELEMENT_SIZE, // Array of device types #define FIXED_DEVICE_TYPES \ - { \ - { 0x00000011, 1 }, { 0x00000016, 1 }, { 0x00000100, 1 }, { 0x00000011, 1 }, { 0x00000100, 1 }, { 0x00000011, 1 }, \ - { \ - 0x00000019, 1 \ - } \ - } + { { 0x00000011, 1 }, { 0x00000016, 1 }, { 0x00000100, 1 }, { 0x00000011, 1 }, \ + { 0x00000100, 1 }, { 0x00000011, 1 }, { 0x00000019, 1 } } // Array of device type offsets #define FIXED_DEVICE_TYPE_OFFSETS { 0, 2, 4, 6 } diff --git a/scripts/tools/zap/tests/outputs/lighting-app/app-templates/endpoint_config.h b/scripts/tools/zap/tests/outputs/lighting-app/app-templates/endpoint_config.h index fa214e1686690b..6395681cf33469 100644 --- a/scripts/tools/zap/tests/outputs/lighting-app/app-templates/endpoint_config.h +++ b/scripts/tools/zap/tests/outputs/lighting-app/app-templates/endpoint_config.h @@ -118,14 +118,12 @@ /* Endpoint: 1, Cluster: On/Off (server) */ \ { (uint16_t) 0xFF, (uint16_t) 0x0, (uint16_t) 0x2 }, /* StartUpOnOff */ \ \ - /* Endpoint: 1, Cluster: Level Control (server) */ \ - { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x3 }, /* Options */ \ - { (uint16_t) 0x32, (uint16_t) 0x1, (uint16_t) 0xFF }, /* DefaultMoveRate */ \ + /* Endpoint: 1, Cluster: Level Control (server) */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x3 }, /* Options */ \ + { (uint16_t) 0x32, (uint16_t) 0x1, (uint16_t) 0xFF }, /* DefaultMoveRate */ \ \ /* Endpoint: 1, Cluster: Color Control (server) */ \ - { \ - (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF \ - } /* StartUpColorTemperatureMireds */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0xFEFF } /* StartUpColorTemperatureMireds */ \ } // This is an array of EmberAfAttributeMetadata structures. @@ -1233,13 +1231,7 @@ static_assert(ATTRIBUTE_LARGEST <= CHIP_CONFIG_MAX_ATTRIBUTE_STORE_ELEMENT_SIZE, #define FIXED_PROFILE_IDS { 0x0103, 0x0103 } // Array of device types -#define FIXED_DEVICE_TYPES \ - { \ - { 0x00000016, 1 }, \ - { \ - 0x00000101, 1 \ - } \ - } +#define FIXED_DEVICE_TYPES { { 0x00000016, 1 }, { 0x00000101, 1 } } // Array of device type offsets #define FIXED_DEVICE_TYPE_OFFSETS { 0, 1 } diff --git a/src/app/clusters/thermostat-server/thermostat-server-presets.cpp b/src/app/clusters/thermostat-server/thermostat-server-presets.cpp index 9413513fd0cedd..1dede071619962 100644 --- a/src/app/clusters/thermostat-server/thermostat-server-presets.cpp +++ b/src/app/clusters/thermostat-server/thermostat-server-presets.cpp @@ -152,69 +152,36 @@ bool GetMatchingPresetInPresets(Delegate * delegate, const DataModel::NullableGetPendingPresetAtIndex(i, pendingPreset); - + PresetTypeStruct::Type presetType; + auto err = delegate->GetPresetTypeAtIndex(i, presetType); if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) { - break; + // We exhausted the list trying to find the preset scenario + return CHIP_NO_ERROR; } if (err != CHIP_NO_ERROR) { - ChipLogError(Zcl, "CountNumberOfPendingPresets: GetPendingPresetAtIndex failed with error %" CHIP_ERROR_FORMAT, - err.Format()); - return 0; + return err; } - numberOfPendingPresets++; - } - - return numberOfPendingPresets; -} - -/** - * @brief Checks if the presetScenario is present in the PresetTypes attribute. - * - * @param[in] delegate The delegate to use. - * @param[in] presetScenario The presetScenario to match with. - * - * @return true if the presetScenario is found, false otherwise. - */ -bool PresetScenarioExistsInPresetTypes(Delegate * delegate, PresetScenarioEnum presetScenario) -{ - VerifyOrReturnValue(delegate != nullptr, false); - - for (uint8_t i = 0; true; i++) - { - PresetTypeStruct::Type presetType; - auto err = delegate->GetPresetTypeAtIndex(i, presetType); - if (err != CHIP_NO_ERROR) - { - return false; - } - if (presetType.presetScenario == presetScenario) { - return true; + count = presetType.numberOfPresets; + return CHIP_NO_ERROR; } } - return false; + return CHIP_NO_ERROR; } /** @@ -410,8 +377,16 @@ CHIP_ERROR ThermostatAttrAccess::AppendPendingPreset(Thermostat::Delegate * dele } } - if (!PresetScenarioExistsInPresetTypes(delegate, preset.GetPresetScenario())) + size_t maximumPresetCount = delegate->GetNumberOfPresets(); + size_t maximumPresetScenarioCount = 0; + if (MaximumPresetScenarioCount(delegate, preset.GetPresetScenario(), maximumPresetScenarioCount) != CHIP_NO_ERROR) { + return CHIP_IM_GLOBAL_STATUS(InvalidInState); + } + + if (maximumPresetScenarioCount == 0) + { + // This is not a supported preset scenario return CHIP_IM_GLOBAL_STATUS(ConstraintError); } @@ -423,16 +398,42 @@ CHIP_ERROR ThermostatAttrAccess::AppendPendingPreset(Thermostat::Delegate * dele // Before adding this preset to the pending presets, if the expected length of the pending presets' list // exceeds the total number of presets supported, return RESOURCE_EXHAUSTED. Note that the preset has not been appended yet. - uint8_t numberOfPendingPresets = CountNumberOfPendingPresets(delegate); + // We're going to append this preset, so let's assume a count as though it had already been inserted + size_t presetCount = 1; + size_t presetScenarioCount = 1; + for (uint8_t i = 0; true; i++) + { + PresetStructWithOwnedMembers otherPreset; + CHIP_ERROR err = delegate->GetPendingPresetAtIndex(i, otherPreset); + + if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) + { + break; + } + if (err != CHIP_NO_ERROR) + { + return CHIP_IM_GLOBAL_STATUS(InvalidInState); + } + presetCount++; + if (preset.GetPresetScenario() == otherPreset.GetPresetScenario()) + { + presetScenarioCount++; + } + } - // We will be adding one more preset, so reject if the length is already at max. - if (numberOfPendingPresets >= delegate->GetNumberOfPresets()) + if (presetCount > maximumPresetCount) { + ChipLogError(Zcl, "Preset count exceeded %u: %u ", static_cast(maximumPresetCount), + static_cast(presetCount)); return CHIP_IM_GLOBAL_STATUS(ResourceExhausted); } - // TODO #34556 : Check if the number of presets for each presetScenario exceeds the max number of presets supported for that - // scenario. We plan to support only one preset for each presetScenario for our use cases so defer this for re-evaluation. + if (presetScenarioCount > maximumPresetScenarioCount) + { + ChipLogError(Zcl, "Preset scenario count exceeded %u: %u ", static_cast(maximumPresetScenarioCount), + static_cast(presetScenarioCount)); + return CHIP_IM_GLOBAL_STATUS(ResourceExhausted); + } return delegate->AppendToPendingPresetList(preset); } diff --git a/src/app/tests/suites/certification/Test_TC_LVL_2_1.yaml b/src/app/tests/suites/certification/Test_TC_LVL_2_1.yaml index 8e9ee05b33e9ff..aa0fbcfddc83bf 100644 --- a/src/app/tests/suites/certification/Test_TC_LVL_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_LVL_2_1.yaml @@ -188,6 +188,16 @@ tests: minValue: MinLevelFeatureMapNotSupportedValue maxValue: MaxLevelFeatureMapNotSupportedValue + - label: "Step 9c: TH reads the OnLevel attribute from the DUT" + PICS: LVL.S.A0011 && !LVL.S.F01 && !LVL.S.A0002 && !LVL.S.A0003 + command: "readAttribute" + attribute: "OnLevel" + response: + constraints: + type: int8u + minValue: 0 + maxValue: 254 + - label: "Step 10: TH reads the OnTransitionTime attribute from the DUT" PICS: LVL.S.A0012 command: "readAttribute" diff --git a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml index f7f5699ef8fccf..ff485bbf6bba81 100644 --- a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml +++ b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml @@ -2698,4 +2698,47 @@ limitations under the License. + + MA-waterheater + CHIP + Water Heater + 0x0103 + 0x050F + Simple + Endpoint + + + CLIENT_LIST + DEVICE_TYPE_LIST + PARTS_LIST + SERVER_LIST + + + IDENTIFY_TIME + IDENTIFY_TYPE + Identify + + + CONTROL_SEQUENCE_OF_OPERATION + LOCAL_TEMPERATURE + SYSTEM_MODE + SetpointRaiseLower + + + BOOST_STATE + HEATER_TYPES + HEAT_DEMAND + BoostEnded + BoostStarted + Boost + CancelBoost + + + CURRENT_MODE + SUPPORTED_MODES + ChangeToMode + ChangeToModeResponse + + + diff --git a/src/darwin/Framework/CHIP/MTRBaseDevice.mm b/src/darwin/Framework/CHIP/MTRBaseDevice.mm index a298b296849d51..2f75038eda97a2 100644 --- a/src/darwin/Framework/CHIP/MTRBaseDevice.mm +++ b/src/darwin/Framework/CHIP/MTRBaseDevice.mm @@ -613,7 +613,9 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue } } -static CHIP_ERROR MTREncodeTLVFromDataValueDictionaryInternal(id object, chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) +// writer is allowed to be null to just validate the incoming object without +// actually encoding. +static CHIP_ERROR MTREncodeTLVFromDataValueDictionaryInternal(id object, chip::TLV::TLVWriter * writer, chip::TLV::Tag tag) { if (![object isKindOfClass:[NSDictionary class]]) { MTR_LOG_ERROR("Error: Unsupported object to encode: %@", [object class]); @@ -631,60 +633,62 @@ static CHIP_ERROR MTREncodeTLVFromDataValueDictionaryInternal(id object, chip::T MTR_LOG_ERROR("Error: Object to encode has corrupt signed integer type: %@", [value class]); return CHIP_ERROR_INVALID_ARGUMENT; } - return writer.Put(tag, [value longLongValue]); + return writer ? writer->Put(tag, [value longLongValue]) : CHIP_NO_ERROR; } if ([typeName isEqualToString:MTRUnsignedIntegerValueType]) { if (![value isKindOfClass:[NSNumber class]]) { MTR_LOG_ERROR("Error: Object to encode has corrupt unsigned integer type: %@", [value class]); return CHIP_ERROR_INVALID_ARGUMENT; } - return writer.Put(tag, [value unsignedLongLongValue]); + return writer ? writer->Put(tag, [value unsignedLongLongValue]) : CHIP_NO_ERROR; } if ([typeName isEqualToString:MTRBooleanValueType]) { if (![value isKindOfClass:[NSNumber class]]) { MTR_LOG_ERROR("Error: Object to encode has corrupt boolean type: %@", [value class]); return CHIP_ERROR_INVALID_ARGUMENT; } - return writer.Put(tag, static_cast([value boolValue])); + return writer ? writer->Put(tag, static_cast([value boolValue])) : CHIP_NO_ERROR; } if ([typeName isEqualToString:MTRFloatValueType]) { if (![value isKindOfClass:[NSNumber class]]) { MTR_LOG_ERROR("Error: Object to encode has corrupt float type: %@", [value class]); return CHIP_ERROR_INVALID_ARGUMENT; } - return writer.Put(tag, [value floatValue]); + return writer ? writer->Put(tag, [value floatValue]) : CHIP_NO_ERROR; } if ([typeName isEqualToString:MTRDoubleValueType]) { if (![value isKindOfClass:[NSNumber class]]) { MTR_LOG_ERROR("Error: Object to encode has corrupt double type: %@", [value class]); return CHIP_ERROR_INVALID_ARGUMENT; } - return writer.Put(tag, [value doubleValue]); + return writer ? writer->Put(tag, [value doubleValue]) : CHIP_NO_ERROR; } if ([typeName isEqualToString:MTRNullValueType]) { - return writer.PutNull(tag); + return writer ? writer->PutNull(tag) : CHIP_NO_ERROR; } if ([typeName isEqualToString:MTRUTF8StringValueType]) { if (![value isKindOfClass:[NSString class]]) { MTR_LOG_ERROR("Error: Object to encode has corrupt UTF8 string type: %@", [value class]); return CHIP_ERROR_INVALID_ARGUMENT; } - return writer.PutString(tag, AsCharSpan(value)); + return writer ? writer->PutString(tag, AsCharSpan(value)) : CHIP_NO_ERROR; } if ([typeName isEqualToString:MTROctetStringValueType]) { if (![value isKindOfClass:[NSData class]]) { MTR_LOG_ERROR("Error: Object to encode has corrupt octet string type: %@", [value class]); return CHIP_ERROR_INVALID_ARGUMENT; } - return writer.Put(tag, AsByteSpan(value)); + return writer ? writer->Put(tag, AsByteSpan(value)) : CHIP_NO_ERROR; } if ([typeName isEqualToString:MTRStructureValueType]) { if (![value isKindOfClass:[NSArray class]]) { MTR_LOG_ERROR("Error: Object to encode has corrupt structure type: %@", [value class]); return CHIP_ERROR_INVALID_ARGUMENT; } - TLV::TLVType outer; - ReturnErrorOnFailure(writer.StartContainer(tag, chip::TLV::kTLVType_Structure, outer)); + TLV::TLVType outer = TLV::kTLVType_NotSpecified; + if (writer) { + ReturnErrorOnFailure(writer->StartContainer(tag, chip::TLV::kTLVType_Structure, outer)); + } for (id element in value) { if (![element isKindOfClass:[NSDictionary class]]) { MTR_LOG_ERROR("Error: Structure element to encode has corrupt type: %@", [element class]); @@ -713,7 +717,9 @@ static CHIP_ERROR MTREncodeTLVFromDataValueDictionaryInternal(id object, chip::T ReturnErrorOnFailure( MTREncodeTLVFromDataValueDictionaryInternal(elementValue, writer, tag)); } - ReturnErrorOnFailure(writer.EndContainer(outer)); + if (writer) { + ReturnErrorOnFailure(writer->EndContainer(outer)); + } return CHIP_NO_ERROR; } if ([typeName isEqualToString:MTRArrayValueType]) { @@ -721,8 +727,10 @@ static CHIP_ERROR MTREncodeTLVFromDataValueDictionaryInternal(id object, chip::T MTR_LOG_ERROR("Error: Object to encode has corrupt array type: %@", [value class]); return CHIP_ERROR_INVALID_ARGUMENT; } - TLV::TLVType outer; - ReturnErrorOnFailure(writer.StartContainer(tag, chip::TLV::kTLVType_Array, outer)); + TLV::TLVType outer = TLV::kTLVType_NotSpecified; + if (writer) { + ReturnErrorOnFailure(writer->StartContainer(tag, chip::TLV::kTLVType_Array, outer)); + } for (id element in value) { if (![element isKindOfClass:[NSDictionary class]]) { MTR_LOG_ERROR("Error: Array element to encode has corrupt type: %@", [element class]); @@ -735,14 +743,16 @@ static CHIP_ERROR MTREncodeTLVFromDataValueDictionaryInternal(id object, chip::T } ReturnErrorOnFailure(MTREncodeTLVFromDataValueDictionaryInternal(elementValue, writer, chip::TLV::AnonymousTag())); } - ReturnErrorOnFailure(writer.EndContainer(outer)); + if (writer) { + ReturnErrorOnFailure(writer->EndContainer(outer)); + } return CHIP_NO_ERROR; } MTR_LOG_ERROR("Error: Unsupported type to encode: %@", typeName); return CHIP_ERROR_INVALID_ARGUMENT; } -static CHIP_ERROR MTREncodeTLVFromDataValueDictionary(id object, chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) +static CHIP_ERROR MTREncodeTLVFromDataValueDictionary(id object, chip::TLV::TLVWriter * writer, chip::TLV::Tag tag) { CHIP_ERROR err = MTREncodeTLVFromDataValueDictionaryInternal(object, writer, tag); if (err != CHIP_NO_ERROR) { @@ -761,7 +771,7 @@ static CHIP_ERROR MTREncodeTLVFromDataValueDictionary(id object, chip::TLV::TLVW TLV::TLVWriter writer; writer.Init(buffer); - CHIP_ERROR err = MTREncodeTLVFromDataValueDictionary(value, writer, TLV::AnonymousTag()); + CHIP_ERROR err = MTREncodeTLVFromDataValueDictionary(value, &writer, TLV::AnonymousTag()); if (err != CHIP_NO_ERROR) { if (error) { *error = [MTRError errorForCHIPErrorCode:err]; @@ -772,6 +782,11 @@ static CHIP_ERROR MTREncodeTLVFromDataValueDictionary(id object, chip::TLV::TLVW return AsData(ByteSpan(buffer, writer.GetLengthWritten())); } +BOOL MTRDataValueDictionaryIsWellFormed(MTRDeviceDataValueDictionary value) +{ + return MTREncodeTLVFromDataValueDictionary(value, nullptr, TLV::AnonymousTag()) == CHIP_NO_ERROR; +} + // Callback type to pass data value as an NSObject typedef void (*MTRDataValueDictionaryCallback)(void * context, id value); @@ -798,7 +813,7 @@ CHIP_ERROR Decode(chip::TLV::TLVReader & data) CHIP_ERROR Encode(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const { - return MTREncodeTLVFromDataValueDictionary(decodedObj, writer, tag); + return MTREncodeTLVFromDataValueDictionary(decodedObj, &writer, tag); } static constexpr bool kIsFabricScoped = false; @@ -2212,7 +2227,7 @@ + (NSDictionary *)eventReportForHeader:(const chip::app::EventHeader &)header an // Commands never need chained buffers, since they cannot be chunked. writer.Init(std::move(buffer), /* useChainedBuffers = */ false); - CHIP_ERROR errorCode = MTREncodeTLVFromDataValueDictionary(data, writer, TLV::AnonymousTag()); + CHIP_ERROR errorCode = MTREncodeTLVFromDataValueDictionary(data, &writer, TLV::AnonymousTag()); if (errorCode != CHIP_NO_ERROR) { LogStringAndReturnError(@"Unable to encode data-value to TLV", errorCode, error); return System::PacketBufferHandle(); @@ -3082,7 +3097,7 @@ static bool EncodeDataValueToTLV(System::PacketBufferHandle & buffer, Platform:: System::PacketBufferTLVWriter writer; writer.Init(std::move(buffer), /* useChainedBuffers = */ true); - CHIP_ERROR errorCode = MTREncodeTLVFromDataValueDictionary(data, writer, TLV::AnonymousTag()); + CHIP_ERROR errorCode = MTREncodeTLVFromDataValueDictionary(data, &writer, TLV::AnonymousTag()); if (errorCode != CHIP_NO_ERROR) { LogStringAndReturnError(@"Unable to encode data-value to TLV", errorCode, error); return false; diff --git a/src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h b/src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h index 1482d80634da43..075ee99da20990 100644 --- a/src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h +++ b/src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h @@ -18,6 +18,8 @@ #import "MTRBaseDevice.h" #import +#import "MTRDeviceDataValueDictionary.h" + #include #include #include @@ -257,6 +259,6 @@ NSDictionary * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV // TLV Data with an anonymous tag. This method assumes the encoding of the // value fits in a single UDP MTU; for lists this method might need to be used // on each list item separately. -NSData * _Nullable MTREncodeTLVFromDataValueDictionary(NSDictionary * value, NSError * __autoreleasing * error); +NSData * _Nullable MTREncodeTLVFromDataValueDictionary(MTRDeviceDataValueDictionary value, NSError * __autoreleasing * error); NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDevice_Internal.h b/src/darwin/Framework/CHIP/MTRDevice_Internal.h index df4a8265538dfe..4414b3c6133b07 100644 --- a/src/darwin/Framework/CHIP/MTRDevice_Internal.h +++ b/src/darwin/Framework/CHIP/MTRDevice_Internal.h @@ -176,6 +176,13 @@ MTR_DIRECT_MEMBERS - (void)devicePrivateInternalStateChanged:(MTRDevice *)device internalState:(NSDictionary *)state; @end +// Returns whether a data-value dictionary is well-formed (in the sense that all +// the types of the objects inside are as expected, so it's actually a valid +// representation of some TLV). Implemented in MTRBaseDevice.mm because that's +// where the pieces needed to implement it are, but declared here so our tests +// can see it. +MTR_EXTERN MTR_TESTABLE BOOL MTRDataValueDictionaryIsWellFormed(MTRDeviceDataValueDictionary value); + #pragma mark - Constants static NSString * const kDefaultSubscriptionPoolSizeOverrideKey = @"subscriptionPoolSizeOverride"; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index b1d26e9ce0fb12..da2ce72f59373d 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -7625,6 +7625,7 @@ typedef NS_ENUM(uint32_t, MTRDeviceTypeIDType) { MTRDeviceTypeIDTypeHumiditySensorID MTR_NEWLY_AVAILABLE = 0x00000307, MTRDeviceTypeIDTypeEVSEID MTR_NEWLY_AVAILABLE = 0x0000050C, MTRDeviceTypeIDTypeDeviceEnergyManagementID MTR_NEWLY_AVAILABLE = 0x0000050D, + MTRDeviceTypeIDTypeWaterHeaterID MTR_PROVISIONALLY_AVAILABLE = 0x0000050F, MTRDeviceTypeIDTypeElectricalSensorID MTR_NEWLY_AVAILABLE = 0x00000510, MTRDeviceTypeIDTypeControlBridgeID MTR_NEWLY_AVAILABLE = 0x00000840, MTRDeviceTypeIDTypeOnOffSensorID MTR_NEWLY_AVAILABLE = 0x00000850, diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm index f0530c41a54f00..b4ea67c2ed66fe 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm @@ -85,6 +85,7 @@ { 0x00000307, MTRDeviceTypeClass::Simple, "Humidity Sensor" }, { 0x0000050C, MTRDeviceTypeClass::Simple, "EVSE" }, { 0x0000050D, MTRDeviceTypeClass::Simple, "Device Energy Management" }, + { 0x0000050F, MTRDeviceTypeClass::Simple, "Water Heater" }, { 0x00000510, MTRDeviceTypeClass::Utility, "Electrical Sensor" }, { 0x00000840, MTRDeviceTypeClass::Simple, "Control Bridge" }, { 0x00000850, MTRDeviceTypeClass::Simple, "On/Off Sensor" }, diff --git a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m index 9d33649057ddb1..3fa4ff45449f89 100644 --- a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m +++ b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m @@ -4819,6 +4819,374 @@ - (void)test040_AttributeValueExpectationSatisfaction } } +- (void)test041_AttributeDataValueValidation +{ + __auto_type * testData = @[ + @{ + @"input" : @ { + MTRTypeKey : MTRSignedIntegerValueType, + MTRValueKey : @(-5), + }, + // -5 is a valid signed integer. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRSignedIntegerValueType, + MTRValueKey : @ {}, + }, + // A dictionary is not a valid signed integer. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRUnsignedIntegerValueType, + MTRValueKey : @(7), + }, + // 7 is a valid unsigned integer. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRUnsignedIntegerValueType, + MTRValueKey : @("abc"), + }, + // "abc" is not an unsigned integer. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRBooleanValueType, + MTRValueKey : @(YES), + }, + // YES is a boolean. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRBooleanValueType, + MTRValueKey : [NSData data], + }, + // NSData is not a boolean integer. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRFloatValueType, + MTRValueKey : @(8), + }, + // 8 is a valid float. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRFloatValueType, + MTRValueKey : @(8.5), + }, + // 8.5 is a valid float. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRFloatValueType, + MTRValueKey : @[], + }, + // An array is not a float. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRDoubleValueType, + MTRValueKey : @(180), + }, + // 180 is a valid double. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRDoubleValueType, + MTRValueKey : @(9.5), + }, + // 9.5 is a valid double. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRDoubleValueType, + MTRValueKey : [NSDate date], + }, + // A date is not a double. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRNullValueType, + }, + // This is a valid null value. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRUTF8StringValueType, + MTRValueKey : @("def"), + }, + // "def" is a valid string. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRUTF8StringValueType, + MTRValueKey : [NSData data], + }, + // NSData is not a string. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTROctetStringValueType, + MTRValueKey : [NSData data], + }, + // NSData is an octet string. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTROctetStringValueType, + MTRValueKey : @(7), + }, + // 7 is not an octet string. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTROctetStringValueType, + MTRValueKey : @("abc"), + }, + // "abc" is not an octet string. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[], + }, + // This is a valid empty structure. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[], + }, + // This is a valid empty structure. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[ + @{ + MTRContextTagKey : @(7), + MTRDataKey : @ { + MTRTypeKey : MTRNullValueType + }, + }, + ], + }, + // This is a valid structure, one null field. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[ + @{ + MTRContextTagKey : @(1), + MTRDataKey : @ { + MTRTypeKey : MTRNullValueType + }, + }, + @{ + MTRContextTagKey : @(2), + MTRDataKey : @ { + MTRTypeKey : MTRUnsignedIntegerValueType, + MTRValueKey : @(9) + }, + }, + ], + }, + // This is a valid structure with two fields. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @(19), + }, + // 19 is not a structure. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[ + @{ + MTRDataKey : @ { + MTRTypeKey : MTRNullValueType + }, + }, + ], + }, + // Field does not have a context tag. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[ + @{ + MTRContextTagKey : @(7), + }, + ], + }, + // Field does not have a value. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[ + @{ + MTRContextTagKey : @(7), + MTRDataKey : @(5), + }, + ], + }, + // Field value is a number, not a data-value + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[ + @{ + MTRContextTagKey : @(7), + MTRDataKey : @[], + }, + ], + }, + // Field value is an array, not a data-value + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[ + @{ + MTRContextTagKey : @(7), + MTRDataKey : @ {}, + }, + ], + }, + // Field value is an invalid data-value + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[ + @{ + MTRContextTagKey : @("abc"), + MTRDataKey : @ { + MTRTypeKey : MTRNullValueType + }, + }, + ], + }, + // Tag is not a number. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRArrayValueType, + MTRValueKey : @[], + }, + // This is a valid empty array. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRArrayValueType, + MTRValueKey : @[ + @{ + MTRDataKey : @ { + MTRTypeKey : MTRNullValueType + }, + }, + ], + }, + // This is an array with a single null value in it. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRArrayValueType, + MTRValueKey : @[ + @{ + MTRDataKey : @ { + MTRTypeKey : MTRUnsignedIntegerValueType, + MTRValueKey : @(8), + }, + }, + @{ + MTRDataKey : @ { + MTRTypeKey : MTRUnsignedIntegerValueType, + MTRValueKey : @(10), + }, + }, + ], + }, + // This is an array with two integers in it. + @"valid" : @(YES), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRArrayValueType, + MTRValueKey : @[ + @{ + MTRTypeKey : MTRUnsignedIntegerValueType, + MTRValueKey : @(8), + }, + ], + }, + // This does not have a proper array-value in the array: missing MTRDataKey. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRArrayValueType, + MTRValueKey : @[ @(7) ], + }, + // This does not have a proper array-value in the array: not a dictionary. + @"valid" : @(NO), + }, + @{ + @"input" : @ { + MTRTypeKey : MTRArrayValueType, + MTRValueKey : @[ @{} ], + }, + // This does not have a proper array-value in the array: empty + // dictionary, so no MTRDataKey. + @"valid" : @(NO), + }, + ]; + + for (NSDictionary * test in testData) { + XCTAssertEqual(MTRDataValueDictionaryIsWellFormed(test[@"input"]), [test[@"valid"] boolValue], + "input: %@", test[@"input"]); + } +} + @end @interface MTRDeviceEncoderTests : XCTestCase diff --git a/src/lib/address_resolve/tool.cpp b/src/lib/address_resolve/tool.cpp index 53d01b4011806f..042f7c6f891753 100644 --- a/src/lib/address_resolve/tool.cpp +++ b/src/lib/address_resolve/tool.cpp @@ -147,7 +147,7 @@ extern "C" void StopSignalHandler(int signal) } // namespace -extern "C" int main(int argc, const char ** argv) +int main(int argc, const char ** argv) { Platform::MemoryInit(); diff --git a/src/lib/support/BufferReader.cpp b/src/lib/support/BufferReader.cpp index 02bce8f3fe0615..cbd13f1ed172dc 100644 --- a/src/lib/support/BufferReader.cpp +++ b/src/lib/support/BufferReader.cpp @@ -18,12 +18,29 @@ #include "BufferReader.h" #include +#include +#include #include #include namespace chip { namespace Encoding { + +BufferReader & BufferReader::ReadBytes(uint8_t * dest, size_t size) +{ + static_assert(CHAR_BIT == 8, "Our various sizeof checks rely on bytes and octets being the same thing"); + + if (EnsureAvailable(size)) + { + memcpy(dest, mReadPtr, size); + mReadPtr += size; + mAvailable -= size; + } + + return *this; +} + namespace LittleEndian { namespace { @@ -58,37 +75,12 @@ void Reader::RawReadLowLevelBeCareful(T * retval) constexpr size_t data_size = sizeof(T); - if (mAvailable < data_size) - { - mStatus = CHIP_ERROR_BUFFER_TOO_SMALL; - // Ensure that future reads all fail. - mAvailable = 0; - return; - } - - ReadHelper(mReadPtr, retval); - mReadPtr += data_size; - - mAvailable = static_cast(mAvailable - data_size); -} - -Reader & Reader::ReadBytes(uint8_t * dest, size_t size) -{ - static_assert(CHAR_BIT == 8, "Our various sizeof checks rely on bytes and octets being the same thing"); - - if ((size > UINT16_MAX) || (mAvailable < size)) + if (EnsureAvailable(data_size)) { - mStatus = CHIP_ERROR_BUFFER_TOO_SMALL; - // Ensure that future reads all fail. - mAvailable = 0; - return *this; + ReadHelper(mReadPtr, retval); + mReadPtr += data_size; + mAvailable -= data_size; } - - memcpy(dest, mReadPtr, size); - - mReadPtr += size; - mAvailable = static_cast(mAvailable - size); - return *this; } // Explicit Read instantiations for the data types we want to support. @@ -104,5 +96,46 @@ template void Reader::RawReadLowLevelBeCareful(uint32_t *); template void Reader::RawReadLowLevelBeCareful(uint64_t *); } // namespace LittleEndian + +namespace BigEndian { + +Reader & Reader::Read16(uint16_t * dest) +{ + if (!EnsureAvailable(sizeof(uint16_t))) + { + return *this; + } + + static_assert(sizeof(*dest) == 2); + + *dest = static_cast((mReadPtr[0] << 8) + mReadPtr[1]); + mReadPtr += 2; + mAvailable -= 2; + return *this; +} + +Reader & Reader::Read32(uint32_t * dest) +{ + if (!EnsureAvailable(sizeof(uint32_t))) + { + return *this; + } + + static_assert(sizeof(*dest) == 4); + + *dest = 0; + for (unsigned i = 0; i < sizeof(uint32_t); i++) + { + *dest <<= 8; + *dest += mReadPtr[i]; + } + + mReadPtr += sizeof(uint32_t); + mAvailable -= sizeof(uint32_t); + return *this; +} + +} // namespace BigEndian + } // namespace Encoding } // namespace chip diff --git a/src/lib/support/BufferReader.h b/src/lib/support/BufferReader.h index ac9c7145359335..725ca8e23ea915 100644 --- a/src/lib/support/BufferReader.h +++ b/src/lib/support/BufferReader.h @@ -31,26 +31,11 @@ namespace chip { namespace Encoding { -namespace LittleEndian { -/** - * @class Reader - * - * Simple reader for reading little-endian things out of buffers. - */ -class Reader +class BufferReader { public: - /** - * Create a buffer reader from a given buffer and length. - * - * @param buffer The octet buffer from which to read. The caller must ensure - * (most simply by allocating the reader on the stack) that - * the buffer outlives the reader. If `buffer` is nullptr, - * length is automatically overridden to zero, to avoid accesses. - * @param buf_len The number of octets in the buffer. - */ - Reader(const uint8_t * buffer, size_t buf_len) : mBufStart(buffer), mReadPtr(buffer), mAvailable(buf_len) + BufferReader(const uint8_t * buffer, size_t buf_len) : mBufStart(buffer), mReadPtr(buffer), mAvailable(buf_len) { if (mBufStart == nullptr) { @@ -58,15 +43,6 @@ class Reader } } - /** - * Create a buffer reader from a given byte span. - * - * @param buffer The octet buffer byte span from which to read. The caller must ensure - * that the buffer outlives the reader. The buffer's ByteSpan .data() pointer - * is is nullptr, length is automatically overridden to zero, to avoid accesses. - */ - Reader(const ByteSpan & buffer) : Reader(buffer.data(), buffer.size()) {} - /** * Number of octets we have read so far. */ @@ -95,6 +71,121 @@ class Reader */ bool IsSuccess() const { return StatusCode() == CHIP_NO_ERROR; } + /** + * Read a byte string from the BufferReader + * + * @param [out] dest Where the bytes read + * @param [in] size How many bytes to read + * + * @note The read can put the reader in a failed-status state if there are + * not enough octets available. Callers must either continue to do + * more reads on the return value or check its status to see whether + * the sequence of reads that has been performed succeeded. + */ + CHECK_RETURN_VALUE + BufferReader & ReadBytes(uint8_t * dest, size_t size); + + /** + * Access bytes of size length, useful for in-place processing of strings + * + * data_ptr MUST NOT be null and will contain the data pointer with `len` bytes available + * if this call is successful + * + * If len is greater than the number of available bytes, the object enters in a failed status. + */ + CHECK_RETURN_VALUE + BufferReader & ZeroCopyProcessBytes(size_t len, const uint8_t ** data_ptr) + { + if (len > mAvailable) + { + *data_ptr = nullptr; + mStatus = CHIP_ERROR_BUFFER_TOO_SMALL; + // Ensure that future reads all fail. + mAvailable = 0; + } + else + { + *data_ptr = mReadPtr; + mReadPtr += len; + mAvailable -= len; + } + return *this; + } + + /** + * Advance the Reader forward by the specified number of octets. + * + * @param len The number of octets to skip. + * + * @note If the len argument is greater than the number of available octets + * remaining, the Reader will advance to the end of the buffer + * without entering a failed-status state. + */ + BufferReader & Skip(size_t len) + { + len = std::min(len, mAvailable); + mReadPtr += len; + mAvailable = static_cast(mAvailable - len); + return *this; + } + +protected: + /// Our buffer start. + const uint8_t * const mBufStart; + + /// Our current read point. + const uint8_t * mReadPtr; + + /// The number of octets we can still read starting at mReadPtr. + size_t mAvailable; + + /// Our current status. + CHIP_ERROR mStatus = CHIP_NO_ERROR; + + /// Make sure we have at least the given number of bytes available (does not consume them) + bool EnsureAvailable(size_t size) + { + if (mAvailable < size) + { + mStatus = CHIP_ERROR_BUFFER_TOO_SMALL; + // Ensure that future reads all fail. + mAvailable = 0; + return false; + } + return true; + } +}; + +namespace LittleEndian { + +/** + * @class Reader + * + * Simple reader for reading little-endian things out of buffers. + */ +class Reader : public BufferReader +{ +public: + /** + * Create a buffer reader from a given buffer and length. + * + * @param buffer The octet buffer from which to read. The caller must ensure + * (most simply by allocating the reader on the stack) that + * the buffer outlives the reader. If `buffer` is nullptr, + * length is automatically overridden to zero, to avoid accesses. + * @param buf_len The number of octets in the buffer. + */ + Reader(const uint8_t * buffer, size_t buf_len) : BufferReader(buffer, buf_len) {} + + /** + * Create a buffer reader from a given byte span. + * + * @param buffer The octet buffer byte span from which to read. The caller must ensure + * that the buffer outlives the reader. The buffer's ByteSpan .data() pointer + * is is nullptr, length is automatically overridden to zero, to avoid accesses. + */ + Reader(const ByteSpan & buffer) : Reader(buffer.data(), buffer.size()) {} + /** * Read a bool, assuming single byte storage. * @@ -267,20 +358,6 @@ class Reader return *this; } - /** - * Read a byte string from the BufferReader - * - * @param [out] dest Where the bytes read - * @param [in] size How many bytes to read - * - * @note The read can put the reader in a failed-status state if there are - * not enough octets available. Callers must either continue to do - * more reads on the return value or check its status to see whether - * the sequence of reads that has been performed succeeded. - */ - CHECK_RETURN_VALUE - Reader & ReadBytes(uint8_t * dest, size_t size); - /** * Helper for our various APIs so we don't have to write out various logic * multiple times. This is public so that consumers that want to read into @@ -290,46 +367,80 @@ class Reader */ template void RawReadLowLevelBeCareful(T * retval); +}; + +} // namespace LittleEndian +namespace BigEndian { + +/** + * @class Reader + * + * Simple reader for reading big-endian things out of buffers. + */ +class Reader : public BufferReader +{ +public: /** - * Advance the Reader forward by the specified number of octets. - * - * @param len The number of octets to skip. + * Create a buffer reader from a given buffer and length. * - * @note If the len argument is greater than the number of available octets - * remaining, the Reader will advance to the end of the buffer - * without entering a failed-status state. + * @param buffer The octet buffer from which to read. The caller must ensure + * (most simply by allocating the reader on the stack) that + * the buffer outlives the reader. If `buffer` is nullptr, + * length is automatically overridden to zero, to avoid accesses. + * @param buf_len The number of octets in the buffer. */ - Reader & Skip(size_t len) - { - len = std::min(len, mAvailable); - mReadPtr += len; - mAvailable = static_cast(mAvailable - len); - return *this; - } + Reader(const uint8_t * buffer, size_t buf_len) : BufferReader(buffer, buf_len) {} -private: /** - * Our buffer start. + * Create a buffer reader from a given byte span. + * + * @param buffer The octet buffer byte span from which to read. The caller must ensure + * that the buffer outlives the reader. If the buffer's ByteSpan .data() pointer + * is nullptr, length is automatically overridden to zero, to avoid accesses. */ - const uint8_t * const mBufStart; + Reader(const ByteSpan & buffer) : Reader(buffer.data(), buffer.size()) {} /** - * Our current read point. + * Read a single 8-bit unsigned integer. + * + * @param [out] dest Where the 8-bit integer goes. + * + * @note The read can put the reader in a failed-status state if there are + * not enough octets available. Callers must either continue to do + * more reads on the return value or check its status to see whether + * the sequence of reads that has been performed succeeded. */ - const uint8_t * mReadPtr; + CHECK_RETURN_VALUE + Reader & Read8(uint8_t * dest) + { + (void) ReadBytes(dest, 1); + return *this; + } - /** - * The number of octets we can still read starting at mReadPtr. - */ - size_t mAvailable; + CHECK_RETURN_VALUE + Reader & ReadChar(char * dest) + { + (void) ReadBytes(reinterpret_cast(dest), 1); + return *this; + } - /** - * Our current status. - */ - CHIP_ERROR mStatus = CHIP_NO_ERROR; + CHECK_RETURN_VALUE + Reader & ReadBool(char * dest) + { + (void) ReadBytes(reinterpret_cast(dest), 1); + return *this; + } + + /// NOTE: only a subset of reads are supported here, more can be added if used/needed + CHECK_RETURN_VALUE + Reader & Read16(uint16_t * dest); + + CHECK_RETURN_VALUE + Reader & Read32(uint32_t * dest); }; -} // namespace LittleEndian +} // namespace BigEndian + } // namespace Encoding } // namespace chip diff --git a/src/lib/support/tests/TestBufferReader.cpp b/src/lib/support/tests/TestBufferReader.cpp index 97db9cf09737b9..ee100e1506bada 100644 --- a/src/lib/support/tests/TestBufferReader.cpp +++ b/src/lib/support/tests/TestBufferReader.cpp @@ -30,21 +30,21 @@ #include using namespace chip; -using namespace chip::Encoding::LittleEndian; +using namespace chip::Encoding; static const uint8_t test_buffer[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; -struct TestReader : public Reader +struct LittleEndianTestReader : public LittleEndian::Reader { - TestReader() : Reader(test_buffer, std::extent::value) {} + LittleEndianTestReader() : LittleEndian::Reader(test_buffer, std::extent::value) {} }; -struct TestSpanReader : public Reader +struct LittleEndianTestSpanReader : public LittleEndian::Reader { - TestSpanReader() : Reader(ByteSpan{ test_buffer, std::extent::value }) {} + LittleEndianTestSpanReader() : LittleEndian::Reader(ByteSpan{ test_buffer, std::extent::value }) {} }; -static void TestBufferReader_BasicImpl(Reader & reader) +static void TestBufferReader_BasicImpl(LittleEndian::Reader & reader) { uint8_t first; uint16_t second; @@ -75,21 +75,21 @@ static void TestBufferReader_BasicImpl(Reader & reader) TEST(TestBufferReader, TestBufferReader_Basic) { - TestReader reader; + LittleEndianTestReader reader; TestBufferReader_BasicImpl(reader); } TEST(TestBufferReader, TestBufferReader_BasicSpan) { - TestSpanReader reader; + LittleEndianTestSpanReader reader; TestBufferReader_BasicImpl(reader); } TEST(TestBufferReader, TestBufferReader_Saturation) { - TestReader reader; + LittleEndianTestReader reader; uint64_t temp; // Read some bytes out so we can get to the end of the buffer. CHIP_ERROR err = reader.Read64(&temp).StatusCode(); @@ -113,12 +113,13 @@ TEST(TestBufferReader, TestBufferReader_Saturation) TEST(TestBufferReader, TestBufferReader_Skip) { - TestReader reader; + LittleEndianTestReader reader; uint8_t temp = 0; uint16_t firstSkipLen = 2; // Verify Skip() advances the start pointer the correct amount. - CHIP_ERROR err = reader.Skip(firstSkipLen).Read8(&temp).StatusCode(); + reader.Skip(firstSkipLen); + CHIP_ERROR err = reader.Read8(&temp).StatusCode(); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(temp, test_buffer[firstSkipLen]); EXPECT_EQ(reader.OctetsRead(), (firstSkipLen + 1u)); @@ -175,7 +176,8 @@ TEST(TestBufferReader, TestBufferReader_LittleEndianScalars) uint32_t val1 = 0; uint32_t val2 = 0; - EXPECT_TRUE(reader.Skip(1).Read32(&val1).Read32(&val2).IsSuccess()); + reader.Skip(1); + EXPECT_TRUE(reader.Read32(&val1).Read32(&val2).IsSuccess()); EXPECT_EQ(reader.Remaining(), 1u); EXPECT_EQ(val1, static_cast(0xfffffffeUL)); EXPECT_EQ(val2, static_cast(0xffffffffUL)); @@ -227,7 +229,8 @@ TEST(TestBufferReader, TestBufferReader_LittleEndianScalars) int32_t val1 = 0; int32_t val2 = 0; - EXPECT_TRUE(reader.Skip(1).ReadSigned32(&val1).ReadSigned32(&val2).IsSuccess()); + reader.Skip(1); + EXPECT_TRUE(reader.ReadSigned32(&val1).ReadSigned32(&val2).IsSuccess()); EXPECT_EQ(reader.Remaining(), 1u); EXPECT_EQ(val1, static_cast(-2L)); EXPECT_EQ(val2, static_cast(-1L)); @@ -272,3 +275,23 @@ TEST(TestBufferReader, TestBufferReader_LittleEndianScalars) EXPECT_EQ(val3, '\xff'); } } + +TEST(TestBigEndianBufferReader, GenericTests) +{ + uint8_t test_buf[] = { 0x12, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xBC, 1, 2, 3 }; + + chip::Encoding::BigEndian::Reader reader{ ByteSpan{ test_buf } }; + + uint16_t v1; + uint32_t v2; + uint8_t v3; + + EXPECT_TRUE(reader.Read16(&v1).Read32(&v2).Read8(&v3).IsSuccess()); + EXPECT_EQ(reader.Remaining(), 3u); + EXPECT_EQ(v1, 0x1223u); + EXPECT_EQ(v2, 0x456789ABu); + EXPECT_EQ(v3, 0xBCu); + + // Insufficient buffer after that + EXPECT_FALSE(reader.Read32(&v2).IsSuccess()); +} diff --git a/src/platform/silabs/BLEManagerImpl.h b/src/platform/silabs/BLEManagerImpl.h index 6d901db16e95db..9380accce38e55 100644 --- a/src/platform/silabs/BLEManagerImpl.h +++ b/src/platform/silabs/BLEManagerImpl.h @@ -58,12 +58,12 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla #if (SLI_SI91X_ENABLE_BLE || RSI_BLE_ENABLE) // Used for posting the event in the BLE queue void BlePostEvent(SilabsBleWrapper::BleEvent_t * event); - void HandleConnectEvent(SilabsBleWrapper::sl_wfx_msg_t * evt); - void HandleConnectionCloseEvent(SilabsBleWrapper::sl_wfx_msg_t * evt); - void HandleWriteEvent(SilabsBleWrapper::sl_wfx_msg_t * evt); - void UpdateMtu(SilabsBleWrapper::sl_wfx_msg_t * evt); + void HandleConnectEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt); + void HandleConnectionCloseEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt); + void HandleWriteEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt); + void UpdateMtu(const SilabsBleWrapper::sl_wfx_msg_t & evt); void HandleTxConfirmationEvent(BLE_CONNECTION_OBJECT conId); - void HandleTXCharCCCDWrite(SilabsBleWrapper::sl_wfx_msg_t * evt); + void HandleTXCharCCCDWrite(const SilabsBleWrapper::sl_wfx_msg_t & evt); void HandleSoftTimerEvent(void); int32_t SendBLEAdvertisementCommand(void); #else @@ -194,7 +194,7 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla #endif #if (SLI_SI91X_ENABLE_BLE || RSI_BLE_ENABLE) - void HandleRXCharWrite(SilabsBleWrapper::sl_wfx_msg_t * evt); + void HandleRXCharWrite(const SilabsBleWrapper::sl_wfx_msg_t & evt); #else void HandleRXCharWrite(volatile sl_bt_msg_t * evt); #endif diff --git a/src/platform/silabs/rs911x/BLEManagerImpl.cpp b/src/platform/silabs/rs911x/BLEManagerImpl.cpp index 44b2a17199b330..176f396f44cd1f 100644 --- a/src/platform/silabs/rs911x/BLEManagerImpl.cpp +++ b/src/platform/silabs/rs911x/BLEManagerImpl.cpp @@ -57,24 +57,7 @@ extern "C" { #define BLE_TIMEOUT_MS 400 #define BLE_SEND_INDICATION_TIMER_PERIOD_MS (5000) -// Used to send the Indication Confirmation -uint8_t dev_address[RSI_DEV_ADDR_LEN]; -uint16_t ble_measurement_hndl; - osSemaphoreId_t sl_rs_ble_init_sem; -osTimerId_t sbleAdvTimeoutTimer; - -static osThreadId_t sBleThread; -constexpr uint32_t kBleTaskSize = 2048; -static uint8_t bleStack[kBleTaskSize]; -static osThread_t sBleTaskControlBlock; -constexpr osThreadAttr_t kBleTaskAttr = { .name = "rsi_ble", - .attr_bits = osThreadDetached, - .cb_mem = &sBleTaskControlBlock, - .cb_size = osThreadCbSize, - .stack_mem = bleStack, - .stack_size = kBleTaskSize, - .priority = osPriorityHigh }; using namespace ::chip; using namespace ::chip::Ble; @@ -111,6 +94,84 @@ const uint8_t UUID_CHIPoBLEService[] = { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00 0x00, 0x10, 0x00, 0x00, 0xF6, 0xFF, 0x00, 0x00 }; const uint8_t ShortUUID_CHIPoBLEService[] = { 0xF6, 0xFF }; +// Used to send the Indication Confirmation +uint8_t dev_address[RSI_DEV_ADDR_LEN]; +uint16_t rsi_ble_measurement_hndl; +uint16_t rsi_ble_gatt_server_client_config_hndl; + +osTimerId_t sbleAdvTimeoutTimer; + +osThreadId_t sBleThread; +constexpr uint32_t kBleTaskSize = 2560; +uint8_t bleStack[kBleTaskSize]; +osThread_t sBleTaskControlBlock; +constexpr osThreadAttr_t kBleTaskAttr = { .name = "rsi_ble", + .attr_bits = osThreadDetached, + .cb_mem = &sBleTaskControlBlock, + .cb_size = osThreadCbSize, + .stack_mem = bleStack, + .stack_size = kBleTaskSize, + .priority = osPriorityHigh }; + +void rsi_ble_add_matter_service(void) +{ + constexpr uuid_t custom_service = { .size = RSI_BLE_MATTER_CUSTOM_SERVICE_SIZE, + .val = { .val16 = RSI_BLE_MATTER_CUSTOM_SERVICE_VALUE_16 } }; + uint8_t data[RSI_BLE_MATTER_CUSTOM_SERVICE_DATA_LENGTH] = { RSI_BLE_MATTER_CUSTOM_SERVICE_DATA }; + + constexpr uuid_t custom_characteristic_RX = { .size = RSI_BLE_CUSTOM_CHARACTERISTIC_RX_SIZE, + .reserved = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_RESERVED }, + .val = { .val128 = { + .data1 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_1 }, + .data2 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_2 }, + .data3 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_3 }, + .data4 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_4 } } } }; + + rsi_ble_resp_add_serv_t new_serv_resp = { 0 }; + rsi_ble_add_service(custom_service, &new_serv_resp); + + // Adding custom characteristic declaration to the custom service + SilabsBleWrapper::rsi_ble_add_char_serv_att( + new_serv_resp.serv_handler, new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_ATTRIBUTE_HANDLE_LOCATION, + RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ, // Set read, write, write without response + new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_VALUE_HANDLE_LOCATION, custom_characteristic_RX); + + // Adding characteristic value attribute to the service + SilabsBleWrapper::rsi_ble_add_char_val_att( + new_serv_resp.serv_handler, new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_VALUE_HANDLE_LOCATION, + custom_characteristic_RX, + RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ, // Set read, write, write without response + data, sizeof(data), ATT_REC_IN_HOST); + + constexpr uuid_t custom_characteristic_TX = { .size = RSI_BLE_CUSTOM_CHARACTERISTIC_TX_SIZE, + .reserved = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_RESERVED }, + .val = { .val128 = { + .data1 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_1 }, + .data2 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_2 }, + .data3 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_3 }, + .data4 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_4 } } } }; + + // Adding custom characteristic declaration to the custom service + SilabsBleWrapper::rsi_ble_add_char_serv_att( + new_serv_resp.serv_handler, new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_ATTRIBUTE_HANDLE_LOCATION, + RSI_BLE_ATT_PROPERTY_WRITE_NO_RESPONSE | RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ | + RSI_BLE_ATT_PROPERTY_NOTIFY | RSI_BLE_ATT_PROPERTY_INDICATE, // Set read, write, write without response + new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_MEASUREMENT_HANDLE_LOCATION, custom_characteristic_TX); + + // Adding characteristic value attribute to the service + rsi_ble_measurement_hndl = new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_MEASUREMENT_HANDLE_LOCATION; + + // Adding characteristic value attribute to the service + rsi_ble_gatt_server_client_config_hndl = + new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_GATT_SERVER_CLIENT_HANDLE_LOCATION; + + SilabsBleWrapper::rsi_ble_add_char_val_att(new_serv_resp.serv_handler, rsi_ble_measurement_hndl, custom_characteristic_TX, + RSI_BLE_ATT_PROPERTY_WRITE_NO_RESPONSE | RSI_BLE_ATT_PROPERTY_WRITE | + RSI_BLE_ATT_PROPERTY_READ | RSI_BLE_ATT_PROPERTY_NOTIFY | + RSI_BLE_ATT_PROPERTY_INDICATE, // Set read, write, write without response + data, sizeof(data), ATT_REC_MAINTAIN_IN_HOST); +} + } // namespace BLEManagerImpl BLEManagerImpl::sInstance; @@ -120,15 +181,14 @@ void BLEManagerImpl::ProcessEvent(SilabsBleWrapper::BleEvent_t inEvent) switch (inEvent.eventType) { case SilabsBleWrapper::BleEventType::RSI_BLE_CONN_EVENT: { - BLEMgrImpl().HandleConnectEvent((inEvent.eventData)); + BLEMgrImpl().HandleConnectEvent(inEvent.eventData); // Requests the connection parameters change with the remote device - rsi_ble_conn_params_update(inEvent.eventData->resp_enh_conn.dev_addr, BLE_MIN_CONNECTION_INTERVAL_MS, + rsi_ble_conn_params_update(inEvent.eventData.resp_enh_conn.dev_addr, BLE_MIN_CONNECTION_INTERVAL_MS, BLE_MAX_CONNECTION_INTERVAL_MS, BLE_SLAVE_LATENCY_MS, BLE_TIMEOUT_MS); - rsi_ble_set_data_len(inEvent.eventData->resp_enh_conn.dev_addr, RSI_BLE_TX_OCTETS, RSI_BLE_TX_TIME); + rsi_ble_set_data_len(inEvent.eventData.resp_enh_conn.dev_addr, RSI_BLE_TX_OCTETS, RSI_BLE_TX_TIME); // Used to send the Indication confirmation - memcpy(dev_address, inEvent.eventData->resp_enh_conn.dev_addr, RSI_DEV_ADDR_LEN); - ble_measurement_hndl = inEvent.eventData->rsi_ble_measurement_hndl; + memcpy(dev_address, inEvent.eventData.resp_enh_conn.dev_addr, RSI_DEV_ADDR_LEN); } break; case SilabsBleWrapper::BleEventType::RSI_BLE_DISCONN_EVENT: { @@ -143,7 +203,7 @@ void BLEManagerImpl::ProcessEvent(SilabsBleWrapper::BleEvent_t inEvent) break; case SilabsBleWrapper::BleEventType::RSI_BLE_EVENT_GATT_RD: { #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING - if (inEvent.eventData->rsi_ble_read_req->type == 0) + if (inEvent.eventData.rsi_ble_read_req->type == 0) { BLEMgrImpl().HandleC3ReadRequest(inEvent.eventData); } @@ -220,10 +280,10 @@ void BLEManagerImpl::sl_ble_init() SilabsBleWrapper::rsi_ble_on_event_indication_confirmation, NULL); // Exchange of GATT info with BLE stack - SilabsBleWrapper::rsi_ble_add_matter_service(); + rsi_ble_add_matter_service(); rsi_ble_set_random_address_with_value(randomAddrBLE); - sInstance.sBleEventQueue = osMessageQueueNew(WFX_QUEUE_SIZE, sizeof(WfxEvent_t), NULL); + sInstance.sBleEventQueue = osMessageQueueNew(WFX_QUEUE_SIZE, sizeof(SilabsBleWrapper::BleEvent_t), NULL); VerifyOrDie(sInstance.sBleEventQueue != nullptr); chip::DeviceLayer::Internal::BLEMgrImpl().HandleBootEvent(); @@ -440,7 +500,7 @@ CHIP_ERROR BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const Chi PacketBufferHandle data) { int32_t status = 0; - status = rsi_ble_indicate_value(dev_address, ble_measurement_hndl, data->DataLength(), data->Start()); + status = rsi_ble_indicate_value(dev_address, rsi_ble_measurement_hndl, data->DataLength(), data->Start()); if (status != RSI_SUCCESS) { ChipLogProgress(DeviceLayer, "indication failed with error code %lx ", status); @@ -734,9 +794,9 @@ CHIP_ERROR BLEManagerImpl::StopAdvertising(void) return err; } -void BLEManagerImpl::UpdateMtu(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::UpdateMtu(const SilabsBleWrapper::sl_wfx_msg_t & evt) { - CHIPoBLEConState * bleConnState = GetConnectionState(evt->connectionHandle); + CHIPoBLEConState * bleConnState = GetConnectionState(evt.connectionHandle); if (bleConnState != NULL) { // bleConnState->MTU is a 10-bit field inside a uint16_t. We're @@ -748,10 +808,10 @@ void BLEManagerImpl::UpdateMtu(SilabsBleWrapper::sl_wfx_msg_t * evt) // TODO: https://github.com/project-chip/connectedhomeip/issues/2569 // tracks making this safe with a check or explaining why no check // is needed. - ChipLogProgress(DeviceLayer, "DriveBLEState UpdateMtu %d", evt->rsi_ble_mtu.mtu_size); + ChipLogProgress(DeviceLayer, "DriveBLEState UpdateMtu %d", evt.rsi_ble_mtu.mtu_size); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" - bleConnState->mtu = evt->rsi_ble_mtu.mtu_size; + bleConnState->mtu = evt.rsi_ble_mtu.mtu_size; #pragma GCC diagnostic pop ; } @@ -763,14 +823,13 @@ void BLEManagerImpl::HandleBootEvent(void) PlatformMgr().ScheduleWork(DriveBLEState, 0); } -void BLEManagerImpl::HandleConnectEvent(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleConnectEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt) { - AddConnection(evt->connectionHandle, evt->bondingHandle); + AddConnection(evt.connectionHandle, evt.bondingHandle); PlatformMgr().ScheduleWork(DriveBLEState, 0); } -// TODO:: Implementation need to be done. -void BLEManagerImpl::HandleConnectionCloseEvent(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleConnectionCloseEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt) { uint8_t connHandle = 1; @@ -780,7 +839,7 @@ void BLEManagerImpl::HandleConnectionCloseEvent(SilabsBleWrapper::sl_wfx_msg_t * event.Type = DeviceEventType::kCHIPoBLEConnectionError; event.CHIPoBLEConnectionError.ConId = connHandle; - switch (evt->reason) + switch (evt.reason) { case RSI_BT_CTRL_REMOTE_USER_TERMINATED: @@ -792,7 +851,7 @@ void BLEManagerImpl::HandleConnectionCloseEvent(SilabsBleWrapper::sl_wfx_msg_t * event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; } - ChipLogProgress(DeviceLayer, "BLE GATT connection closed (con %u, reason %x)", connHandle, evt->reason); + ChipLogProgress(DeviceLayer, "BLE GATT connection closed (con %u, reason %x)", connHandle, evt.reason); PlatformMgr().PostEventOrDie(&event); @@ -804,11 +863,11 @@ void BLEManagerImpl::HandleConnectionCloseEvent(SilabsBleWrapper::sl_wfx_msg_t * } } -void BLEManagerImpl::HandleWriteEvent(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleWriteEvent(const SilabsBleWrapper::sl_wfx_msg_t & evt) { - ChipLogProgress(DeviceLayer, "Char Write Req, packet type %d", evt->rsi_ble_write.pkt_type); + ChipLogProgress(DeviceLayer, "Char Write Req, packet type %d", evt.rsi_ble_write.pkt_type); - if (evt->rsi_ble_write.handle[0] == (uint8_t) evt->rsi_ble_gatt_server_client_config_hndl) // TODO:: compare the handle exactly + if (evt.rsi_ble_write.handle[0] == (uint8_t) rsi_ble_gatt_server_client_config_hndl) // TODO:: compare the handle exactly { HandleTXCharCCCDWrite(evt); } @@ -818,23 +877,22 @@ void BLEManagerImpl::HandleWriteEvent(SilabsBleWrapper::sl_wfx_msg_t * evt) } } -// TODO:: Need to implement this -void BLEManagerImpl::HandleTXCharCCCDWrite(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleTXCharCCCDWrite(const SilabsBleWrapper::sl_wfx_msg_t & evt) { CHIP_ERROR err = CHIP_NO_ERROR; bool isIndicationEnabled = false; ChipDeviceEvent event; CHIPoBLEConState * bleConnState; - bleConnState = GetConnectionState(evt->connectionHandle); + bleConnState = GetConnectionState(evt.connectionHandle); VerifyOrExit(bleConnState != NULL, err = CHIP_ERROR_NO_MEMORY); // Determine if the client is enabling or disabling notification/indication. - if (evt->rsi_ble_write.att_value[0] != 0) + if (evt.rsi_ble_write.att_value[0] != 0) { isIndicationEnabled = true; } - ChipLogProgress(DeviceLayer, "HandleTXcharCCCDWrite - Config Flags value : %d", evt->rsi_ble_write.att_value[0]); + ChipLogProgress(DeviceLayer, "HandleTXcharCCCDWrite - Config Flags value : %d", evt.rsi_ble_write.att_value[0]); ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", isIndicationEnabled ? "subscribe" : "unsubscribe"); if (isIndicationEnabled) @@ -864,13 +922,13 @@ void BLEManagerImpl::HandleTXCharCCCDWrite(SilabsBleWrapper::sl_wfx_msg_t * evt) } } -void BLEManagerImpl::HandleRXCharWrite(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleRXCharWrite(const SilabsBleWrapper::sl_wfx_msg_t & evt) { uint8_t conId = 1; CHIP_ERROR err = CHIP_NO_ERROR; System::PacketBufferHandle buf; - uint16_t writeLen = evt->rsi_ble_write.length; - uint8_t * data = (uint8_t *) evt->rsi_ble_write.att_value; + uint16_t writeLen = evt.rsi_ble_write.length; + uint8_t * data = (uint8_t *) evt.rsi_ble_write.att_value; // Copy the data to a packet buffer. buf = System::PacketBufferHandle::NewWithData(data, writeLen, 0, 0); @@ -997,9 +1055,9 @@ CHIP_ERROR BLEManagerImpl::EncodeAdditionalDataTlv() return err; } -void BLEManagerImpl::HandleC3ReadRequest(SilabsBleWrapper::sl_wfx_msg_t * evt) +void BLEManagerImpl::HandleC3ReadRequest(const SilabsBleWrapper::sl_wfx_msg_t & evt) { - sl_status_t ret = rsi_ble_gatt_read_response(evt->rsi_ble_read_req->dev_addr, GATT_READ_RESP, evt->rsi_ble_read_req->handle, + sl_status_t ret = rsi_ble_gatt_read_response(evt.rsi_ble_read_req->dev_addr, GATT_READ_RESP, evt.rsi_ble_read_req->handle, GATT_READ_ZERO_OFFSET, sInstance.c3AdditionalDataBufferHandle->DataLength(), sInstance.c3AdditionalDataBufferHandle->Start()); if (ret != SL_STATUS_OK) diff --git a/src/platform/silabs/rs911x/wfx_sl_ble_init.cpp b/src/platform/silabs/rs911x/wfx_sl_ble_init.cpp index c1af13e2cd807c..971852592c3e2e 100644 --- a/src/platform/silabs/rs911x/wfx_sl_ble_init.cpp +++ b/src/platform/silabs/rs911x/wfx_sl_ble_init.cpp @@ -26,9 +26,6 @@ using namespace chip::DeviceLayer::Internal; -// Global Variables -SilabsBleWrapper::BleEvent_t bleEvent; - /*==============================================*/ /** * @fn rsi_ble_on_mtu_event @@ -40,8 +37,9 @@ SilabsBleWrapper::BleEvent_t bleEvent; */ void SilabsBleWrapper::rsi_ble_on_mtu_event(rsi_ble_event_mtu_t * rsi_ble_mtu) { - bleEvent.eventType = BleEventType::RSI_BLE_MTU_EVENT; - memcpy(&bleEvent.eventData->rsi_ble_mtu, rsi_ble_mtu, sizeof(rsi_ble_event_mtu_t)); + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_MTU_EVENT, + .eventData = { .connectionHandle = 1, .rsi_ble_mtu = *rsi_ble_mtu } }; + BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -57,9 +55,9 @@ void SilabsBleWrapper::rsi_ble_on_mtu_event(rsi_ble_event_mtu_t * rsi_ble_mtu) */ void SilabsBleWrapper::rsi_ble_on_gatt_write_event(uint16_t event_id, rsi_ble_event_write_t * rsi_ble_write) { - bleEvent.eventType = BleEventType::RSI_BLE_GATT_WRITE_EVENT; - bleEvent.eventData->event_id = event_id; - memcpy(&bleEvent.eventData->rsi_ble_write, rsi_ble_write, sizeof(rsi_ble_event_write_t)); + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_GATT_WRITE_EVENT, + .eventData = { + .connectionHandle = 1, .event_id = event_id, .rsi_ble_write = *rsi_ble_write } }; BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -74,10 +72,12 @@ void SilabsBleWrapper::rsi_ble_on_gatt_write_event(uint16_t event_id, rsi_ble_ev */ void SilabsBleWrapper::rsi_ble_on_enhance_conn_status_event(rsi_ble_event_enhance_conn_status_t * resp_enh_conn) { - bleEvent.eventType = BleEventType::RSI_BLE_CONN_EVENT; - bleEvent.eventData->connectionHandle = 1; - bleEvent.eventData->bondingHandle = 255; - memcpy(bleEvent.eventData->resp_enh_conn.dev_addr, resp_enh_conn->dev_addr, RSI_DEV_ADDR_LEN); + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_CONN_EVENT, + .eventData = { + .connectionHandle = 1, + .bondingHandle = 255, + } }; + memcpy(bleEvent.eventData.resp_enh_conn.dev_addr, resp_enh_conn->dev_addr, RSI_DEV_ADDR_LEN); BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -93,8 +93,7 @@ void SilabsBleWrapper::rsi_ble_on_enhance_conn_status_event(rsi_ble_event_enhanc */ void SilabsBleWrapper::rsi_ble_on_disconnect_event(rsi_ble_event_disconnect_t * resp_disconnect, uint16_t reason) { - bleEvent.eventType = BleEventType::RSI_BLE_DISCONN_EVENT; - bleEvent.eventData->reason = reason; + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_DISCONN_EVENT, .eventData = { .reason = reason } }; BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -110,9 +109,9 @@ void SilabsBleWrapper::rsi_ble_on_disconnect_event(rsi_ble_event_disconnect_t * void SilabsBleWrapper::rsi_ble_on_event_indication_confirmation(uint16_t resp_status, rsi_ble_set_att_resp_t * rsi_ble_event_set_att_rsp) { - bleEvent.eventType = BleEventType::RSI_BLE_GATT_INDICATION_CONFIRMATION; - bleEvent.eventData->resp_status = resp_status; - memcpy(&bleEvent.eventData->rsi_ble_event_set_att_rsp, rsi_ble_event_set_att_rsp, sizeof(rsi_ble_set_att_resp_t)); + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_GATT_INDICATION_CONFIRMATION, + .eventData = { .resp_status = resp_status, + .rsi_ble_event_set_att_rsp = *rsi_ble_event_set_att_rsp } }; BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -128,9 +127,8 @@ void SilabsBleWrapper::rsi_ble_on_event_indication_confirmation(uint16_t resp_st */ void SilabsBleWrapper::rsi_ble_on_read_req_event(uint16_t event_id, rsi_ble_read_req_t * rsi_ble_read_req) { - bleEvent.eventType = BleEventType::RSI_BLE_EVENT_GATT_RD; - bleEvent.eventData->event_id = event_id; - memcpy(&bleEvent.eventData->rsi_ble_read_req, rsi_ble_read_req, sizeof(rsi_ble_read_req_t)); + SilabsBleWrapper::BleEvent_t bleEvent = { .eventType = BleEventType::RSI_BLE_EVENT_GATT_RD, + .eventData = { .event_id = event_id, .rsi_ble_read_req = rsi_ble_read_req } }; BLEMgrImpl().BlePostEvent(&bleEvent); } @@ -282,77 +280,3 @@ void SilabsBleWrapper::rsi_ble_add_char_val_att(void * serv_handler, uint16_t ha return; } - -/*==============================================*/ -/** - * @fn rsi_ble_add_matter_service - * @brief this function is used to add service for matter - * @return status (uint32_t) 0 for success. - * @section description - * This function is used at application to create new service. - */ - -uint32_t SilabsBleWrapper::rsi_ble_add_matter_service(void) -{ - uuid_t custom_service = { RSI_BLE_MATTER_CUSTOM_SERVICE_UUID }; - custom_service.size = RSI_BLE_MATTER_CUSTOM_SERVICE_SIZE; - custom_service.val.val16 = RSI_BLE_MATTER_CUSTOM_SERVICE_VALUE_16; - uint8_t data[RSI_BLE_MATTER_CUSTOM_SERVICE_DATA_LENGTH] = { RSI_BLE_MATTER_CUSTOM_SERVICE_DATA }; - - static const uuid_t custom_characteristic_RX = { - .size = RSI_BLE_CUSTOM_CHARACTERISTIC_RX_SIZE, - .reserved = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_RESERVED }, - .val = { .val128 = { .data1 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_1 }, - .data2 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_2 }, - .data3 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_3 }, - .data4 = { RSI_BLE_CUSTOM_CHARACTERISTIC_RX_VALUE_128_DATA_4 } } } - }; - - rsi_ble_resp_add_serv_t new_serv_resp = { 0 }; - rsi_ble_add_service(custom_service, &new_serv_resp); - - // Adding custom characteristic declaration to the custom service - rsi_ble_add_char_serv_att( - new_serv_resp.serv_handler, new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_ATTRIBUTE_HANDLE_LOCATION, - RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ, // Set read, write, write without response - new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_VALUE_HANDLE_LOCATION, custom_characteristic_RX); - - // Adding characteristic value attribute to the service - rsi_ble_add_char_val_att(new_serv_resp.serv_handler, - new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_RX_VALUE_HANDLE_LOCATION, custom_characteristic_RX, - RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ, // Set read, write, write without response - data, sizeof(data), ATT_REC_IN_HOST); - - static const uuid_t custom_characteristic_TX = { - .size = RSI_BLE_CUSTOM_CHARACTERISTIC_TX_SIZE, - .reserved = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_RESERVED }, - .val = { .val128 = { .data1 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_1 }, - .data2 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_2 }, - .data3 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_3 }, - .data4 = { RSI_BLE_CUSTOM_CHARACTERISTIC_TX_VALUE_128_DATA_4 } } } - }; - - // Adding custom characteristic declaration to the custom service - rsi_ble_add_char_serv_att( - new_serv_resp.serv_handler, new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_ATTRIBUTE_HANDLE_LOCATION, - RSI_BLE_ATT_PROPERTY_WRITE_NO_RESPONSE | RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ | - RSI_BLE_ATT_PROPERTY_NOTIFY | RSI_BLE_ATT_PROPERTY_INDICATE, // Set read, write, write without response - new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_MEASUREMENT_HANDLE_LOCATION, custom_characteristic_TX); - - // Adding characteristic value attribute to the service - bleEvent.eventData->rsi_ble_measurement_hndl = - new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_MEASUREMENT_HANDLE_LOCATION; - - // Adding characteristic value attribute to the service - bleEvent.eventData->rsi_ble_gatt_server_client_config_hndl = - new_serv_resp.start_handle + RSI_BLE_CHARACTERISTIC_TX_GATT_SERVER_CLIENT_HANDLE_LOCATION; - - rsi_ble_add_char_val_att(new_serv_resp.serv_handler, bleEvent.eventData->rsi_ble_measurement_hndl, custom_characteristic_TX, - RSI_BLE_ATT_PROPERTY_WRITE_NO_RESPONSE | RSI_BLE_ATT_PROPERTY_WRITE | RSI_BLE_ATT_PROPERTY_READ | - RSI_BLE_ATT_PROPERTY_NOTIFY | - RSI_BLE_ATT_PROPERTY_INDICATE, // Set read, write, write without response - data, sizeof(data), ATT_REC_MAINTAIN_IN_HOST); - - memset(&data, 0, sizeof(data)); - return 0; -} diff --git a/src/platform/silabs/rs911x/wfx_sl_ble_init.h b/src/platform/silabs/rs911x/wfx_sl_ble_init.h index 1e770de0727100..54351674ef121e 100644 --- a/src/platform/silabs/rs911x/wfx_sl_ble_init.h +++ b/src/platform/silabs/rs911x/wfx_sl_ble_init.h @@ -104,15 +104,13 @@ class SilabsBleWrapper rsi_ble_event_disconnect_t * resp_disconnect; rsi_ble_read_req_t * rsi_ble_read_req; rsi_ble_set_att_resp_t rsi_ble_event_set_att_rsp; - uint16_t rsi_ble_measurement_hndl; - uint16_t rsi_ble_gatt_server_client_config_hndl; uint16_t subscribed; }; struct BleEvent_t { BleEventType eventType; - sl_wfx_msg_t * eventData; + sl_wfx_msg_t eventData; }; // ALL Ble functions @@ -129,7 +127,6 @@ class SilabsBleWrapper uuid_t att_val_uuid); static void rsi_ble_add_char_val_att(void * serv_handler, uint16_t handle, uuid_t att_type_uuid, uint8_t val_prop, uint8_t * data, uint8_t data_len, uint8_t auth_read); - static uint32_t rsi_ble_add_matter_service(void); }; } // namespace Internal diff --git a/src/python_testing/TC_DeviceBasicComposition.py b/src/python_testing/TC_DeviceBasicComposition.py index 59182fa4e2fcb2..0f227c2c672ea4 100644 --- a/src/python_testing/TC_DeviceBasicComposition.py +++ b/src/python_testing/TC_DeviceBasicComposition.py @@ -108,7 +108,8 @@ from chip.clusters.ClusterObjects import ClusterAttributeDescriptor, ClusterObjectFieldDescriptor from chip.interaction_model import InteractionModelError, Status from chip.testing.basic_composition import BasicCompositionTests -from chip.testing.global_attribute_ids import AttributeIdType, ClusterIdType, GlobalAttributeIds, attribute_id_type, cluster_id_type +from chip.testing.global_attribute_ids import (AttributeIdType, ClusterIdType, CommandIdType, GlobalAttributeIds, attribute_id_type, + cluster_id_type, command_id_type) from chip.testing.matter_testing import (AttributePathLocation, ClusterPathLocation, CommandPathLocation, MatterBaseTest, TestStep, async_test_body, default_matter_test_main) from chip.testing.taglist_and_topology_test import (create_device_type_list_for_root, create_device_type_lists, @@ -503,7 +504,7 @@ class RequiredMandatoryAttribute: location = CommandPathLocation(endpoint_id=endpoint_id, cluster_id=cluster_id, command_id=bad_cmd_id) vendor_id = get_vendor_id(bad_cmd_id) self.record_error(self.get_test_name( - ), location=location, problem=f'Command 0x{bad_cmd_id:08x} with bad prefix 0x{vendor_id:04x} in cluster 0x{cluster_id:08x}', spec_location='Manufacturer Extensible Identifier (MEI)') + ), location=location, problem=f'Command 0x{bad_cmd_id:08x} with bad prefix 0x{vendor_id:04x} in cluster 0x{cluster_id:08x}' + (' (Test Vendor)' if command_id_type(bad_cmd_id) == CommandIdType.kTest else ''), spec_location='Manufacturer Extensible Identifier (MEI)') success = False self.print_step(7, "Validate that none of the MEI global attribute IDs contain values outside of the allowed suffix range") diff --git a/src/python_testing/TC_TSTAT_4_2.py b/src/python_testing/TC_TSTAT_4_2.py index 6dad144f3050c4..85ff487a9dc639 100644 --- a/src/python_testing/TC_TSTAT_4_2.py +++ b/src/python_testing/TC_TSTAT_4_2.py @@ -37,6 +37,7 @@ import copy import logging import random +from collections import namedtuple import chip.clusters as Clusters from chip import ChipDeviceCtrl # Needed before chip.FabricAdmin @@ -418,11 +419,6 @@ async def test_TC_TSTAT_4_2(self): logger.info( "Couldn't run test step 4 since there were no built-in presets") - # Send the SetActivePresetRequest command - await self.send_set_active_preset_handle_request_command(value=b'\x03') - - activePresetHandle = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=cluster.Attributes.ActivePresetHandle) - self.step("5") if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.Cfe.Rsp")): @@ -714,6 +710,28 @@ async def test_TC_TSTAT_4_2(self): self.step("18") if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.Cfe.Rsp")): + ScenarioHeadroom = namedtuple("ScenarioHeadroom", "presetScenario remaining") + # Generate list of tuples of scenarios and number of remaining presets per scenario allowed + presetScenarioHeadrooms = list(ScenarioHeadroom(presetType.presetScenario, + presetType.numberOfPresets - presetScenarioCounts.get(presetType.presetScenario, 0)) for presetType in presetTypes) + + if presetScenarioHeadrooms: + # Find the preset scenario with the smallest number of remaining allowed presets + presetScenarioHeadrooms = sorted(presetScenarioHeadrooms, key=lambda psh: psh.remaining) + presetScenarioHeadroom = presetScenarioHeadrooms[0] + + # Add one more preset than is allowed by the preset type + test_presets = copy.deepcopy(current_presets) + test_presets.extend([cluster.Structs.PresetStruct(presetHandle=NullValue, presetScenario=presetScenarioHeadroom.presetScenario, + coolingSetpoint=coolSetpoint, heatingSetpoint=heatSetpoint, builtIn=False)] * (presetScenarioHeadroom.remaining + 1)) + + await self.send_atomic_request_begin_command() + + await self.write_presets(endpoint=endpoint, presets=test_presets, expected_status=Status.ResourceExhausted) + + # Clear state for next test. + await self.send_atomic_request_rollback_command() + # Calculate the length of the Presets list that could be created using the preset scenarios in PresetTypes and numberOfPresets supported for each scenario. totalExpectedPresetsLength = sum(presetType.numberOfPresets for presetType in presetTypes) diff --git a/src/python_testing/TestIdChecks.py b/src/python_testing/TestIdChecks.py index eda01ef9556493..c86d4bfe6d0d0b 100644 --- a/src/python_testing/TestIdChecks.py +++ b/src/python_testing/TestIdChecks.py @@ -15,9 +15,9 @@ # limitations under the License. # -from chip.testing.global_attribute_ids import (AttributeIdType, ClusterIdType, DeviceTypeIdType, attribute_id_type, cluster_id_type, - device_type_id_type, is_valid_attribute_id, is_valid_cluster_id, - is_valid_device_type_id) +from chip.testing.global_attribute_ids import (AttributeIdType, ClusterIdType, CommandIdType, DeviceTypeIdType, attribute_id_type, + cluster_id_type, command_id_type, device_type_id_type, is_valid_attribute_id, + is_valid_cluster_id, is_valid_command_id, is_valid_device_type_id) from chip.testing.matter_testing import MatterBaseTest, default_matter_test_main from mobly import asserts @@ -210,6 +210,71 @@ def check_all_bad(id): for id in prefix_bad: check_all_bad(id) + def test_command_ids(self): + standard_global_good = [0x0000_00E0, 0x0000_00FF, 0x0000_00E1, 0x0000_00FE] + standard_global_bad = [0x0000_01E0, 0x0000_0FFF, 0x0000_AAE1, 0x0000_BBFE, 0x0000_FFFF] + scoped_non_global_good = [0x0000_0000, 0x0000_00DF, 0x0000_0001] + scoped_non_global_bad = [0x0000_0F00, 0x0000_01DF, 0x0000_0F01] + manufacturer_good = [0x0001_0000, 0x0001_00FF, 0xFFF0_0000, 0xFFF0_00FF, 0x0001_00FE] + manufacturer_bad = [0x0001_0A00, 0x0001_0BFF, 0x0001_FFFF, 0xFFF0_0C00, 0xFFF0_D0FF, 0x0001_F0FE] + test_good = [0xFFF1_0000, 0xFFF1_00E0, 0xFFF1_00FF, 0xFFF4_0000, 0xFFF4_00E0, 0xFFF4_00FF] + test_bad = [0xFFF1_5000, 0xFFF1_F000, 0xFFF1_FFFF, 0xFFF4_5000, 0xFFF4_F000, 0xFFF4_FFFF] + prefix_bad = [0xFFF5_0000, 0xFFF5_4FFF, 0xFFF5_5000, 0xFFF5_F000, 0xFFF5_FFFF] + + def check_standard_global(id): + id_type = command_id_type(id) + msg = f"Incorrect command range assessment, expecting standard global {id:08x}, type = {id_type}" + asserts.assert_equal(id_type, CommandIdType.kStandardGlobal, msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=True), msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=False), msg) + + def check_scoped_non_global(id): + id_type = command_id_type(id) + msg = f"Incorrect command range assessment, expecting scoped non-global {id:08x}, type = {id_type}" + asserts.assert_equal(id_type, CommandIdType.kScopedNonGlobal, msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=True), msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=False), msg) + + def check_manufacturer(id): + id_type = command_id_type(id) + msg = f"Incorrect command range assessment, expecting manufacturer {id:08x}, type = {id_type}" + asserts.assert_equal(id_type, CommandIdType.kManufacturer, msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=True), msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=False), msg) + + def check_test(id): + id_type = command_id_type(id) + msg = f"Incorrect command range assessment, expecting test {id:08x}, type = {id_type}" + asserts.assert_equal(id_type, CommandIdType.kTest, msg) + asserts.assert_true(is_valid_command_id(id_type, allow_test=True), msg) + asserts.assert_false(is_valid_command_id(id_type, allow_test=False), msg) + + def check_all_bad(id): + id_type = command_id_type(id) + msg = f"Incorrect command range assessment, expecting invalid {id:08x}, type = {id_type}" + asserts.assert_equal(id_type, CommandIdType.kInvalid, msg) + asserts.assert_false(is_valid_command_id(id_type, allow_test=True), msg) + asserts.assert_false(is_valid_command_id(id_type, allow_test=False), msg) + + for id in standard_global_good: + check_standard_global(id) + for id in standard_global_bad: + check_all_bad(id) + for id in scoped_non_global_good: + check_scoped_non_global(id) + for id in scoped_non_global_bad: + check_all_bad(id) + for id in manufacturer_good: + check_manufacturer(id) + for id in manufacturer_bad: + check_all_bad(id) + for id in test_good: + check_test(id) + for id in test_bad: + check_all_bad(id) + for id in prefix_bad: + check_all_bad(id) + if __name__ == "__main__": default_matter_test_main() diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/global_attribute_ids.py b/src/python_testing/matter_testing_infrastructure/chip/testing/global_attribute_ids.py index e692adfdfb5a10..f9fbd2e2ade835 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/global_attribute_ids.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/global_attribute_ids.py @@ -61,6 +61,15 @@ class AttributeIdType(Enum): kManufacturer = auto(), kTest = auto(), + +class CommandIdType(Enum): + kInvalid = auto() + kStandardGlobal = auto(), + kScopedNonGlobal = auto(), + kManufacturer = auto(), + kTest = auto(), + + # ID helper classes - this allows us to use the values from the prefix and suffix table directly # because the class handles the non-inclusive range. @@ -92,6 +101,9 @@ def __contains__(self, id: int): CLUSTER_ID_MANUFACTURER_RANGE_SUFFIX = SuffixIdRange(0xFC00, 0xFFFE) ATTRIBUTE_ID_GLOBAL_RANGE_SUFFIX = SuffixIdRange(0xF000, 0xFFFE) ATTRIBUTE_ID_NON_GLOBAL_RANGE_SUFFIX = SuffixIdRange(0x0000, 0x4FFF) +COMMAND_ID_GLOBAL_STANDARD_SUFFIX = SuffixIdRange(0x00E0, 0x00FF) +COMMAND_ID_NON_GLOBAL_SCOPED_SUFFIX = SuffixIdRange(0x0000, 0x00DF) +COMMAND_ID_SUFFIX = SuffixIdRange(0x0000, 0x00FF) def device_type_id_type(id: int) -> DeviceTypeIdType: @@ -145,3 +157,22 @@ def is_valid_attribute_id(id_type: AttributeIdType, allow_test: bool = False): if allow_test: valid.append(AttributeIdType.kTest) return id_type in valid + + +def command_id_type(id: int) -> CommandIdType: + if id in STANDARD_PREFIX and id in COMMAND_ID_GLOBAL_STANDARD_SUFFIX: + return CommandIdType.kStandardGlobal + if id in STANDARD_PREFIX and id in COMMAND_ID_NON_GLOBAL_SCOPED_SUFFIX: + return CommandIdType.kScopedNonGlobal + if id in MANUFACTURER_PREFIX and id in COMMAND_ID_SUFFIX: + return CommandIdType.kManufacturer + if id in TEST_PREFIX and id in COMMAND_ID_SUFFIX: + return CommandIdType.kTest + return CommandIdType.kInvalid + + +def is_valid_command_id(id_type: CommandIdType, allow_test: bool = False): + valid = [CommandIdType.kStandardGlobal, CommandIdType.kScopedNonGlobal, CommandIdType.kManufacturer] + if allow_test: + valid.append(CommandIdType.kTest) + return id_type in valid diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py index 0a40b1688d74cf..053fa575c6452d 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py @@ -919,6 +919,9 @@ class TestStep: expectation: str = "" is_commissioning: bool = False + def __str__(self): + return f'{self.test_plan_number}: {self.description}\tExpected outcome: {self.expectation}' + @dataclass class TestInfo: @@ -1325,7 +1328,7 @@ def extract_error_text() -> tuple[str, str]: if not trace: return no_stack_trace - if isinstance(exception, signals.TestError): + if isinstance(exception, signals.TestError) or isinstance(exception, signals.TestFailure): # Exception gets raised by the mobly framework, so the proximal error is one line back in the stack trace assert_candidates = [idx for idx, line in enumerate(trace) if "asserts" in line and "asserts.py" not in line] if not assert_candidates: @@ -1343,6 +1346,9 @@ def extract_error_text() -> tuple[str, str]: return probable_error.strip(), trace[file_candidates[-1]].strip() probable_error, probable_file = extract_error_text() + test_steps = self.get_defined_test_steps(self.current_test_info.name) + test_step = str(test_steps[self.current_step_index-1] + ) if test_steps is not None else 'UNKNOWN - no test steps provided in test script' logging.error(textwrap.dedent(f""" ****************************************************************** @@ -1353,8 +1359,12 @@ def extract_error_text() -> tuple[str, str]: * {probable_file} * {probable_error} * + * Test step: + * {test_step} + * + * Endpoint: {self.matter_test_config.endpoint} + * ******************************************************************* - """)) def on_pass(self, record): diff --git a/src/test_driver/nrfconnect/main/runner.cpp b/src/test_driver/nrfconnect/main/runner.cpp index 44fb5bae2a6183..bd719fbd4e5b33 100644 --- a/src/test_driver/nrfconnect/main/runner.cpp +++ b/src/test_driver/nrfconnect/main/runner.cpp @@ -29,7 +29,7 @@ using namespace ::chip::DeviceLayer; LOG_MODULE_REGISTER(runner, CONFIG_MATTER_LOG_LEVEL); -extern "C" int main(void) +int main(void) { VerifyOrDie(settings_subsys_init() == 0); diff --git a/src/tools/chip-cert/chip-cert.cpp b/src/tools/chip-cert/chip-cert.cpp index 571a00421f2569..a06a7341fafc09 100644 --- a/src/tools/chip-cert/chip-cert.cpp +++ b/src/tools/chip-cert/chip-cert.cpp @@ -85,7 +85,7 @@ bool PrintVersion() } // namespace -extern "C" int main(int argc, char * argv[]) +int main(int argc, char * argv[]) { bool res = false; diff --git a/src/tools/spake2p/spake2p.cpp b/src/tools/spake2p/spake2p.cpp index 45f5cc9d7c4323..ce1c0f82c60212 100644 --- a/src/tools/spake2p/spake2p.cpp +++ b/src/tools/spake2p/spake2p.cpp @@ -62,7 +62,7 @@ bool PrintVersion() } // namespace -extern "C" int main(int argc, char * argv[]) +int main(int argc, char * argv[]) { bool res = false; diff --git a/third_party/openthread/platforms/efr32/BUILD.gn b/third_party/openthread/platforms/efr32/BUILD.gn index 69e55a5d76151d..e270db2ae8757f 100644 --- a/third_party/openthread/platforms/efr32/BUILD.gn +++ b/third_party/openthread/platforms/efr32/BUILD.gn @@ -65,7 +65,6 @@ source_set("libopenthread-efr32") { "${sl_ot_efr32_root}/flash.c", "${sl_ot_efr32_root}/ieee802154-packet-utils.cpp", "${sl_ot_efr32_root}/misc.c", - "${sl_ot_efr32_root}/radio.c", "${sl_ot_efr32_root}/radio_coex.c", "${sl_ot_efr32_root}/radio_extension.c", "${sl_ot_efr32_root}/radio_power_manager.c", @@ -73,6 +72,9 @@ source_set("libopenthread-efr32") { "${sl_ot_efr32_root}/sleep.c", "${sl_ot_efr32_root}/soft_source_match_table.c", "${sl_ot_efr32_root}/system.c", + + # Temporary file until the files in the SI SDK is fixed + "${sdk_support_root}/protocol/openthread/platform-abstraction/efr32/radio.c", ] include_dirs = [ "${openthread_root}/examples/platforms/utils" ] diff --git a/third_party/openthread/repo b/third_party/openthread/repo index 2aeb8b833ba760..287dbfa25130ea 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit 2aeb8b833ba760ec29d5f340dd1ce7bcb61c5d56 +Subproject commit 287dbfa25130ead5010877e934effbb0a2534265 diff --git a/third_party/pigweed/repo b/third_party/pigweed/repo index d5fcc90b39ee75..ce0e3e2d1b7eec 160000 --- a/third_party/pigweed/repo +++ b/third_party/pigweed/repo @@ -1 +1 @@ -Subproject commit d5fcc90b39ee7568855390535fa854cea8f33c95 +Subproject commit ce0e3e2d1b7eec7cdf59fbb2ceed2b1cb3edd1ec diff --git a/third_party/pigweed/update.sh b/third_party/pigweed/update.sh old mode 100644 new mode 100755 index c8dd96862d7285..b15e967930577b --- a/third_party/pigweed/update.sh +++ b/third_party/pigweed/update.sh @@ -3,8 +3,8 @@ # Update the submodule. cd "$(dirname "${BASH_SOURCE[0]}")/repo" -git fetch origin master -git checkout origin/master +git fetch origin main +git checkout origin/main # Copy the CIPD manifest but change the Python line so we don't use CIPD # Python on Linux. diff --git a/third_party/silabs/BUILD.gn b/third_party/silabs/BUILD.gn index e08c7cd0bd11bd..16e0ba68c4607a 100644 --- a/third_party/silabs/BUILD.gn +++ b/third_party/silabs/BUILD.gn @@ -206,7 +206,9 @@ if (wifi_soc != true) { # CCP board "${openthread_root}/src/core/mac/mac_frame.cpp", "${openthread_root}/src/core/mac/sub_mac.cpp", "${openthread_root}/src/core/thread/mle.cpp", - "${sl_ot_platform_abstraction}/efr32/radio.c", + + # Temporary file until the files in the SI SDK is fixed + "${sdk_support_root}/protocol/openthread/platform-abstraction/efr32/radio.c", ] include_dirs = [ "${sl_ot_platform_abstraction}/include" ] diff --git a/third_party/silabs/lwip.gni b/third_party/silabs/lwip.gni index b0b6a0db0d2c9f..9a35e7c45f7a61 100644 --- a/third_party/silabs/lwip.gni +++ b/third_party/silabs/lwip.gni @@ -169,10 +169,8 @@ template("lwip_target") { "${_lwip_root}/src/core/ipv6/ip6.c", "${_lwip_root}/src/core/ipv6/ip6_addr.c", "${_lwip_root}/src/core/ipv6/ip6_frag.c", + "${_lwip_root}/src/core/ipv6/mld6.c", "${_lwip_root}/src/core/ipv6/nd6.c", - - # TODO: When updating to next Si SDK version, revert change. - "${sdk_support_root}/src/core/ipv6/mld6.c", ] } diff --git a/third_party/silabs/matter_support b/third_party/silabs/matter_support index 8dd7b9bb5f8577..bf647de36d841e 160000 --- a/third_party/silabs/matter_support +++ b/third_party/silabs/matter_support @@ -1 +1 @@ -Subproject commit 8dd7b9bb5f8577834140bcc54f7497ae3f4b9bd0 +Subproject commit bf647de36d841e62fdac5d37c0cdfc5ebf9200bc diff --git a/third_party/silabs/simplicity_sdk b/third_party/silabs/simplicity_sdk index aa5ce2e835dfdc..36e12f01947c2b 160000 --- a/third_party/silabs/simplicity_sdk +++ b/third_party/silabs/simplicity_sdk @@ -1 +1 @@ -Subproject commit aa5ce2e835dfdce8c20fb828f27d3a261946f946 +Subproject commit 36e12f01947c2bed82922015e87b926df0745bc2 diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/EntryToText.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/EntryToText.cpp index 0b5178d3bcb208..7c4c38ae6cec3f 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/EntryToText.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/EntryToText.cpp @@ -6495,6 +6495,8 @@ char const * DeviceTypeIdToText(chip::DeviceTypeId id) return "EVSE"; case 0x0000050D: return "Device Energy Management"; + case 0x0000050F: + return "Water Heater"; case 0x00000510: return "Electrical Sensor"; case 0x00000840: