From 9df00a22f42bf7d756ab36f90cd0842c871e4088 Mon Sep 17 00:00:00 2001 From: Axel Le Bourhis <45206070+axelnxp@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:17:34 +0100 Subject: [PATCH] [nxp fromtree][NXP] Initial enablement of NXP Matter over WiFi with Zephyr (#31648) * [zephyr] Update deprecated Kconfig CPLUSPLUS is deprecated and should be replaced with CPP LIB_CPLUSPLUS is deprecated and should be replaced with REQUIRES_FULL_LIBCPP Signed-off-by: Axel Le Bourhis * [NXP] Initial enablement of NXP Matter over WiFi with Zephyr Features: * Matter over WiFi * BLE commissioning * Storage * Factory data * OTA * MbedTLS PSA API Signed-off-by: Axel Le Bourhis * Restyled by whitespace * Restyled by clang-format * Restyled by gn * Restyled by prettier-markdown * Fix misspell error Signed-off-by: Axel Le Bourhis * Update copyrights to date contributed Signed-off-by: Axel Le Bourhis --------- Signed-off-by: Axel Le Bourhis Co-authored-by: Restyled.io (cherry picked from commit 28676c8) --- config/nxp/README.md | 10 + config/nxp/app/bootloader.conf | 25 + config/nxp/app/enable-gnu-std.cmake | 22 + config/nxp/app/pre-zephyr.cmake | 21 + config/nxp/chip-gn/.gn | 29 + config/nxp/chip-gn/BUILD.gn | 40 + config/nxp/chip-gn/args.gni | 32 + config/nxp/chip-gn/toolchain/BUILD.gn | 34 + config/nxp/chip-module/CMakeLists.txt | 270 +++++++ config/nxp/chip-module/Kconfig | 258 +++++++ config/nxp/chip-module/Kconfig.defaults | 381 ++++++++++ config/nxp/chip-module/Kconfig.features | 74 ++ .../chip-module/generate_factory_data.cmake | 229 ++++++ config/nxp/chip-module/zephyr/module.yml | 22 + config/zephyr/Kconfig | 8 +- docs/guides/nxp_zephyr_ota_software_update.md | 205 ++++++ src/platform/BUILD.gn | 9 + src/platform/device.gni | 19 +- .../factory_data/FactoryDataProvider.cpp | 6 +- src/platform/nxp/zephyr/BLEManagerImpl.h | 26 + src/platform/nxp/zephyr/BUILD.gn | 111 +++ src/platform/nxp/zephyr/BlePlatformConfig.h | 27 + .../nxp/zephyr/CHIPDevicePlatformConfig.h | 220 ++++++ .../nxp/zephyr/CHIPDevicePlatformEvent.h | 26 + src/platform/nxp/zephyr/CHIPPlatformConfig.h | 141 ++++ .../nxp/zephyr/ConfigurationManagerImpl.h | 26 + .../nxp/zephyr/ConnectivityManagerImpl.cpp | 69 ++ .../nxp/zephyr/ConnectivityManagerImpl.h | 121 ++++ .../zephyr/DeviceInstanceInfoProviderImpl.cpp | 47 ++ .../zephyr/DeviceInstanceInfoProviderImpl.h | 43 ++ .../zephyr/DiagnosticDataProviderImplNxp.cpp | 157 ++++ .../zephyr/DiagnosticDataProviderImplNxp.h | 60 ++ .../nxp/zephyr/FactoryDataProviderImpl.cpp | 246 +++++++ .../nxp/zephyr/FactoryDataProviderImpl.h | 82 +++ src/platform/nxp/zephyr/InetPlatformConfig.h | 27 + .../nxp/zephyr/KeyValueStoreManagerImpl.h | 27 + src/platform/nxp/zephyr/PlatformManagerImpl.h | 25 + .../nxp/zephyr/SystemPlatformConfig.h | 27 + src/platform/nxp/zephyr/args.gni | 20 + .../nxp/zephyr/nxp-zephyr-mbedtls-config.h | 38 + .../nxp/zephyr/ota/OTAImageProcessorImpl.cpp | 174 +++++ .../nxp/zephyr/ota/OTAImageProcessorImpl.h | 54 ++ .../wifi/ConnectivityManagerImplWiFi.cpp | 178 +++++ .../zephyr/wifi/ConnectivityManagerImplWiFi.h | 80 ++ .../nxp/zephyr/wifi/NxpWifiDriver.cpp | 298 ++++++++ src/platform/nxp/zephyr/wifi/NxpWifiDriver.h | 112 +++ src/platform/nxp/zephyr/wifi/WiFiManager.cpp | 685 ++++++++++++++++++ src/platform/nxp/zephyr/wifi/WiFiManager.h | 253 +++++++ 48 files changed, 5079 insertions(+), 15 deletions(-) create mode 100644 config/nxp/README.md create mode 100644 config/nxp/app/bootloader.conf create mode 100644 config/nxp/app/enable-gnu-std.cmake create mode 100644 config/nxp/app/pre-zephyr.cmake create mode 100644 config/nxp/chip-gn/.gn create mode 100644 config/nxp/chip-gn/BUILD.gn create mode 100644 config/nxp/chip-gn/args.gni create mode 100644 config/nxp/chip-gn/toolchain/BUILD.gn create mode 100644 config/nxp/chip-module/CMakeLists.txt create mode 100644 config/nxp/chip-module/Kconfig create mode 100644 config/nxp/chip-module/Kconfig.defaults create mode 100644 config/nxp/chip-module/Kconfig.features create mode 100644 config/nxp/chip-module/generate_factory_data.cmake create mode 100644 config/nxp/chip-module/zephyr/module.yml create mode 100644 docs/guides/nxp_zephyr_ota_software_update.md create mode 100644 src/platform/nxp/zephyr/BLEManagerImpl.h create mode 100644 src/platform/nxp/zephyr/BUILD.gn create mode 100644 src/platform/nxp/zephyr/BlePlatformConfig.h create mode 100644 src/platform/nxp/zephyr/CHIPDevicePlatformConfig.h create mode 100644 src/platform/nxp/zephyr/CHIPDevicePlatformEvent.h create mode 100644 src/platform/nxp/zephyr/CHIPPlatformConfig.h create mode 100644 src/platform/nxp/zephyr/ConfigurationManagerImpl.h create mode 100644 src/platform/nxp/zephyr/ConnectivityManagerImpl.cpp create mode 100644 src/platform/nxp/zephyr/ConnectivityManagerImpl.h create mode 100644 src/platform/nxp/zephyr/DeviceInstanceInfoProviderImpl.cpp create mode 100644 src/platform/nxp/zephyr/DeviceInstanceInfoProviderImpl.h create mode 100644 src/platform/nxp/zephyr/DiagnosticDataProviderImplNxp.cpp create mode 100644 src/platform/nxp/zephyr/DiagnosticDataProviderImplNxp.h create mode 100644 src/platform/nxp/zephyr/FactoryDataProviderImpl.cpp create mode 100644 src/platform/nxp/zephyr/FactoryDataProviderImpl.h create mode 100644 src/platform/nxp/zephyr/InetPlatformConfig.h create mode 100644 src/platform/nxp/zephyr/KeyValueStoreManagerImpl.h create mode 100644 src/platform/nxp/zephyr/PlatformManagerImpl.h create mode 100644 src/platform/nxp/zephyr/SystemPlatformConfig.h create mode 100644 src/platform/nxp/zephyr/args.gni create mode 100644 src/platform/nxp/zephyr/nxp-zephyr-mbedtls-config.h create mode 100644 src/platform/nxp/zephyr/ota/OTAImageProcessorImpl.cpp create mode 100755 src/platform/nxp/zephyr/ota/OTAImageProcessorImpl.h create mode 100644 src/platform/nxp/zephyr/wifi/ConnectivityManagerImplWiFi.cpp create mode 100644 src/platform/nxp/zephyr/wifi/ConnectivityManagerImplWiFi.h create mode 100644 src/platform/nxp/zephyr/wifi/NxpWifiDriver.cpp create mode 100644 src/platform/nxp/zephyr/wifi/NxpWifiDriver.h create mode 100644 src/platform/nxp/zephyr/wifi/WiFiManager.cpp create mode 100644 src/platform/nxp/zephyr/wifi/WiFiManager.h diff --git a/config/nxp/README.md b/config/nxp/README.md new file mode 100644 index 00000000000000..e15ad309dc9d1a --- /dev/null +++ b/config/nxp/README.md @@ -0,0 +1,10 @@ +# NXP Zephyr build and configuration files + +This directory contains build scripts and common configuration files used by +CHIP NXP Zephyr applications. It is structured as follows: + +| File/Folder | Contents | +| ----------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| chip-gn | GN project used to build selected CHIP libraries with the _nxp_zephyr_ platform integration layer | +| chip-module | CMake wrapper for the GN project defined in `chip-gn` directory, and other components that allow one to use CHIP as a Zephyr module | +| app | Common and optional Kconfig configuration files that can be used in NXP Zephyr applications | diff --git a/config/nxp/app/bootloader.conf b/config/nxp/app/bootloader.conf new file mode 100644 index 00000000000000..281e1145a89aa0 --- /dev/null +++ b/config/nxp/app/bootloader.conf @@ -0,0 +1,25 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Options to be used for MCUBOOT build are located on this file. + +# The default signature key used by MCUBOOT is located on their repository, +# change this to the appropriate one. +# NOTE: This option needs to contain a path to the same file used by +# MCUBOOT_SIGNATURE_KEY_FILE. +#CONFIG_BOOT_SIGNATURE_KEY_FILE="root-rsa-2048.pem" + +CONFIG_BOOT_MAX_IMG_SECTORS=2048 diff --git a/config/nxp/app/enable-gnu-std.cmake b/config/nxp/app/enable-gnu-std.cmake new file mode 100644 index 00000000000000..a5a5c6c6aca10f --- /dev/null +++ b/config/nxp/app/enable-gnu-std.cmake @@ -0,0 +1,22 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +add_library(gnu17 INTERFACE) +target_compile_options(gnu17 + INTERFACE + $<$:-std=gnu++17> + -D_SYS__PTHREADTYPES_H_) +target_link_libraries(app PRIVATE gnu17) diff --git a/config/nxp/app/pre-zephyr.cmake b/config/nxp/app/pre-zephyr.cmake new file mode 100644 index 00000000000000..9dd1b2ae32c5bf --- /dev/null +++ b/config/nxp/app/pre-zephyr.cmake @@ -0,0 +1,21 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Automatically find overlays defined at platform level +# Those are usually used to change FLASH and RAM layouts +if (EXISTS ${CHIP_ROOT}/src/platform/nxp/zephyr/boards/${BOARD}/${BOARD}.overlay) + list(APPEND EXTRA_DTC_OVERLAY_FILE ${CHIP_ROOT}/src/platform/nxp/zephyr/boards/${BOARD}/${BOARD}.overlay) +endif() diff --git a/config/nxp/chip-gn/.gn b/config/nxp/chip-gn/.gn new file mode 100644 index 00000000000000..0cc783dee91703 --- /dev/null +++ b/config/nxp/chip-gn/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + target_os = "zephyr" + + import("${chip_root}/config/nxp/chip-gn/args.gni") +} diff --git a/config/nxp/chip-gn/BUILD.gn b/config/nxp/chip-gn/BUILD.gn new file mode 100644 index 00000000000000..1fc09ec27d611a --- /dev/null +++ b/config/nxp/chip-gn/BUILD.gn @@ -0,0 +1,40 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") + +import("${chip_root}/build/chip/tests.gni") + +assert(current_os == "zephyr") + +declare_args() { + chip_build_example_providers = false +} + +group("nxp_zephyr") { + deps = [ "${chip_root}/src/lib" ] + + if (chip_build_tests) { + deps += [ "${chip_root}/src:tests" ] + } + + if (chip_build_example_providers) { + deps += [ "${chip_root}/examples/providers:device_info_provider" ] + } +} + +group("default") { + deps = [ ":nxp_zephyr" ] +} diff --git a/config/nxp/chip-gn/args.gni b/config/nxp/chip-gn/args.gni new file mode 100644 index 00000000000000..702e9537b4b74d --- /dev/null +++ b/config/nxp/chip-gn/args.gni @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") + +import("${chip_root}/src/crypto/crypto.gni") + +chip_device_platform = "nxp_zephyr" + +chip_build_tests = false + +chip_project_config_include = "" +chip_system_project_config_include = "" +chip_ble_project_config_include = "" + +chip_crypto = "mbedtls" +chip_external_mbedtls = true + +custom_toolchain = "${chip_root}/config/nxp/chip-gn/toolchain:zephyr" + +pw_build_PIP_CONSTRAINTS = [ "${chip_root}/scripts/setup/constraints.txt" ] diff --git a/config/nxp/chip-gn/toolchain/BUILD.gn b/config/nxp/chip-gn/toolchain/BUILD.gn new file mode 100644 index 00000000000000..0bee7f170cbd89 --- /dev/null +++ b/config/nxp/chip-gn/toolchain/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +import("${build_root}/toolchain/arm_gcc/arm_toolchain.gni") + +declare_args() { + zephyr_ar = "" + zephyr_cc = "" + zephyr_cxx = "" +} + +gcc_toolchain("zephyr") { + ar = zephyr_ar + cc = zephyr_cc + cxx = zephyr_cxx + + toolchain_args = { + current_os = "zephyr" + is_clang = false + } +} diff --git a/config/nxp/chip-module/CMakeLists.txt b/config/nxp/chip-module/CMakeLists.txt new file mode 100644 index 00000000000000..0e35f27a44d153 --- /dev/null +++ b/config/nxp/chip-module/CMakeLists.txt @@ -0,0 +1,270 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# +# @file +# CMake sub-project defining 'chip' target which represents CHIP library +# and other optional libraries like unit tests, built with 'nxp_zephyr' +# platform. +# Since CHIP doesn't provide native CMake support, ExternalProject +# module is used to build the required artifacts with GN meta-build +# system. It is assumed that find_package(Zephyr) has been called before +# including this file. +# + +if (CONFIG_CHIP) + +include(ExternalProject) +include(../../zephyr/ota-image.cmake) +include(../../zephyr/zephyr-util.cmake) +include(generate_factory_data.cmake) + +# ============================================================================== +# Prepare CHIP configuration based on the project Kconfig configuration +# ============================================================================== + +# Set paths + +if (NOT CHIP_ROOT) + get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../.. REALPATH) +endif() +get_filename_component(GN_ROOT_TARGET ${CHIP_ROOT}/config/nxp/chip-gn REALPATH) +get_filename_component(COMMON_CMAKE_SOURCE_DIR ${CHIP_ROOT}/config/common/cmake REALPATH) + +# Get common Cmake sources + +include(${COMMON_CMAKE_SOURCE_DIR}/chip_gn_args.cmake) +include(${COMMON_CMAKE_SOURCE_DIR}/chip_gn.cmake) + +# Prepare compiler flags +if (CHIP_CFLAGS) + matter_add_flags("${CHIP_CFLAGS}") +endif() + +matter_add_cxxflags(-D_POSIX_C_SOURCE=200809) + +if (CONFIG_ARM) + matter_add_cflags(--specs=nosys.specs) +endif() + +if(CONFIG_MBEDTLS) + zephyr_include_directories($) + zephyr_compile_definitions($) +endif() + +zephyr_include_directories(${CHIP_ROOT}/src/platform/nxp/zephyr) + +zephyr_get_compile_flags(ZEPHYR_CFLAGS_C C) +matter_add_cflags("${ZEPHYR_CFLAGS_C}") +zephyr_get_compile_flags(ZEPHYR_CFLAGS_CC CXX) +matter_add_cxxflags("${ZEPHYR_CFLAGS_CC}") +zephyr_get_gnu_cpp_standard(ZEPHYR_GNU_CPP_STD) +matter_add_cxxflags(${ZEPHYR_GNU_CPP_STD}) + +# Set up custom OpenThread configuration + +if (CONFIG_CHIP_OPENTHREAD_CONFIG) + get_filename_component(CHIP_OPENTHREAD_CONFIG + ${CONFIG_CHIP_OPENTHREAD_CONFIG} + REALPATH + BASE_DIR ${CMAKE_SOURCE_DIR} + ) + zephyr_set_openthread_config(${CHIP_OPENTHREAD_CONFIG}) +endif() + +# Set up Zephyr symbol level + +if (NOT CONFIG_CHIP_DEBUG_SYMBOLS) + set_compiler_property(PROPERTY debug -g0) +endif() + +# Determine if ccache should be used + +get_property(CHIP_COMPILER_LAUNCHER GLOBAL PROPERTY RULE_LAUNCH_COMPILE) + +# ============================================================================== +# Generate configuration for CHIP GN build system +# ============================================================================== + +matter_common_gn_args( + DEBUG CONFIG_DEBUG + LIB_SHELL CONFIG_CHIP_LIB_SHELL + LIB_TESTS CONFIG_CHIP_BUILD_TESTS + PROJECT_CONFIG ${CONFIG_CHIP_PROJECT_CONFIG} + DEVICE_INFO_EXAMPLE_PROVIDER CONFIG_CHIP_EXAMPLE_DEVICE_INFO_PROVIDER +) +matter_add_gn_arg_string("zephyr_ar" ${CMAKE_AR}) +matter_add_gn_arg_string("zephyr_cc" ${CMAKE_C_COMPILER}) +matter_add_gn_arg_string("zephyr_cxx" ${CMAKE_CXX_COMPILER}) +matter_add_gn_arg_bool ("chip_logging" CONFIG_LOG) +matter_add_gn_arg_bool ("chip_enable_openthread" CONFIG_NET_L2_OPENTHREAD) +matter_add_gn_arg_bool ("chip_openthread_ftd" CONFIG_OPENTHREAD_FTD) +matter_add_gn_arg_bool ("chip_config_network_layer_ble" CONFIG_BT) +matter_add_gn_arg_bool ("chip_inet_config_enable_ipv4" CONFIG_CHIP_IPV4) +matter_add_gn_arg_bool ("chip_persist_subscriptions" CONFIG_CHIP_PERSISTENT_SUBSCRIPTIONS) +matter_add_gn_arg_bool ("chip_monolithic_tests" CONFIG_CHIP_BUILD_TESTS) +matter_add_gn_arg_bool ("chip_inet_config_enable_tcp_endpoint" CONFIG_CHIP_BUILD_TESTS) +matter_add_gn_arg_bool ("chip_error_logging" CONFIG_MATTER_LOG_LEVEL GREATER_EQUAL 1) +matter_add_gn_arg_bool ("chip_progress_logging" CONFIG_MATTER_LOG_LEVEL GREATER_EQUAL 3) +matter_add_gn_arg_bool ("chip_detail_logging" CONFIG_MATTER_LOG_LEVEL GREATER_EQUAL 4) +matter_add_gn_arg_bool ("chip_automation_logging" FALSE) +matter_add_gn_arg_bool ("chip_malloc_sys_heap" CONFIG_CHIP_MALLOC_SYS_HEAP) +matter_add_gn_arg_bool ("chip_enable_wifi" CONFIG_CHIP_WIFI) +matter_add_gn_arg_bool ("chip_system_config_provide_statistics" CONFIG_CHIP_STATISTICS) +matter_add_gn_arg_bool ("chip_enable_icd_server" CONFIG_CHIP_ENABLE_ICD_SUPPORT) +matter_add_gn_arg_bool ("enable_eventlist_attribute" TRUE) +matter_add_gn_arg_bool ("chip_enable_ota_requestor" CONFIG_CHIP_OTA_REQUESTOR) + +if(CONFIG_DEBUG) + matter_add_gn_arg_bool("optimize_debug" true) + matter_add_gn_arg_string("optimize_debug_level" "0") + matter_add_gn_arg_string("symbol_level" "2") +endif() + +if (CONFIG_CHIP_FACTORY_DATA) + matter_add_gn_arg_bool("chip_use_transitional_commissionable_data_provider" FALSE) + matter_add_gn_arg_bool("chip_enable_factory_data" TRUE) +elseif (CONFIG_CHIP_FACTORY_DATA_CUSTOM_BACKEND) + matter_add_gn_arg_bool("chip_use_transitional_commissionable_data_provider" FALSE) +endif() + +if (CONFIG_CHIP_ROTATING_DEVICE_ID) + matter_add_gn_arg_bool("chip_enable_rotating_device_id" TRUE) + matter_add_gn_arg_bool("chip_enable_additional_data_advertising" TRUE) +endif() + +if (CONFIG_NET_L2_OPENTHREAD) + matter_add_gn_arg_string("chip_mdns" "platform") +elseif(CONFIG_WIFI_NXP) + matter_add_gn_arg_string("chip_mdns" "minimal") +else() + matter_add_gn_arg_string("chip_mdns" "none") +endif() + +if (CONFIG_CHIP_CRYPTO_PSA) + matter_add_gn_arg_string("chip_crypto" "psa") +endif() + +# if (BOARD STREQUAL "native_posix") +# matter_add_gn_arg_string("target_cpu" "x86") +# elseif (BOARD STREQUAL "native_posix_64") +# matter_add_gn_arg_string("target_cpu" "x64") +# endif() + +if (NOT CONFIG_CHIP_DEBUG_SYMBOLS) + matter_add_gn_arg_string("symbol_level" "0") +endif() + +# if (CHIP_COMPILER_LAUNCHER) +# matter_add_gn_arg_string("pw_command_launcher" ${CHIP_COMPILER_LAUNCHER}) +# endif() + +# if (CONFIG_CHIP_PW_RPC) +# set(PIGWEED_DIR "//third_party/pigweed/repo") +# matter_add_gn_arg_string("pw_assert_BACKEND" ${PIGWEED_DIR}/pw_assert_log:check_backend) +# matter_add_gn_arg_string("pw_log_BACKEND" ${PIGWEED_DIR}/pw_log_basic) +# matter_add_gn_arg("pw_build_LINK_DEPS" [\"${PIGWEED_DIR}/pw_assert:impl\",\ \"${PIGWEED_DIR}/pw_log:impl\"]) +# endif() + +matter_generate_args_tmp_file() + +# ============================================================================== +# Build chip library +# ============================================================================== + +matter_build(chip + LIB_SHELL ${CONFIG_CHIP_LIB_SHELL} + LIB_TESTS ${CONFIG_CHIP_BUILD_TESTS} + DEVICE_INFO_EXAMPLE_PROVIDER ${CONFIG_CHIP_EXAMPLE_DEVICE_INFO_PROVIDER} + GN_DEPENDENCIES kernel +) + +set_property(GLOBAL APPEND PROPERTY ZEPHYR_INTERFACE_LIBS chip) +# Enable visibility of POSIX.1-2008 functions, such as strnlen +target_compile_definitions(chip INTERFACE _POSIX_C_SOURCE=200809) +# Make sure that kernel symbols that are only referenced by the Matter libraries are resolved. +target_link_libraries(chip INTERFACE $) + +if (CONFIG_CHIP_MALLOC_SYS_HEAP_OVERRIDE) + target_link_options(chip INTERFACE + -Wl,--wrap=malloc + -Wl,--wrap=calloc + -Wl,--wrap=realloc + -Wl,--wrap=free + -Wl,--wrap=_malloc_r + -Wl,--wrap=_calloc_r + -Wl,--wrap=_realloc_r + -Wl,--wrap=_free_r + ) +endif() + +# ============================================================================== +# Define 'chip-ota-image' target for building CHIP OTA image +# ============================================================================== +if(EXISTS "${CHIP_ROOT}/src/platform/nxp/zephyr/boards/${BOARD}/${BOARD}.overlay") + set(DTC_BOARD_OVERLAY "${CHIP_ROOT}/src/platform/nxp/zephyr/boards/${BOARD}/${BOARD}.overlay") +else() + set(DTC_BOARD_OVERLAY "") + message(STATUS "No board overlay found") +endif() + +if (CONFIG_CHIP_OTA_REQUESTOR) + if(CONFIG_MCUBOOT_SIGNATURE_KEY_FILE STREQUAL "") + set(ZEPHYR_OUTPUT_NAME "zephyr") + else() + set(ZEPHYR_OUTPUT_NAME "zephyr.signed") + endif() + + set(GLOBAL_BOOTLOADER_CONF_OVERLAY_FILE "${CHIP_ROOT}/config/nxp/app/bootloader.conf") + + add_custom_target(build_mcuboot ALL + COMMAND + west build -b ${BOARD} -d build_mcuboot ${ZEPHYR_BASE}/../bootloader/mcuboot/boot/zephyr + -- -DOVERLAY_CONFIG=${GLOBAL_BOOTLOADER_CONF_OVERLAY_FILE} -DEXTRA_DTC_OVERLAY_FILE=${DTC_BOARD_OVERLAY} + COMMAND + cp ${PROJECT_BINARY_DIR}/../modules/connectedhomeip/build_mcuboot/zephyr/zephyr.bin ${PROJECT_BINARY_DIR}/zephyr.mcuboot.bin + ) + + set(BLOCK_SIZE "1024") + dt_nodelabel(dts_partition_path NODELABEL "boot_partition") + dt_reg_size(mcuboot_size PATH ${dts_partition_path}) + math(EXPR boot_blocks "${mcuboot_size} / ${BLOCK_SIZE}" OUTPUT_FORMAT DECIMAL) + + add_custom_target(merge_mcuboot ALL + COMMAND + dd if=${PROJECT_BINARY_DIR}/zephyr.mcuboot.bin of=${PROJECT_BINARY_DIR}/zephyr_full.bin + COMMAND + dd if=${PROJECT_BINARY_DIR}/${ZEPHYR_OUTPUT_NAME}.bin of=${PROJECT_BINARY_DIR}/zephyr_full.bin bs=${BLOCK_SIZE} seek=${boot_blocks} + ) + add_dependencies(merge_mcuboot ${ZEPHYR_FINAL_EXECUTABLE}) + + if (CONFIG_CHIP_OTA_IMAGE_BUILD) + chip_ota_image(chip-ota-image + INPUT_FILES ${PROJECT_BINARY_DIR}/${ZEPHYR_OUTPUT_NAME}.bin + OUTPUT_FILE ${PROJECT_BINARY_DIR}/${CONFIG_CHIP_OTA_IMAGE_FILE_NAME} + ) + endif() +endif() + +# ============================================================================== +# Define 'factory_data' target for generating a factory data partition +# ============================================================================== + +if (CONFIG_CHIP_FACTORY_DATA_BUILD) + nxp_generate_factory_data() +endif() + +endif() # CONFIG_CHIP diff --git a/config/nxp/chip-module/Kconfig b/config/nxp/chip-module/Kconfig new file mode 100644 index 00000000000000..88918a67450ad3 --- /dev/null +++ b/config/nxp/chip-module/Kconfig @@ -0,0 +1,258 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +rsource "../../zephyr/Kconfig" + +if CHIP + +config CHIP_NXP_PLATFORM + bool + default y + help + States that the configuration uses Matter NXP platform, + what can be used to conditionally deviate from Zephyr generic configuration + for NXP platform related purposes. + +# See config/zephyr/Kconfig for full definition +config CHIP_DEVICE_VENDOR_NAME + default "NXP Semiconductors" + +config CHIP_APP_LOG_LEVEL + int "Logging level in application" + default LOG_DEFAULT_LEVEL + depends on LOG + help + Sets the logging level in the Matter application. Use this configuration + option only within the application. To set the logging level for the + Matter stack, use the MATTER_LOG_LEVEL configuration option. + +config CHIP_EXAMPLE_DEVICE_INFO_PROVIDER + bool "Include default device information provider build" + default y + +config CHIP_DEBUG_SYMBOLS + bool "Generate debug symbols" + default y + help + Enables building the application with debug symbols. + +config CHIP_MALLOC_SYS_HEAP + default y if !ARCH_POSIX + +config CHIP_FACTORY_DATA + bool "Factory data provider" + help + Enables the default NXP factory data provider implementation that + supports reading the factory data encoded in the KLV format from the + flash memory partition. This option requires a fixed partition named + "factory_partition" declared on the device tree. Factory data partition + can be generated during build process, see CHIP_FACTORY_DATA_BUILD Kconfig. + +config CHIP_FACTORY_DATA_CUSTOM_BACKEND + bool "Custom factory data provider" + depends on !CHIP_FACTORY_DATA + help + Enables user's custom factory data provider implementation. This option + cannot be used with the CHIP_FACTORY_DATA, which enables the default NXP + factory data provider implementation. + +config CHIP_FACTORY_DATA_BUILD + bool "Generate factory data contents" + default n + imply CHIP_FACTORY_DATA + help + Enables generation of the factory data contents during the building. This + option requires a fixed partition named "factory_partition" declared on the + device tree. + +config CHIP_FACTORY_DATA_VERSION + int + default 1 + help + Provides the version of the generated factory data parameter set. This is + a hidden configuration option that the user cannot change. You can use + this value in the factory data provider implementation to verify that the + factory data saved in the flash memory has the expected version. + +config CHIP_FACTORY_DATA_ROTATING_DEVICE_UID_MAX_LEN + int "Maximum length of rotating device ID unique ID in bytes" + default 16 + depends on CHIP_FACTORY_DATA + help + Maximum acceptable length of rotating device ID unique ID in bytes. + +if CHIP_FACTORY_DATA + +config CHIP_ENCRYPTED_FACTORY_DATA_AES128_KEY + string "AES128 key used to encrypt factory data." + default "2B7E151628AED2A6ABF7158809CF4F3C" + help + AES128 key used to encrypt factory data. + +config CHIP_ENCRYPTED_FACTORY_DATA + bool "Encrypt factory data with AES128 ECB." + default y + help + If enabled, the factory data partition will be encrypted with AES128 ECB. + +config CHIP_DEVICE_PRODUCT_URL + string "Product URL" + help + Provides the URL to the product page. The URL is exposed as an attribute + of the Basic Information cluster. + +config CHIP_DEVICE_PRODUCT_LABEL + string "Product label" + help + Provides the product label. The label is exposed as an attribute + of the Basic Information cluster. + +config CHIP_DEVICE_PART_NUMBER + string "Part number" + help + Provides the part number. The part number is exposed as an attribute + of the Basic Information cluster. + +endif + +if CHIP_FACTORY_DATA_BUILD + +# Factory data definitions +config CHIP_FACTORY_DATA_GENERATE_ONBOARDING_CODES + bool "Generate onboarding codes during the generation of a factory data set" + help + Enables generation of onboarding codes (manual pairing code and QR code) + during the generation of a factory data set. You can provide the + onboarding codes a Matter controller to commission a device to a Matter + network. + +# Select source of the certificates +choice CHIP_FACTORY_DATA_CERT_SOURCE + prompt "Attestation certificate file source" + default CHIP_FACTORY_DATA_USE_DEFAULT_CERTS + + config CHIP_FACTORY_DATA_USE_DEFAULT_CERTS + bool "Use pre-generated development certificates" + help + Uses pre-generated certificate files from the + credentials/development/attestation/ directory that match the + configured Product ID. This can be used for development purpose. + + config CHIP_FACTORY_DATA_CERT_SOURCE_GENERATED + bool "Auto-generate certificates" + help + Generates new certificates instead of using pre-generated ones. The + certificates are generated on every build. + + config CHIP_FACTORY_DATA_CERT_SOURCE_USER + bool "Use user-provided certificate files" + help + Uses user-provided certificate files. The user needs to specify the + absolute paths to all necessary files. + +endchoice + +if CHIP_FACTORY_DATA_CERT_SOURCE_USER + +config CHIP_FACTORY_DATA_USER_CERTS_CD_CERT + string "Path to the CD certificate (DER format)" + help + Provides the absolute path to the CD certificate file in the DER format. + +config CHIP_FACTORY_DATA_USER_CERTS_DAC_CERT + string "Path to the DAC certificate (DER format)" + help + Provides the absolute path to the DAC certificate file in the DER format. + +config CHIP_FACTORY_DATA_USER_CERTS_DAC_KEY + string "Path to the DAC private key (DER format)" + help + Provides the absolute path to the DAC keypair file in the DER format. Both + public and private keys must be present (the private key will be extracted + automatically). + +config CHIP_FACTORY_DATA_USER_CERTS_PAI_CERT + string "Path to the PAI certificate (DER format)" + help + Provides the absolute path to the PAI certificate in the DER format. +endif + +# Configs for SPAKE2+ generation +config CHIP_FACTORY_DATA_GENERATE_SPAKE2_VERIFIER + bool "Generate SPAKE2+ verifier" + help + Enables the generation of the SPAKE2+ verifier for the configured SPAKE2+ + passcode, iteration count and salt. + +config CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID + bool "Generate Rotating device ID unique ID" + default y + help + Enables the generation of a random Rotating device ID unique ID. + +endif #CHIP_FACTORY_DATA_BUILD + +# See config/zephyr/Kconfig for full definition +config CHIP_FACTORY_RESET_ERASE_NVS + bool + default y if CHIP_FACTORY_DATA || CHIP_FACTORY_DATA_CUSTOM_BACKEND + +endif + +config CHIP_LOG_SIZE_OPTIMIZATION + bool "Disable some detailed logs to decrease flash usage" + help + Disables some log levels for specific Matter log modules that provide + information that is too detailed to be used in most cases. You can find + full configuration enabled by this option in the + platform/nxp/CHIPPlatformConfig.h file. + +config CHIP_IPV4 + bool "IPv4 support for Matter" + default n + depends on NET_IPV4 + help + If disabled, it allows to build NXP SDK application + with IPv4 support independently of the Matter stack still + running over IPv6. + +config CHIP_OTA_REQUESTOR + bool + select BOOTLOADER_MCUBOOT + +config BOOTLOADER_MCUBOOT + bool + select IMG_MANAGER + select STREAM_FLASH + select STREAM_FLASH_ERASE + +config CHIP_OTA_REQUESTOR_BUFFER_SIZE + int "OTA Requestor image buffer size" + default 256 + depends on CHIP_OTA_REQUESTOR + help + Configures the size of the buffer used by OTA Requestor when downloading + and writing a new firmware image to flash. + +config CHIP_OTA_REQUESTOR_REBOOT_ON_APPLY + bool "Auto-reboot when firmware update is applied" + default y + depends on CHIP_OTA_REQUESTOR + imply REBOOT + help + Reboots the device automatically after downloading a new firmware update + to swap the old and the new firmware images. The reboot happens only when + a user consents to apply the firmware update. diff --git a/config/nxp/chip-module/Kconfig.defaults b/config/nxp/chip-module/Kconfig.defaults new file mode 100644 index 00000000000000..56c82e3752900c --- /dev/null +++ b/config/nxp/chip-module/Kconfig.defaults @@ -0,0 +1,381 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# The purpose of this file is to define new default values of settings used when building Matter samples. +# This file only changes defaults and thus all symbols here must be promptless +# and safeguarded so that they only are applied when building Matter. + +if CHIP + +config CHIP_OPERATIONAL_TIME_SAVE_INTERVAL + default 1 + +if CHIP_FACTORY_DATA + +config CHIP_DEVICE_VENDOR_ID + default 4151 # 0x1037 + +config CHIP_DEVICE_MANUFACTURING_DATE + default "2023-01-01" + +config CHIP_DEVICE_PRODUCT_ID + default 41510 if SOC_SERIES_RW6XX + +endif # CHIP_FACTORY_DATA + +config LOG + default y + +if LOG + +choice LOG_MODE + default LOG_MODE_MINIMAL +endchoice + +choice MATTER_LOG_LEVEL_CHOICE + default MATTER_LOG_LEVEL_DBG +endchoice + +config CHIP_APP_LOG_LEVEL + default 4 # debug + +config LOG_DEFAULT_LEVEL + default 1 # error + +config CHIP_LOG_SIZE_OPTIMIZATION + default y + +endif + +config PRINTK_SYNC + default y + +config ASSERT + default y + +config ASSERT_NO_COND_INFO + default y + +config ASSERT_NO_MSG_INFO + default y + +config HW_STACK_PROTECTION + default y + +config FPU + default y + +config SHELL + default y + +config PTHREAD_IPC + bool + default n + +config POSIX_MAX_FDS + int + default 16 + +# Application stack size +config MAIN_STACK_SIZE + default 8192 + +config INIT_STACKS + default y + +config NET_MGMT_EVENT_STACK_SIZE + default 2048 + +config NET_IPV6_MLD + default y + +config NET_IF_MCAST_IPV6_ADDR_COUNT + default 14 + +config NET_TC_TX_COUNT + default 1 + +config NET_TC_RX_COUNT + default 1 + +config NET_TC_THREAD_PRIO_CUSTOM + default y + +choice NET_TC_THREAD_TYPE + default NET_TC_THREAD_PREEMPTIVE +endchoice + +config NET_TCP_WORK_QUEUE_THREAD_PRIO + default -16 + +config NET_TC_TX_THREAD_BASE_PRIO + default 3 + +config NET_TC_RX_THREAD_BASE_PRIO + default 3 + +# Network buffers +config NET_PKT_RX_COUNT + default 16 + +config NET_PKT_TX_COUNT + default 16 + +config NET_BUF_RX_COUNT + default 60 + +config NET_BUF_TX_COUNT + default 80 + +config NET_BUF_DATA_SIZE + default 1700 + +# Bluetooth Low Energy configs + +config BT + default y + +config BT_PERIPHERAL + default y + +config BT_CENTRAL + default n + +config BT_PERIPHERAL_PREF_MIN_INT + default 36 + +config BT_PERIPHERAL_PREF_MAX_INT + default 36 + +# Increase BT timeout to 5 s to improve connection reliability and avoid fast drop outs. +config BT_PERIPHERAL_PREF_TIMEOUT + default 500 + +config BT_GAP_AUTO_UPDATE_CONN_PARAMS + default y + +# Decrease connection parameters update time, as some Matter controllers request +# enabling IP networking faster than BT connection parameters are updated, what may result +# in commissioning instabilities. +config BT_CONN_PARAM_UPDATE_TIMEOUT + default 1000 + +config BT_GATT_DYNAMIC_DB + default y + +config BT_DEVICE_NAME_DYNAMIC + default y + +config BT_DEVICE_NAME_MAX + default 15 + +config BT_MAX_CONN + default 1 + +config BT_L2CAP_TX_MTU + default 247 + +config BT_BUF_ACL_RX_SIZE + default 251 + +config BT_BUF_ACL_TX_SIZE + default 251 + +config BT_RX_STACK_SIZE + default 2048 if NO_OPTIMIZATIONS && DEBUG + default 1536 + +config BT_DEVICE_NAME_GATT_WRITABLE + bool + default n + +config HCI_NXP_ENABLE_AUTO_SLEEP + default n + +config CHIP_OTA_REQUESTOR + default n + +# Enable extended discovery +config CHIP_EXTENDED_DISCOVERY + default y + +config NVS_LOOKUP_CACHE + default y + +config NVS_LOOKUP_CACHE_SIZE + default 512 + +if CHIP_WIFI + +choice SCHED_ALGORITHM + default SCHED_MULTIQ +endchoice + +choice LIBC_IMPLEMENTATION + default NEWLIB_LIBC +endchoice + +choice WPA_SUPP_LOG_LEVEL_CHOICE + default WPA_SUPP_LOG_LEVEL_ERR +endchoice + +config WPA_SUPP_THREAD_STACK_SIZE + default 6144 + +config SYSTEM_WORKQUEUE_STACK_SIZE + default 2048 + +# align these numbers to match the OpenThread config +config NET_IF_UNICAST_IPV6_ADDR_COUNT + default 6 + +config NET_IF_MCAST_IPV6_ADDR_COUNT + default 8 + +config NET_SOCKETS_POLL_MAX + default 4 + +# options managed by IP4/IP6 simultaneous support +# aligned here to match OpenThread config +config NET_MAX_ROUTERS + default 1 + +config NET_MAX_CONN + default 4 + +config SHELL_STACK_SIZE + default 2616 + +config HEAP_MEM_POOL_SIZE + default 65536 + +config CHIP_MALLOC_SYS_HEAP_SIZE + default 28672 # 28 kB + +endif + +# Configure MBEDTLS lib +config MBEDTLS + default y + +config MBEDTLS_CFG_FILE + default "config-tls-generic.h" + +config MBEDTLS_USER_CONFIG_ENABLE + default y + +config MBEDTLS_USER_CONFIG_FILE + default "nxp-zephyr-mbedtls-config.h" + +config MBEDTLS_ENTROPY_ENABLED + default y + +config MBEDTLS_ZEPHYR_ENTROPY + default y + +config MBEDTLS_ENABLE_HEAP + default y + +config MBEDTLS_HEAP_SIZE + default 15360 + +config MBEDTLS_CIPHER_AES_ENABLED + default y + +config MBEDTLS_CIPHER_CCM_ENABLED + default y + +config MBEDTLS_CTR_DRBG_ENABLED + default y + +config MBEDTLS_CIPHER_MODE_CBC_ENABLED + default y + +config MBEDTLS_ECP_C + default y + +config MBEDTLS_ECP_DP_SECP256R1_ENABLED + default y + +if CHIP_CRYPTO_PSA + +config MBEDTLS_PSA_CRYPTO_C + default y + +config WPA_SUPP_CRYPTO_MBEDTLS_PSA + default y if WPA_SUPP_CRYPTO + +endif + +config MCUX_ELS_PKC + default y if SOC_SERIES_RW6XX + +if MCUX_ELS_PKC + +config KSDK_MBEDTLS + default n + +config MCUX_PSA_CRYPTO_DRIVER_ELS_PKC + default y if MBEDTLS_PSA_CRYPTO_C + +config ENTROPY_GENERATOR + default y + +endif # MCUX_ELS_PKC + + +if SHELL + +config KERNEL_SHELL + default y + +config DEVICE_SHELL + default y + +config REBOOT + default y + +# Disable not used shell modules +config SHELL_WILDCARD + default n + +config SHELL_VT100_COLORS + default n + +config SHELL_STATS + default n + +config SENSOR_SHELL + default n + +config DATE_SHELL + default n + +config DEVMEM_SHELL + default n + +config MCUBOOT_SHELL + default n + +config FLASH_SHELL + default n + +endif # SHELL + +endif + +config NXP_FW_LOADER_MONOLITHIC + default y if NXP_FW_LOADER diff --git a/config/nxp/chip-module/Kconfig.features b/config/nxp/chip-module/Kconfig.features new file mode 100644 index 00000000000000..d8d194ccef2b41 --- /dev/null +++ b/config/nxp/chip-module/Kconfig.features @@ -0,0 +1,74 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# The purpose of this file is to define Kconfig options enabling specific features. +# Feature options will define defaults for settings that are related to the specific feature. + +if CHIP + +config CHIP_WIFI + bool "Enable NXP Wi-Fi support" + default y + select WIFI + select WIFI_NXP + select WPA_SUPP + select WPA_SUPP_AP + select WPA_SUPP_WPS + select WPA_SUPP_WPA3 + select WPA_SUPP_CRYPTO_ENTERPRISE + imply MBEDTLS_ENTROPY_C + imply NET_STATISTICS + imply NET_PKT_TXTIME + imply NET_PKT_TIMESTAMP + imply NET_IPV6_ND # enable Neighbor Discovery to handle Router Advertisements + imply NET_IPV6_NBR_CACHE + imply NET_STATISTICS_IPV6 + imply NET_STATISTICS_USER_API + +config CHIP_WIFI_CONNECTION_RECOVERY_MINIMUM_INTERVAL + int "Define the minimum connection recovery time interval in milliseconds" + depends on CHIP_WIFI + default 500 + help + Specifies the minimum connection recovery interval (in milliseconds). + +config CHIP_WIFI_CONNECTION_RECOVERY_MAXIMUM_INTERVAL + int "Define the maximum connection recovery time interval in milliseconds" + depends on CHIP_WIFI + default 3600000 # 1 hour + help + Specifies the maximum connection recovery interval (in milliseconds). + +config CHIP_WIFI_CONNECTION_RECOVERY_MAX_RETRIES_NUMBER + int "Define the maximum amount of connection recovery occurrences" + depends on CHIP_WIFI + default 0 + help + Specifies the maximum number of connection recovery attempts. + If set to 0, no limitation is applied and attempts + to recover the connection are performed indefinitely. + +config CHIP_WIFI_CONNECTION_RECOVERY_JITTER + int "Define the connection recovery jitter in milliseconds" + depends on CHIP_WIFI + default 2000 + help + Specifies the maximum connection recovery jitter interval (in milliseconds). + Once the wait time reaches the current maximum value (defined by CHIP_WIFI_CONNECTION_RECOVERY_MAXIMUM_INTERVAL), + a random jitter interval is added to it to avoid periodicity. The random jitter is selected + within range [-JITTER; +JITTER]. + +endif # CHIP diff --git a/config/nxp/chip-module/generate_factory_data.cmake b/config/nxp/chip-module/generate_factory_data.cmake new file mode 100644 index 00000000000000..ea1e35a797ab78 --- /dev/null +++ b/config/nxp/chip-module/generate_factory_data.cmake @@ -0,0 +1,229 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Generate certificates based on factory data given via Kconfigs. +# +# This function creates a list of arguments for external script and then run it to generate certificates. +# +# During generation process a some file will be created in zephyr's build directory: +# - Chip-PAI-NXP---Cert.der +# - Chip-PAI-NXP---Key.der +# - Chip-DAC-NXP---Cert.der +# - Chip-DAC-NXP---Key.der +# +# [Args]: +# script_path - a path to script that generates the certificates. +# output_path - a path to output directory, where generated certificates will be stored. +function(nxp_generate_certs script_path output_path) + if(NOT EXISTS ${CHIP_ROOT}/out/chip-cert) + message(FATAL_ERROR "Couldn't find chip-cert in ${CHIP_ROOT}/out folder. + Run following command from ${CHIP_ROOT} to build it: + gn gen out + ninja -C out chip-cert") + endif() + + # generate all script arguments + set(script_args) + string(APPEND script_args "--gen_cd\n") + string(APPEND script_args "--cd_type \"1\"\n") + string(APPEND script_args "--chip_cert_path ${CHIP_ROOT}/out/chip-cert\n") + string(APPEND script_args "--vendor_id ${CONFIG_CHIP_DEVICE_VENDOR_ID}\n") + string(APPEND script_args "--product_id ${CONFIG_CHIP_DEVICE_PRODUCT_ID}\n") + string(APPEND script_args "--vendor_name \"${CONFIG_CHIP_DEVICE_VENDOR_NAME}\"\n") + string(APPEND script_args "--product_name \"${CONFIG_CHIP_DEVICE_PRODUCT_NAME}\"\n") + string(APPEND script_args "--device_type \"${CONFIG_CHIP_DEVICE_TYPE}\"\n") + string(APPEND script_args "--output \"${output_path}\"\n") + + # convert decimal VID to its hexadecimal representation to find out certification files in repository + math(EXPR LOCAL_VID "${CONFIG_CHIP_DEVICE_VENDOR_ID}" OUTPUT_FORMAT HEXADECIMAL) + string(SUBSTRING ${LOCAL_VID} 2 -1 raw_vid) + string(TOUPPER ${raw_vid} raw_vid_upper) + + # convert decimal PID to its hexadecimal representation to find out certification files in repository + math(EXPR LOCAL_PID "${CONFIG_CHIP_DEVICE_PRODUCT_ID}" OUTPUT_FORMAT HEXADECIMAL) + string(SUBSTRING ${LOCAL_PID} 2 -1 raw_pid) + string(TOUPPER ${raw_pid} raw_pid_upper) + + # execute the script which can generate the certificates + separate_arguments(separated_script_args NATIVE_COMMAND ${script_args}) + add_custom_command( + OUTPUT + ${output_path}/Chip-PAI-NXP-${raw_vid_upper}-${raw_pid_upper}-Cert.pem + ${output_path}/Chip-PAI-NXP-${raw_vid_upper}-${raw_pid_upper}-Key.pem + ${output_path}/Chip-DAC-NXP-${raw_vid_upper}-${raw_pid_upper}-Cert.pem + ${output_path}/Chip-DAC-NXP-${raw_vid_upper}-${raw_pid_upper}-Key.pem + ${output_path}/Chip-PAI-NXP-${raw_vid_upper}-${raw_pid_upper}-Cert.der + ${output_path}/Chip-PAI-NXP-${raw_vid_upper}-${raw_pid_upper}-Key.der + ${output_path}/Chip-DAC-NXP-${raw_vid_upper}-${raw_pid_upper}-Cert.der + ${output_path}/Chip-DAC-NXP-${raw_vid_upper}-${raw_pid_upper}-Key.der + DEPENDS ${script_path} + COMMAND ${Python3_EXECUTABLE} ${script_path} ${separated_script_args} + COMMENT "Generating new certificates..." + ) + add_custom_target(chip-certificates ALL + DEPENDS + ${output_path}/Chip-PAI-NXP-${raw_vid_upper}-${raw_pid_upper}-Cert.pem + ${output_path}/Chip-PAI-NXP-${raw_vid_upper}-${raw_pid_upper}-Key.pem + ${output_path}/Chip-DAC-NXP-${raw_vid_upper}-${raw_pid_upper}-Cert.pem + ${output_path}/Chip-DAC-NXP-${raw_vid_upper}-${raw_pid_upper}-Key.pem + ${output_path}/Chip-PAI-NXP-${raw_vid_upper}-${raw_pid_upper}-Cert.der + ${output_path}/Chip-PAI-NXP-${raw_vid_upper}-${raw_pid_upper}-Key.der + ${output_path}/Chip-DAC-NXP-${raw_vid_upper}-${raw_pid_upper}-Cert.der + ${output_path}/Chip-DAC-NXP-${raw_vid_upper}-${raw_pid_upper}-Key.der + ) +endfunction() + +# Create a .bin file with factory data in KLV format. +# +# This function creates a .bin file from given Kconfig. +# +# During generation process, following files will be created in zephyr's build directory: +# - .bin a binary file containing all raw factory data in KLV format. +# +# [Args]: +# script_path - a path to script that makes a factory data .bin file from given arguments. +# output_path - a path to output directory, where created bin file will be stored. +function(nxp_generate_factory_data_bin script_path output_path) + if(NOT EXISTS ${CHIP_ROOT}/out/spake2p) + message(FATAL_ERROR "Couldn't find spake2p in ${CHIP_ROOT}/out folder. + Run following command from ${CHIP_ROOT} to build it: + gn gen out + ninja -C out spake2p") + endif() + + # convert decimal VID to its hexadecimal representation to find out certification files in repository + math(EXPR LOCAL_VID "${CONFIG_CHIP_DEVICE_VENDOR_ID}" OUTPUT_FORMAT HEXADECIMAL) + string(SUBSTRING ${LOCAL_VID} 2 -1 raw_vid) + string(TOUPPER ${raw_vid} raw_vid_upper) + + # convert decimal PID to its hexadecimal representation to find out certification files in repository + math(EXPR LOCAL_PID "${CONFIG_CHIP_DEVICE_PRODUCT_ID}" OUTPUT_FORMAT HEXADECIMAL) + string(SUBSTRING ${LOCAL_PID} 2 -1 raw_pid) + string(TOUPPER ${raw_pid} raw_pid_upper) + + # generate all script arguments + set(script_args) + string(APPEND script_args "--it \"${CONFIG_CHIP_DEVICE_SPAKE2_IT}\"\n") + string(APPEND script_args "--salt \"${CONFIG_CHIP_DEVICE_SPAKE2_SALT}\"\n") + string(APPEND script_args "--discriminator ${CONFIG_CHIP_DEVICE_DISCRIMINATOR}\n") + string(APPEND script_args "--passcode ${CONFIG_CHIP_DEVICE_SPAKE2_PASSCODE}\n") + string(APPEND script_args "--vid ${CONFIG_CHIP_DEVICE_VENDOR_ID}\n") + string(APPEND script_args "--pid ${CONFIG_CHIP_DEVICE_PRODUCT_ID}\n") + string(APPEND script_args "--vendor_name \"${CONFIG_CHIP_DEVICE_VENDOR_NAME}\"\n") + string(APPEND script_args "--product_name \"${CONFIG_CHIP_DEVICE_PRODUCT_NAME}\"\n") + string(APPEND script_args "--hw_version ${CONFIG_CHIP_DEVICE_HARDWARE_VERSION}\n") + string(APPEND script_args "--hw_version_str \"${CONFIG_CHIP_DEVICE_HARDWARE_VERSION_STRING}\"\n") + string(APPEND script_args "--spake2p_path \"${CHIP_ROOT}/out/spake2p\"\n") + string(APPEND script_args "--serial_num \"${CONFIG_CHIP_DEVICE_SERIAL_NUMBER}\"\n") + string(APPEND script_args "--date \"${CONFIG_CHIP_DEVICE_MANUFACTURING_DATE}\"\n") + string(APPEND script_args "--unique_id \"${CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID}\"\n") + string(APPEND script_args "--product_finish ${CONFIG_CHIP_DEVICE_PRODUCT_FINISH}\n") + string(APPEND script_args "--product_url ${CONFIG_CHIP_DEVICE_PRODUCT_URL}\n") + string(APPEND script_args "--product_label ${CONFIG_CHIP_DEVICE_PRODUCT_LABEL}\n") + string(APPEND script_args "--part_number ${CONFIG_CHIP_DEVICE_PART_NUMBER}\n") + string(APPEND script_args "--out \"${output_path}/factory_data.bin\"\n") + + # for development purpose user can use default certs instead of generating or providing them + if(CONFIG_CHIP_FACTORY_DATA_USE_DEFAULT_CERTS) + # all certs are located in ${CHIP_ROOT}/credentials/development/attestation + # it can be used during development without need to generate new certifications + set(cd_cert ${CHIP_ROOT}/credentials/development/cd-certs/Chip-Test-CD-Cert.der) + set(dac_cert ${CHIP_ROOT}/credentials/development/attestation/Matter-Development-DAC-${raw_vid_upper}-${raw_pid_upper}-Cert.der) + set(dac_key ${CHIP_ROOT}/credentials/development/attestation/Matter-Development-DAC-${raw_vid_upper}-${raw_pid_upper}-Key.der) + set(pai_cert ${CHIP_ROOT}/credentials/development/attestation/Matter-Development-PAI-${raw_vid_upper}-noPID-Cert.der) + elseif(CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_USER) + set(cd_cert ${CONFIG_CHIP_FACTORY_DATA_USER_CERTS_CD_CERT}) + set(dac_cert ${CONFIG_CHIP_FACTORY_DATA_USER_CERTS_DAC_CERT}) + set(dac_key ${CONFIG_CHIP_FACTORY_DATA_USER_CERTS_DAC_KEY}) + set(pai_cert ${CONFIG_CHIP_FACTORY_DATA_USER_CERTS_PAI_CERT}) + elseif(CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_GENERATED) + set(cd_cert ${output_path}/Chip-Test-CD-${raw_vid_upper}-${raw_pid_upper}.der) + set(dac_cert ${output_path}/Chip-DAC-NXP-${raw_vid_upper}-${raw_pid_upper}-Cert.der) + set(dac_key ${output_path}/Chip-DAC-NXP-${raw_vid_upper}-${raw_pid_upper}-Key.der) + set(pai_cert ${output_path}/Chip-PAI-NXP-${raw_vid_upper}-${raw_pid_upper}-Cert.der) + else() + message(FATAL_ERROR "Either CONFIG_CHIP_FACTORY_DATA_USE_DEFAULT_CERTS or CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_USER + or CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_GENERATED must be defined. + See ${CHIP_ROOT}/config/nxp/chip-module/Kconfig for details.") + endif() + + string(APPEND script_args "--cert_declaration \"${cd_cert}\"\n") + string(APPEND script_args "--dac_cert \"${dac_cert}\"\n") + string(APPEND script_args "--dac_key \"${dac_key}\"\n") + string(APPEND script_args "--pai_cert \"${pai_cert}\"\n") + + # check if spake2 verifier should be generated using script + if(NOT CONFIG_CHIP_FACTORY_DATA_GENERATE_SPAKE2_VERIFIER) + # Spake2 verifier should be provided using Kconfig + string(APPEND script_args "--spake2p_verifier \"${CONFIG_CHIP_DEVICE_SPAKE2_TEST_VERIFIER}\"\n") + endif() + + if(CONFIG_CHIP_ENCRYPTED_FACTORY_DATA) + if(NOT CONFIG_CHIP_ENCRYPTED_FACTORY_DATA_AES128_KEY) + message(FATAL_ERROR "CONFIG_CHIP_ENCRYPTED_FACTORY_DATA_AES128_KEY is required when using CONFIG_CHIP_ENCRYPTED_FACTORY_DATA !") + endif() + + string(APPEND script_args "--aes128_key \"${CONFIG_CHIP_ENCRYPTED_FACTORY_DATA_AES128_KEY}\"\n") + endif() + + if(CONFIG_CHIP_DEVICE_PRODUCT_COLOR) + string(APPEND script_args "--product_primary_color ${CONFIG_CHIP_DEVICE_PRODUCT_COLOR}\n") + endif() + + # execute the script which can generate the factory_data.bin file + separate_arguments(separated_script_args NATIVE_COMMAND ${script_args}) + add_custom_command( + OUTPUT ${output_path}/factory_data.bin + DEPENDS ${script_path} + COMMAND ${Python3_EXECUTABLE} ${script_path} ${separated_script_args} + COMMENT "Generating new Factory Data..." + ) + add_custom_target(factory_data ALL + DEPENDS ${output_path}/factory_data.bin + ) + + if(CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_GENERATED) + # Make sure certificates are generated before trying to generate factory data + add_dependencies(factory_data chip-certificates) + endif() +endfunction() + +# Generate factory data partition using given args +# +# During generation process a some file will be created in zephyr's build directory: +# - factory_data.bin: a raw binary file containing the factory data partition +# - CD, PAI, DEC certificates if CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_GENERATED is set +# +function(nxp_generate_factory_data) + find_package(Python REQUIRED) + + # CHIP_ROOT must be provided as a reference set all localization of scripts + if(NOT CHIP_ROOT) + message(FATAL_ERROR "CHIP_ROOT variable is not set, please add it to CMakeLists.txt file") + endif() + + # Localize all scripts needed to generate factory data partition + set(GENERATE_CERTS_SCRIPT_PATH ${CHIP_ROOT}/scripts/tools/nxp/generate_certs.py) + set(GENERATE_FDATA_SCRIPT_PATH ${CHIP_ROOT}/scripts/tools/nxp/factory_data_generator/generate.py) + set(OUTPUT_FILE_PATH ${APPLICATION_BINARY_DIR}/zephyr) + + if(CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_GENERATED) + # Generate certificates + nxp_generate_certs(${GENERATE_CERTS_SCRIPT_PATH} ${OUTPUT_FILE_PATH}) + endif() + + nxp_generate_factory_data_bin(${GENERATE_FDATA_SCRIPT_PATH} ${OUTPUT_FILE_PATH}) +endfunction() diff --git a/config/nxp/chip-module/zephyr/module.yml b/config/nxp/chip-module/zephyr/module.yml new file mode 100644 index 00000000000000..870b1a37e35231 --- /dev/null +++ b/config/nxp/chip-module/zephyr/module.yml @@ -0,0 +1,22 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: connectedhomeip +build: + cmake: . + kconfig: Kconfig + depends: + - openthread diff --git a/config/zephyr/Kconfig b/config/zephyr/Kconfig index bd4b52ecb7a193..8df6c418aa42e3 100644 --- a/config/zephyr/Kconfig +++ b/config/zephyr/Kconfig @@ -17,12 +17,12 @@ menuconfig CHIP bool "Matter protocol stack" default n - select CPLUSPLUS - imply LIB_CPLUSPLUS + select CPP + imply REQUIRES_FULL_LIBCPP imply REQUIRES_FULL_LIBC imply NEWLIB_LIBC_NANO imply CBPRINTF_LIBC_SUBSTS - imply POSIX_API if !ARCH_POSIX && !CHIP_NRF_PLATFORM + imply POSIX_API if !ARCH_POSIX && !CHIP_NRF_PLATFORM && !CHIP_NXP_PLATFORM imply EVENTFD if !ARCH_POSIX imply REBOOT imply ENTROPY_GENERATOR @@ -30,7 +30,7 @@ menuconfig CHIP imply NET_IPV6 imply NET_CONFIG_NEED_IPV6 imply NET_SOCKETS - imply NET_SOCKETS_POSIX_NAMES if !ARCH_POSIX && CHIP_NRF_PLATFORM + imply NET_SOCKETS_POSIX_NAMES if !ARCH_POSIX && (CHIP_NRF_PLATFORM || CHIP_NXP_PLATFORM) imply NETWORKING imply HWINFO imply FLASH diff --git a/docs/guides/nxp_zephyr_ota_software_update.md b/docs/guides/nxp_zephyr_ota_software_update.md new file mode 100644 index 00000000000000..430e0bfd81e694 --- /dev/null +++ b/docs/guides/nxp_zephyr_ota_software_update.md @@ -0,0 +1,205 @@ +# Matter Over-The-Air Software Update with NXP using Zephyr example applications + +## Overview + +The OTA Requestor feature enables the device to be informed of, download and +apply a software update from an OTA Provider. + +This section explains how to perform an OTA Software Update with NXP platform +using NXP/Zephyr SDK. Throughout this guide, the all-clusters application is +used as an example. + +In general, the Over-The-Air Software Update process consists of the following +steps : + +- The OTA Requestor queries an update image from the OTA Provider which + responds according to its availability. +- The update image is received in blocks and stored in the external flash of + the device. +- Once the update image is fully downloaded, the bootloader is notified and + the device resets applying the update in test-mode. +- If the test is successful, the update is applied permanently. Otherwise, the + bootloader reverts back to the primary application, preventing any + downgrade. + +### Flash Memory Layout + +The Flash is divided into different regions as follow : + +- Bootloader : MCUBoot resides at the base of the flash. +- Primary application partition : The example application which would be run + by the bootloader (active application). +- Secondary application partition : Update image received with the OTA + (candidate application). + +The size reserved for each partition can be found in +`src/platform/nxp/zephyr/boards/board.overlay`. + +Notes : + +- When applicable, BLE/15.4/Wi-Fi firmware are embedded in the application + binary, ensuring compatibility between the application and the controllers. +- The sizes of the primary and secondary applications are provided as an + example. The size can be changed by overriding the partitions located at + `board.overlay`.(example: + `src/platform/nxp/zephyr/boards/rd_rw612_bga.overlay`) + +### MCUBoot Bootloader + +Current OTA solution is using MCUBoot Bootloader. MCUBoot is an open-source +secure bootloader used to apply the self-upgrade. For more details, please refer +to the +[MCUBoot documentation](https://github.com/mcu-tools/mcuboot/blob/main/docs/design.md). + +In our use case, the bootloader runs the application residing in the primary +partition. In order to run the OTA update image, the bootloader will swap the +content of the primary and the secondary partitions. This type of upgrade is +called swap-move and is the default upgrade configured by MCUBoot. + +## OTA Software Update process + +### Generating and flashing application image + +The all cluster app is able to demonstrate the usage of OTA. To have this OTA +support, prj_ota.conf configurations needs to be used. This can be done by +adding `-DEXTRA_CONF_FILE=prj_ota.conf` to the west build command. + +Current OTA implementation automates the following procedures: + +- Generation of MCUBOOT image (File generated: + `modules/connectedhomeip/build_mcuboot/zephyr/zephyr.bin`)\* +- Generation of Matter application image (File generated: + `zephyr/zephyr.bin`)\* +- Signature of the application image (File generated: + `zephyr/zephyr.signed.bin`)\* +- Generation of a single binary merging the signed application with the + MCUBoot Image (File generated: `zephyr/zephyr_full.bin`)\* + +> **Note**: \*All paths are relative to the output folder. + +The final binary to be used is `zephyr_full.bin`. + +The application image have the following format : + +- Header : contains general information about the image (version, size, + magic...) +- Code of the application : generated binary +- Trailer : contains metadata needed by the bootloader such as the image + signature, the upgrade type, the swap status... + +In the all-cluster-app example, the image is signed with the default private key +provided by MCUBoot(`/zephyrproject/bootloader/mcuboot/root-rsa-2048.pem`). +MCUBoot is built with its corresponding public key which would be used to verify +the integrity of the image. It is possible to generate a new pair of keys using +the following commands. This procedure should be done prior to building the +mcuboot application. + +- To generate the private key : + +``` +user@ubuntu: python3 imgtool.py keygen -k priv_key.pem -t rsa-2048 +``` + +- To extract the public key : + +``` +user@ubuntu: python3 imgtool.py getpub -k priv_key.pem +``` + +To use a different key than the default one, `CONFIG_BOOT_SIGNATURE_KEY_FILE` +and `CONFIG_MCUBOOT_SIGNATURE_KEY_FILE` needs to point to that same key. + +- `CONFIG_BOOT_SIGNATURE_KEY_FILE`: This is used for the MCUboot bootloader + image. The path to the key can be either absolute or relative. Relative + paths starts from the MCUBoot repository root. This option can be changed + in: `config/nxp/app/bootloader.conf` + +- `CONFIG_BOOT_SIGNATURE_KEY_FILE`: This is used for the application to be + loaded by the bootloader. The path can be either absolute or relative. + Relative paths starts from the west workspace location. This option can be + changed in the application .conf files. + +Refer to those two files for more information: + +- [MCUBoot Config used for the MCUBoot Image](https://github.com/zephyrproject-rtos/mcuboot/blob/main/boot/zephyr/Kconfig) +- [MCUBoot Config used for the application](https://github.com/zephyrproject-rtos/zephyr/blob/main/modules/Kconfig.mcuboot) + +JLink can be used to flash the mixed binary at the base address 0x8000000, using +the command : + +``` +J-Link > loadbin zephyr_full.bin 0x8000000 +``` + +The bootloader should then be able to jump directly to the start of the +application and run it. + +### Generating the OTA Update Image + +The same procedure can be followed from the +[Generating and flashing application image](#generating-and-flashing-application-image) +sub-section, replacing `CONFIG_CHIP_DEVICE_SOFTWARE_VERSION` with a number +greater than the initial one used on the active application (Candidate +application version number should be greater than the one used on the active +application). By default the value is set to 0, try resetting this option to 1 +to generate the OTA update Image. You can do this by adding +`-DCONFIG_CHIP_DEVICE_SOFTWARE_VERSION=1` to the west build command. + +The current implementation automates the following procedures: + +- Generation of the Image to be used for update (File generated: + `zephyr/zephyr.bin`)\* +- Signature of the Image (File generated: `zephyr/zephyr.signed.bin`)\* +- Conversion of the signed Image into the OTA format (.ota file) (File + generated: `zephyr/matter.ota`)\* + +> **Note**: \*All paths are relative to the output folder. + +The generated OTA file `matter.ota` can be used to perform the OTA Software +Update. The instructions below describes the procedure step-by-step. + +### Performing the OTA Software Update + +Setup example : + +- [Chip-tool](../../examples/chip-tool/README.md) application running on the + RPi. +- OTA Provider application built on the same RPi (as explained below). +- Board programmed with the example application (with the instructions above). + +Before starting the OTA process, the Linux OTA Provider application can be built +on the RPi (if not already present in the pre-installed apps) : + +``` +user@ubuntu:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/ota-provider-app chip_config_network_layer_ble=false + +user@ubuntu:~/connectedhomeip$ : rm -rf /tmp/chip_* +user@ubuntu:~/connectedhomeip$ : ./out/ota-provider-app/chip-ota-provider-app -f matter.ota +``` + +The OTA Provider should first be provisioned with chip-tool by assigning it the +node id 1, and then granted the ACL entries : + +``` +user@ubuntu:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing onnetwork 1 20202021 +user@ubuntu:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": null, "targets": null}]' 1 0 +``` + +The second step is to provision the device with the node id 2 using ble-wifi or +ble-thread commissioning. For example : + +``` +user@ubuntu:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing ble-wifi 2 WIFI_SSID WIFI_PASSWORD 20202021 3840 +``` + +Once commissioned, the OTA process can be initiated with the +"announce-ota-provider" command using chip-tool (the given numbers refer +respectively to [ProviderNodeId][vendorid] [AnnouncementReason][endpoint] +[node-id][endpoint-id]) : + +``` +user@ubuntu:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool otasoftwareupdaterequestor announce-otaprovider 1 0 0 0 2 0 +``` + +When the full update image is downloaded and stored, the bootloader will be +notified and the device will reboot with the update image. diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index 5884f22d38fe4b..c81a268849fa1e 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -217,6 +217,12 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "CHIP_DEVICE_LAYER_TARGET=${nxp_device_layer}", "CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE=${chip_enable_ble}", ] + } else if (chip_device_platform == "nxp_zephyr") { + device_layer_target_define = "NXP_ZEPHYR" + defines += [ + "CHIP_DEVICE_LAYER_TARGET_NXP_ZEPHYR=1", + "CHIP_DEVICE_LAYER_TARGET=nxp/zephyr", + ] } else if (chip_device_platform == "telink") { device_layer_target_define = "TELINK" defines += [ "CHIP_DEVICE_LAYER_TARGET=telink" ] @@ -320,6 +326,7 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "QPG", "K32W", "NXP", + "NXP_ZEPHYR", "TELINK", "MBED", "BL602", @@ -532,6 +539,8 @@ if (chip_device_platform != "none") { _platform_target = "qpg" } else if (chip_device_platform == "nxp") { _platform_target = "nxp" + } else if (chip_device_platform == "nxp_zephyr") { + _platform_target = "nxp/zephyr:nxp_zephyr" } else if (chip_device_platform == "telink") { _platform_target = "telink" } else if (chip_device_platform == "mbed") { diff --git a/src/platform/device.gni b/src/platform/device.gni index 7286805620e0c3..6a4c5a05535513 100644 --- a/src/platform/device.gni +++ b/src/platform/device.gni @@ -158,6 +158,8 @@ if (chip_device_platform == "cc13x2_26x2") { import("//build_overrides/nxp_sdk.gni") import("${nxp_sdk_build_root}/nxp_sdk.gni") _chip_device_layer = "nxp/${nxp_platform}" +} else if (chip_device_platform == "nxp_zephyr") { + _chip_device_layer = "nxp/zephyr" } else if (chip_device_platform == "telink") { _chip_device_layer = "telink" } else if (chip_device_platform == "mbed") { @@ -254,14 +256,15 @@ assert( chip_device_platform == "tizen" || chip_device_platform == "nrfconnect" || chip_device_platform == "nxp" || chip_device_platform == "k32w0" || chip_device_platform == "k32w1" || - chip_device_platform == "qpg" || chip_device_platform == "telink" || - chip_device_platform == "mbed" || chip_device_platform == "psoc6" || - chip_device_platform == "android" || chip_device_platform == "ameba" || - chip_device_platform == "cyw30739" || chip_device_platform == "webos" || - chip_device_platform == "mw320" || chip_device_platform == "zephyr" || - chip_device_platform == "beken" || chip_device_platform == "bl602" || - chip_device_platform == "bl702" || chip_device_platform == "bl702l" || - chip_device_platform == "mt793x" || chip_device_platform == "SiWx917" || + chip_device_platform == "nxp_zephyr" || chip_device_platform == "qpg" || + chip_device_platform == "telink" || chip_device_platform == "mbed" || + chip_device_platform == "psoc6" || chip_device_platform == "android" || + chip_device_platform == "ameba" || chip_device_platform == "cyw30739" || + chip_device_platform == "webos" || chip_device_platform == "mw320" || + chip_device_platform == "zephyr" || chip_device_platform == "beken" || + chip_device_platform == "bl602" || chip_device_platform == "bl702" || + chip_device_platform == "bl702l" || chip_device_platform == "mt793x" || + chip_device_platform == "SiWx917" || chip_device_platform == "openiotsdk" || chip_device_platform == "asr" || chip_device_platform == "stm32", "Please select a valid value for chip_device_platform") diff --git a/src/platform/nxp/common/factory_data/FactoryDataProvider.cpp b/src/platform/nxp/common/factory_data/FactoryDataProvider.cpp index 5991a81d703ac8..bdaaaae1d120b8 100644 --- a/src/platform/nxp/common/factory_data/FactoryDataProvider.cpp +++ b/src/platform/nxp/common/factory_data/FactoryDataProvider.cpp @@ -258,9 +258,9 @@ CHIP_ERROR FactoryDataProvider::GetManufacturingDate(uint16_t & year, uint8_t & if (length == 10 && isdigit(date[0]) && isdigit(date[1]) && isdigit(date[2]) && isdigit(date[3]) && date[4] == '-' && isdigit(date[5]) && isdigit(date[6]) && date[7] == '-' && isdigit(date[8]) && isdigit(date[9])) { - year = 1000 * (date[0] - '0') + 100 * (date[1] - '0') + 10 * (date[2] - '0') + date[3] - '0'; - month = 10 * (date[5] - '0') + date[6] - '0'; - day = 10 * (date[8] - '0') + date[9] - '0'; + year = (uint16_t) (1000 * (date[0] - '0') + 100 * (date[1] - '0') + 10 * (date[2] - '0') + date[3] - '0'); + month = (uint8_t) (10 * (date[5] - '0') + date[6] - '0'); + day = (uint8_t) (10 * (date[8] - '0') + date[9] - '0'); } else { diff --git a/src/platform/nxp/zephyr/BLEManagerImpl.h b/src/platform/nxp/zephyr/BLEManagerImpl.h new file mode 100644 index 00000000000000..bb3e7405153b07 --- /dev/null +++ b/src/platform/nxp/zephyr/BLEManagerImpl.h @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides an implementation of the BLEManager singleton object + * for the Zephyr platforms. + */ + +#pragma once + +#include diff --git a/src/platform/nxp/zephyr/BUILD.gn b/src/platform/nxp/zephyr/BUILD.gn new file mode 100644 index 00000000000000..1c370750d911a6 --- /dev/null +++ b/src/platform/nxp/zephyr/BUILD.gn @@ -0,0 +1,111 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") + +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/src/platform/nxp/zephyr/args.gni") + +assert(chip_device_platform == "nxp_zephyr") + +static_library("nxp_zephyr") { + defines = [] + sources = [ + "../../SingletonConfigurationManager.cpp", + "../../Zephyr/BLEAdvertisingArbiter.cpp", + "../../Zephyr/BLEAdvertisingArbiter.h", + "../../Zephyr/BLEManagerImpl.cpp", + "../../Zephyr/ConfigurationManagerImpl.cpp", + "../../Zephyr/DiagnosticDataProviderImpl.cpp", + "../../Zephyr/DiagnosticDataProviderImpl.h", + "../../Zephyr/KeyValueStoreManagerImpl.cpp", + "../../Zephyr/Logging.cpp", + "../../Zephyr/PlatformManagerImpl.cpp", + "../../Zephyr/SysHeapMalloc.h", + "../../Zephyr/SystemTimeSupport.cpp", + "../../Zephyr/ZephyrConfig.cpp", + "../../Zephyr/ZephyrConfig.h", + "../common/CHIPDeviceNXPPlatformDefaultConfig.h", + "../common/CHIPNXPPlatformDefaultConfig.h", + "BLEManagerImpl.h", + "BlePlatformConfig.h", + "CHIPDevicePlatformConfig.h", + "CHIPDevicePlatformEvent.h", + "CHIPPlatformConfig.h", + "ConfigurationManagerImpl.h", + "ConnectivityManagerImpl.cpp", + "ConnectivityManagerImpl.h", + "DiagnosticDataProviderImplNxp.cpp", + "DiagnosticDataProviderImplNxp.h", + "InetPlatformConfig.h", + "KeyValueStoreManagerImpl.h", + "PlatformManagerImpl.h", + "SystemPlatformConfig.h", + ] + + public = [ + "${chip_root}/src/credentials/CHIPCert.h", + "${chip_root}/src/credentials/CertificationDeclaration.h", + "${chip_root}/src/credentials/DeviceAttestationCredsProvider.h", + "${chip_root}/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h", + "${chip_root}/src/credentials/attestation_verifier/DeviceAttestationVerifier.h", + "${chip_root}/src/credentials/examples/DeviceAttestationCredsExample.h", + "${chip_root}/src/credentials/examples/ExampleDACs.h", + "${chip_root}/src/credentials/examples/ExamplePAI.h", + ] + + public_deps = [ "${chip_root}/src/platform:platform_base" ] + deps = [ "${chip_root}/src/platform/logging:headers" ] + + if (chip_enable_factory_data) { + sources += [ + "../common/factory_data/FactoryDataProvider.cpp", + "../common/factory_data/FactoryDataProvider.h", + "FactoryDataProviderImpl.cpp", + "FactoryDataProviderImpl.h", + ] + defines += [ "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/zephyr/FactoryDataProviderImpl.h\"" ] + } else { + sources += [ + "DeviceInstanceInfoProviderImpl.cpp", + "DeviceInstanceInfoProviderImpl.h", + ] + } + + if (chip_enable_wifi) { + sources += [ + "../../Zephyr/InetUtils.cpp", + "../../Zephyr/InetUtils.h", + "wifi/ConnectivityManagerImplWiFi.cpp", + "wifi/ConnectivityManagerImplWiFi.h", + "wifi/NxpWifiDriver.cpp", + "wifi/NxpWifiDriver.h", + "wifi/WiFiManager.cpp", + "wifi/WiFiManager.h", + ] + } + + if (chip_enable_ota_requestor) { + sources += [ + "ota/OTAImageProcessorImpl.cpp", + "ota/OTAImageProcessorImpl.h", + ] + } + + if (chip_malloc_sys_heap) { + sources += [ "../../Zephyr/SysHeapMalloc.cpp" ] + } + + cflags = [ "-Wconversion" ] +} diff --git a/src/platform/nxp/zephyr/BlePlatformConfig.h b/src/platform/nxp/zephyr/BlePlatformConfig.h new file mode 100644 index 00000000000000..35c31253622817 --- /dev/null +++ b/src/platform/nxp/zephyr/BlePlatformConfig.h @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific configuration overrides for the CHIP BLE + * Layer on Zephyr platform. + * + */ + +#pragma once + +#include diff --git a/src/platform/nxp/zephyr/CHIPDevicePlatformConfig.h b/src/platform/nxp/zephyr/CHIPDevicePlatformConfig.h new file mode 100644 index 00000000000000..f8c72dd043902f --- /dev/null +++ b/src/platform/nxp/zephyr/CHIPDevicePlatformConfig.h @@ -0,0 +1,220 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific configuration overrides for the chip Device Layer + * on Zephyr platform. + */ + +#pragma once + +#include "autoconf.h" + +// ==================== Platform Adaptations ==================== + +#ifndef CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER CONFIG_CHIP_DEVICE_SERIAL_NUMBER +#endif + +#ifndef CHIP_DEVICE_CONFIG_TEST_MANUFACTURING_DATE +#define CHIP_DEVICE_CONFIG_TEST_MANUFACTURING_DATE CONFIG_CHIP_DEVICE_MANUFACTURING_DATE +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION CONFIG_CHIP_DEVICE_HARDWARE_VERSION +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE CONFIG_CHIP_DEVICE_SPAKE2_PASSCODE +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR CONFIG_CHIP_DEVICE_DISCRIMINATOR +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING CONFIG_CHIP_DEVICE_HARDWARE_VERSION_STRING +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT +#define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT CONFIG_CHIP_DEVICE_SPAKE2_IT +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT +#define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT CONFIG_CHIP_DEVICE_SPAKE2_SALT +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER +#define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER CONFIG_CHIP_DEVICE_SPAKE2_TEST_VERIFIER +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID CONFIG_CHIP_DEVICE_VENDOR_ID +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID CONFIG_CHIP_DEVICE_PRODUCT_ID +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME CONFIG_CHIP_DEVICE_VENDOR_NAME +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME CONFIG_CHIP_DEVICE_PRODUCT_NAME +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION CONFIG_CHIP_DEVICE_SOFTWARE_VERSION +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING CONFIG_CHIP_DEVICE_SOFTWARE_VERSION_STRING +#endif + +#ifdef CONFIG_NET_L2_OPENTHREAD +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD CONFIG_NET_L2_OPENTHREAD +#else +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD 0 +#endif + +#ifdef CONFIG_WIFI_NXP +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI CONFIG_WIFI_NXP +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 1 +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0 +#else +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI 0 +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 0 +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0 +#endif + +#ifdef CONFIG_BT +#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE CONFIG_BT +#else +#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 0 +#endif + +// ========== Platform-specific Configuration ========= + +// These are configuration options that are unique to Zephyr platforms. +// These can be overridden by the application as needed. + +#ifndef CHIP_DEVICE_CONFIG_SETTINGS_KEY +/// Key for all Matter persistent data stored using the Zephyr Settings API +#define CHIP_DEVICE_CONFIG_SETTINGS_KEY "mt" +#endif // CHIP_DEVICE_CONFIG_SETTINGS_KEY + +#ifndef CHIP_DEVICE_CONFIG_OTA_REQUESTOR_REBOOT_DELAY_MS +/// Delay between completing a firmware update download and reboot to apply the update +#define CHIP_DEVICE_CONFIG_OTA_REQUESTOR_REBOOT_DELAY_MS 1000 +#endif // CHIP_DEVICE_CONFIG_OTA_REQUESTOR_REBOOT_DELAY_MS + +#ifndef CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS +/// Time to sleep after running server shutdown actions to let lower layers complete the actions. +/// This may include transmitting packets created by the actions. +#define CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS 500 +#endif // CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS + +#ifndef CHIP_DEVICE_CONFIG_HEAP_STATISTICS_MALLINFO +#if !defined(CONFIG_CHIP_MALLOC_SYS_HEAP) && defined(CONFIG_NEWLIB_LIBC) +/// Use mallinfo() to obtain the heap usage statistics exposed by SoftwareDiagnostics cluster attributes. +#define CHIP_DEVICE_CONFIG_HEAP_STATISTICS_MALLINFO 1 +#else +#define CHIP_DEVICE_CONFIG_HEAP_STATISTICS_MALLINFO 0 +#endif // !defined(CONFIG_CHIP_MALLOC_SYS_HEAP) && defined(CONFIG_NEWLIB_LIBC) +#endif // CHIP_DEVICE_CONFIG_HEAP_STATISTICS_MALLINFO + +#ifndef CHIP_DEVICE_BLE_ADVERTISING_PRIORITY +/// Priority of the Matter BLE advertising when there are multiple application +/// components that compete for the BLE advertising. +#define CHIP_DEVICE_BLE_ADVERTISING_PRIORITY 0 +#endif // CHIP_DEVICE_BLE_ADVERTISING_PRIORITY + +// ========== Platform-specific Configuration Overrides ========= + +#ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY +#define CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY (K_PRIO_PREEMPT(1)) +#endif // CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY + +#ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE +#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE 8192 +#endif // CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE + +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY 0 +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY 0 +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY_FULL 0 + +#define CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART 0 + +#ifndef CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART +#define CHIP_DEVICE_CONFIG_ENABLE_PAIRING_AUTOSTART 0 +#else +#define CHIP_DEVICE_CONFIG_ENABLE_PAIRING_AUTOSTART CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART +#endif // CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART + +#ifdef CONFIG_CHIP_ENABLE_DNSSD_SRP +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT 1 +#ifdef CONFIG_CHIP_ENABLE_DNS_CLIENT +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT 1 +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_COMMISSIONABLE_DISCOVERY 1 +#endif // CONFIG_CHIP_ENABLE_DNS_CLIENT +#endif // CONFIG_CHIP_ENABLE_DNSSD_SRP + +#if defined(CONFIG_CHIP_ENABLE_ICD_SUPPORT) && defined(CONFIG_CHIP_THREAD_SSED) +#define CHIP_DEVICE_CONFIG_THREAD_SSED CONFIG_CHIP_THREAD_SSED +#else +#define CHIP_DEVICE_CONFIG_THREAD_SSED 0 +#endif // defined(CONFIG_CHIP_ENABLE_ICD_SUPPORT) && defined(CONFIG_CHIP_THREAD_SSED) + +#ifndef CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL +#ifdef CONFIG_CHIP_ICD_SLOW_POLL_INTERVAL +#define CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL chip::System::Clock::Milliseconds32(CONFIG_CHIP_ICD_SLOW_POLL_INTERVAL) +#endif // CONFIG_CHIP_ICD_SLOW_POLL_INTERVAL +#endif // CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL + +#ifndef CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL +#ifdef CONFIG_CHIP_ICD_FAST_POLLING_INTERVAL +#define CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL chip::System::Clock::Milliseconds32(CONFIG_CHIP_ICD_FAST_POLLING_INTERVAL) +#endif // CONFIG_CHIP_ICD_FAST_POLLING_INTERVAL +#endif // CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL + +#ifdef CONFIG_CHIP_COMMISSIONABLE_DEVICE_TYPE +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE 1 +#endif // CONFIG_CHIP_COMMISSIONABLE_DEVICE_TYPE + +#ifdef CONFIG_CHIP_DEVICE_TYPE +#define CHIP_DEVICE_CONFIG_DEVICE_TYPE CONFIG_CHIP_DEVICE_TYPE +#endif // CONFIG_CHIP_DEVICE_TYPE + +#ifdef CONFIG_CHIP_EXTENDED_DISCOVERY +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 +#endif // CONFIG_CHIP_EXTENDED_DISCOVERY + +#ifndef CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID_LENGTH +#ifdef CONFIG_CHIP_FACTORY_DATA +// UID will be copied from the externally programmed factory data, so we don't know the actual length and we need to assume some max +// boundary. +#define CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID_LENGTH CONFIG_CHIP_FACTORY_DATA_ROTATING_DEVICE_UID_MAX_LEN +#else +// UID will be copied from hex encoded Kconfig option, so we may calculate its length in bytes by subtracting null terminator and +// dividing size by 2. +#define CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID_LENGTH ((sizeof(CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID) - 1) / 2) +#endif // CONFIG_CHIP_FACTORY_DATA +#endif // CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID_LENGTH + +#include diff --git a/src/platform/nxp/zephyr/CHIPDevicePlatformEvent.h b/src/platform/nxp/zephyr/CHIPDevicePlatformEvent.h new file mode 100644 index 00000000000000..3b38a1d75ccf58 --- /dev/null +++ b/src/platform/nxp/zephyr/CHIPDevicePlatformEvent.h @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Defines platform-specific event types and data for the chip + * Device Layer on Zephyr platforms. + */ + +#pragma once + +#include diff --git a/src/platform/nxp/zephyr/CHIPPlatformConfig.h b/src/platform/nxp/zephyr/CHIPPlatformConfig.h new file mode 100644 index 00000000000000..cd9873051e5fed --- /dev/null +++ b/src/platform/nxp/zephyr/CHIPPlatformConfig.h @@ -0,0 +1,141 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific configuration overrides for CHIP on + * Zephyr platform. + */ + +#pragma once + +#ifdef CONFIG_CHIP_CRYPTO_PSA +#include +#endif + +// ==================== General Platform Adaptations ==================== + +#define CHIP_CONFIG_ABORT() abort() + +#define CHIP_CONFIG_PERSISTED_STORAGE_KEY_TYPE const char * +#define CHIP_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH 2 + +#define CHIP_CONFIG_LIFETIIME_PERSISTED_COUNTER_KEY "rc" + +// ==================== Security Adaptations ==================== + +#ifdef CONFIG_CHIP_CRYPTO_PSA +#define CHIP_CONFIG_SHA256_CONTEXT_SIZE sizeof(psa_hash_operation_t) +#define CHIP_CONFIG_SHA256_CONTEXT_ALIGN psa_hash_operation_t +#elif defined(CONFIG_CC3XX_BACKEND) +// Size of the statically allocated context for SHA256 operations in CryptoPAL +// determined empirically. +#define CHIP_CONFIG_SHA256_CONTEXT_SIZE 244 +#else +#define CHIP_CONFIG_SHA256_CONTEXT_SIZE 208 +#endif + +// ==================== General Configuration Overrides ==================== + +#ifndef CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS +#define CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS 8 +#endif // CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS + +#ifndef CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS +#define CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS 8 +#endif // CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS + +#ifndef CHIP_LOG_FILTERING +#define CHIP_LOG_FILTERING 0 +#endif // CHIP_LOG_FILTERING + +#ifndef CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS +#define CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS 1 +#endif // CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS + +#ifndef CHIP_CONFIG_MAX_FABRICS +#define CHIP_CONFIG_MAX_FABRICS 5 +#endif + +#ifdef CONFIG_CHIP_LOG_SIZE_OPTIMIZATION +// Disable some of the too detailed log modules to save flash +#define CHIP_CONFIG_LOG_MODULE_ExchangeManager_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_Crypto_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_Crypto_PROGRESS 0 +#define CHIP_CONFIG_LOG_MODULE_BDX_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_BDX_PROGRESS 0 +#define CHIP_CONFIG_LOG_MODULE_EventLogging_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_EventLogging_PROGRESS 0 +#define CHIP_CONFIG_LOG_MODULE_SetupPayload_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_SetupPayload_PROGRESS 0 +#define CHIP_CONFIG_LOG_MODULE_CASESessionManager_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_CASESessionManager_PROGRESS 0 +#define CHIP_CONFIG_LOG_MODULE_DataManagement_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_FabricProvisioning_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_chipSystemLayer_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_chipSystemLayer_PROGRESS 0 +#define CHIP_CONFIG_LOG_MODULE_Zcl_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_SecureChannel_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_Ble_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_AppServer_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_Support_DETAIL 0 +#define CHIP_CONFIG_LOG_MODULE_Support_PROGRESS 0 +#endif + +// Set MRP retry intervals for Thread and Wi-Fi to test-proven values. +#ifndef CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL +#if CHIP_ENABLE_OPENTHREAD +#define CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL (800_ms32) +#else +#define CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL (2000_ms32) +#endif // CHIP_ENABLE_OPENTHREAD +#endif // CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL + +#ifndef CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL +#if CHIP_ENABLE_OPENTHREAD +#define CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL (800_ms32) +#else +#define CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL (2000_ms32) +#endif // CHIP_ENABLE_OPENTHREAD +#endif // CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL + +#ifndef CHIP_CONFIG_ICD_IDLE_MODE_DURATION_SEC +#ifdef CONFIG_CHIP_ICD_IDLE_MODE_INTERVAL +#define CHIP_CONFIG_ICD_IDLE_MODE_DURATION_SEC CONFIG_CHIP_ICD_IDLE_MODE_INTERVAL +#endif // CONFIG_CHIP_ICD_IDLE_MODE_INTERVAL +#endif // CHIP_CONFIG_ICD_IDLE_MODE_DURATION_SEC + +#ifndef CHIP_CONFIG_ICD_ACTIVE_MODE_DURATION_MS +#ifdef CONFIG_CHIP_ICD_ACTIVE_MODE_INTERVAL +#define CHIP_CONFIG_ICD_ACTIVE_MODE_DURATION_MS CONFIG_CHIP_ICD_ACTIVE_MODE_INTERVAL +#endif // CONFIG_CHIP_ICD_ACTIVE_MODE_INTERVAL +#endif // CHIP_CONFIG_ICD_ACTIVE_MODE_DURATION_MS + +#ifndef CHIP_CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS +#ifdef CONFIG_CHIP_ICD_ACTIVE_MODE_THRESHOLD +#define CHIP_CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS CONFIG_CHIP_ICD_ACTIVE_MODE_THRESHOLD +#endif // CONFIG_CHIP_ICD_ACTIVE_MODE_THRESHOLD +#endif // CHIP_CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS + +#ifndef CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC +#ifdef CONFIG_CHIP_ICD_CLIENTS_PER_FABRIC +#define CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC CONFIG_CHIP_ICD_CLIENTS_PER_FABRIC +#endif // CONFIG_CHIP_ICD_CLIENTS_PER_FABRIC +#endif // CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC + +#include +#include diff --git a/src/platform/nxp/zephyr/ConfigurationManagerImpl.h b/src/platform/nxp/zephyr/ConfigurationManagerImpl.h new file mode 100644 index 00000000000000..846671b64b1683 --- /dev/null +++ b/src/platform/nxp/zephyr/ConfigurationManagerImpl.h @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides an implementation of the ConfigurationManager object + * for Zephyr platforms. + */ + +#pragma once + +#include diff --git a/src/platform/nxp/zephyr/ConnectivityManagerImpl.cpp b/src/platform/nxp/zephyr/ConnectivityManagerImpl.cpp new file mode 100644 index 00000000000000..888e5748ad6b10 --- /dev/null +++ b/src/platform/nxp/zephyr/ConnectivityManagerImpl.cpp @@ -0,0 +1,69 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include +#include + +#include + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +#include +#endif + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#include +#endif + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#include +#endif + +using namespace ::chip; +using namespace ::chip::TLV; +using namespace ::chip::DeviceLayer::Internal; + +namespace chip { +namespace DeviceLayer { + +ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; + +CHIP_ERROR ConnectivityManagerImpl::_Init() +{ +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + GenericConnectivityManagerImpl_Thread::_Init(); +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI + ReturnErrorOnFailure(InitWiFi()); +#endif + return CHIP_NO_ERROR; +} + +void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) +{ + // Forward the event to the generic base classes as needed. +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + GenericConnectivityManagerImpl_Thread::_OnPlatformEvent(event); +#endif +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/ConnectivityManagerImpl.h b/src/platform/nxp/zephyr/ConnectivityManagerImpl.h new file mode 100644 index 00000000000000..6d7a717886a7eb --- /dev/null +++ b/src/platform/nxp/zephyr/ConnectivityManagerImpl.h @@ -0,0 +1,121 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +#include +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#include +#else +#include +#endif + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#include +#else +#include +#endif + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI +#include "wifi/ConnectivityManagerImplWiFi.h" +#else +#include +#endif + +#include + +namespace chip { +namespace Inet { +class IPAddress; +} // namespace Inet +} // namespace chip + +namespace chip { +namespace DeviceLayer { + +/** + * Concrete implementation of the ConnectivityManager singleton object for Zephyr platforms. + */ +class ConnectivityManagerImpl final : public ConnectivityManager, + public Internal::GenericConnectivityManagerImpl, + public Internal::GenericConnectivityManagerImpl_UDP, +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + public Internal::GenericConnectivityManagerImpl_TCP, +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + public Internal::GenericConnectivityManagerImpl_BLE, +#else + public Internal::GenericConnectivityManagerImpl_NoBLE, +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + public Internal::GenericConnectivityManagerImpl_Thread, +#else + public Internal::GenericConnectivityManagerImpl_NoThread, +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI + public ConnectivityManagerImplWiFi +#else + public Internal::GenericConnectivityManagerImpl_NoWiFi +#endif +{ + // Allow the ConnectivityManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class ConnectivityManager; + +private: + // ===== Members that implement the ConnectivityManager abstract interface. + + CHIP_ERROR _Init(void); + void _OnPlatformEvent(const ChipDeviceEvent * event); + + // ===== Members for internal use by the following friends. + + friend ConnectivityManager & ConnectivityMgr(void); + friend ConnectivityManagerImpl & ConnectivityMgrImpl(void); + + static ConnectivityManagerImpl sInstance; +}; + +/** + * Returns the public interface of the ConnectivityManager singleton object. + * + * chip applications should use this to access features of the ConnectivityManager object + * that are common to all platforms. + */ +inline ConnectivityManager & ConnectivityMgr(void) +{ + return ConnectivityManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the ConnectivityManager singleton object. + * + * chip applications can use this to gain access to features of the ConnectivityManager + * that are specific to the NXP platform. + */ +inline ConnectivityManagerImpl & ConnectivityMgrImpl(void) +{ + return ConnectivityManagerImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/DeviceInstanceInfoProviderImpl.cpp b/src/platform/nxp/zephyr/DeviceInstanceInfoProviderImpl.cpp new file mode 100644 index 00000000000000..92029ebd617386 --- /dev/null +++ b/src/platform/nxp/zephyr/DeviceInstanceInfoProviderImpl.cpp @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DeviceInstanceInfoProviderImpl.h" +#include + +namespace chip { +namespace DeviceLayer { + +CHIP_ERROR DeviceInstanceInfoProviderImpl::GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) +{ +#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID) + static_assert(ConfigurationManager::kRotatingDeviceIDUniqueIDLength >= ConfigurationManager::kMinRotatingDeviceIDUniqueIDLength, + "Length of unique ID for rotating device ID is smaller than minimum."); + + ReturnErrorCodeIf(ConfigurationManager::kRotatingDeviceIDUniqueIDLength > uniqueIdSpan.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + + size_t bytesLen = chip::Encoding::HexToBytes(CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID, + ConfigurationManager::kRotatingDeviceIDUniqueIDLength * 2, uniqueIdSpan.data(), + uniqueIdSpan.size()); + + ReturnErrorCodeIf(bytesLen != ConfigurationManager::kRotatingDeviceIDUniqueIDLength, CHIP_ERROR_INVALID_STRING_LENGTH); + uniqueIdSpan.reduce_size(bytesLen); + + return CHIP_NO_ERROR; +#endif // CHIP_ENABLE_ROTATING_DEVICE_ID + + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/DeviceInstanceInfoProviderImpl.h b/src/platform/nxp/zephyr/DeviceInstanceInfoProviderImpl.h new file mode 100644 index 00000000000000..31cc98bfaa2a84 --- /dev/null +++ b/src/platform/nxp/zephyr/DeviceInstanceInfoProviderImpl.h @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace DeviceLayer { + +class DeviceInstanceInfoProviderImpl : public Internal::GenericDeviceInstanceInfoProvider +{ +public: + CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override; + + DeviceInstanceInfoProviderImpl(ConfigurationManagerImpl & configManager) : + Internal::GenericDeviceInstanceInfoProvider(configManager) + {} +}; + +inline DeviceInstanceInfoProviderImpl & DeviceInstanceInfoProviderMgrImpl() +{ + static DeviceInstanceInfoProviderImpl sInstance(ConfigurationManagerImpl::GetDefaultInstance()); + return sInstance; +} +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/DiagnosticDataProviderImplNxp.cpp b/src/platform/nxp/zephyr/DiagnosticDataProviderImplNxp.cpp new file mode 100644 index 00000000000000..b7f0e2523610a5 --- /dev/null +++ b/src/platform/nxp/zephyr/DiagnosticDataProviderImplNxp.cpp @@ -0,0 +1,157 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides an implementation of the DiagnosticDataProvider object + * for NXP Zephyr platform. + */ + +#include "DiagnosticDataProviderImplNxp.h" + +#ifdef CONFIG_WIFI_NXP +#include +#endif + +namespace chip { +namespace DeviceLayer { + +DiagnosticDataProvider & GetDiagnosticDataProviderImpl() +{ + return DiagnosticDataProviderImplNxp::GetDefaultInstance(); +} + +DiagnosticDataProviderImplNxp & DiagnosticDataProviderImplNxp::GetDefaultInstance() +{ + static DiagnosticDataProviderImplNxp sInstance; + return sInstance; +} + +#ifdef CONFIG_WIFI_NXP +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiBssId(MutableByteSpan & value) +{ + WiFiManager::WiFiInfo info; + ReturnErrorOnFailure(WiFiManager::Instance().GetWiFiInfo(info)); + ReturnErrorCodeIf(sizeof(info.mBssId) >= value.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + + memcpy(value.data(), info.mBssId, sizeof(info.mBssId)); + value.reduce_size(sizeof(info.mBssId)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR +DiagnosticDataProviderImplNxp::GetWiFiSecurityType(app::Clusters::WiFiNetworkDiagnostics::SecurityTypeEnum & securityType) +{ + using app::Clusters::WiFiNetworkDiagnostics::SecurityTypeEnum; + + WiFiManager::WiFiInfo info; + CHIP_ERROR err = WiFiManager::Instance().GetWiFiInfo(info); + securityType = info.mSecurityType; + return err; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiVersion(app::Clusters::WiFiNetworkDiagnostics::WiFiVersionEnum & wiFiVersion) +{ + WiFiManager::WiFiInfo info; + CHIP_ERROR err = WiFiManager::Instance().GetWiFiInfo(info); + wiFiVersion = info.mWiFiVersion; + return err; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiChannelNumber(uint16_t & channelNumber) +{ + WiFiManager::WiFiInfo info; + CHIP_ERROR err = WiFiManager::Instance().GetWiFiInfo(info); + channelNumber = info.mChannel; + return err; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiRssi(int8_t & rssi) +{ + WiFiManager::WiFiInfo info; + CHIP_ERROR err = WiFiManager::Instance().GetWiFiInfo(info); + rssi = info.mRssi; + return err; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiBeaconLostCount(uint32_t & beaconLostCount) +{ + WiFiManager::NetworkStatistics stats; + CHIP_ERROR err = WiFiManager::Instance().GetNetworkStatistics(stats); + beaconLostCount = stats.mBeaconsLostCount; + return err; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiBeaconRxCount(uint32_t & beaconRxCount) +{ + WiFiManager::NetworkStatistics stats; + CHIP_ERROR err = WiFiManager::Instance().GetNetworkStatistics(stats); + beaconRxCount = stats.mBeaconsSuccessCount; + return err; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiPacketMulticastRxCount(uint32_t & packetMulticastRxCount) +{ + WiFiManager::NetworkStatistics stats; + CHIP_ERROR err = WiFiManager::Instance().GetNetworkStatistics(stats); + packetMulticastRxCount = stats.mPacketMulticastRxCount; + return err; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiPacketMulticastTxCount(uint32_t & packetMulticastTxCount) +{ + WiFiManager::NetworkStatistics stats; + CHIP_ERROR err = WiFiManager::Instance().GetNetworkStatistics(stats); + packetMulticastTxCount = stats.mPacketMulticastTxCount; + return err; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiPacketUnicastRxCount(uint32_t & packetUnicastRxCount) +{ + WiFiManager::NetworkStatistics stats; + CHIP_ERROR err = WiFiManager::Instance().GetNetworkStatistics(stats); + packetUnicastRxCount = stats.mPacketUnicastRxCount; + return err; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiPacketUnicastTxCount(uint32_t & packetUnicastTxCount) +{ + WiFiManager::NetworkStatistics stats; + CHIP_ERROR err = WiFiManager::Instance().GetNetworkStatistics(stats); + packetUnicastTxCount = stats.mPacketUnicastTxCount; + return err; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiCurrentMaxRate(uint64_t & currentMaxRate) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::GetWiFiOverrunCount(uint64_t & overrunCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR DiagnosticDataProviderImplNxp::ResetWiFiNetworkDiagnosticsCounts() +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} +#endif + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/DiagnosticDataProviderImplNxp.h b/src/platform/nxp/zephyr/DiagnosticDataProviderImplNxp.h new file mode 100644 index 00000000000000..cac2fa240ffa18 --- /dev/null +++ b/src/platform/nxp/zephyr/DiagnosticDataProviderImplNxp.h @@ -0,0 +1,60 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides an implementation of the DiagnosticDataProvider object + * for NXP Zephyr platform. + */ + +#pragma once + +#include + +namespace chip { +namespace DeviceLayer { + +class DiagnosticDataProviderImplNxp : public DiagnosticDataProviderImpl +{ +public: +#ifdef CONFIG_WIFI_NXP + CHIP_ERROR GetWiFiBssId(MutableByteSpan & value) override; + CHIP_ERROR GetWiFiSecurityType(app::Clusters::WiFiNetworkDiagnostics::SecurityTypeEnum & securityType) override; + CHIP_ERROR GetWiFiVersion(app::Clusters::WiFiNetworkDiagnostics::WiFiVersionEnum & wiFiVersion) override; + CHIP_ERROR GetWiFiChannelNumber(uint16_t & channelNumber) override; + CHIP_ERROR GetWiFiRssi(int8_t & rssi) override; + CHIP_ERROR GetWiFiBeaconLostCount(uint32_t & beaconLostCount) override; + CHIP_ERROR GetWiFiBeaconRxCount(uint32_t & beaconRxCount) override; + CHIP_ERROR GetWiFiPacketMulticastRxCount(uint32_t & packetMulticastRxCount) override; + CHIP_ERROR GetWiFiPacketMulticastTxCount(uint32_t & packetMulticastTxCount) override; + CHIP_ERROR GetWiFiPacketUnicastRxCount(uint32_t & packetUnicastRxCount) override; + CHIP_ERROR GetWiFiPacketUnicastTxCount(uint32_t & packetUnicastTxCount) override; + CHIP_ERROR GetWiFiCurrentMaxRate(uint64_t & currentMaxRate) override; + CHIP_ERROR GetWiFiOverrunCount(uint64_t & overrunCount) override; + CHIP_ERROR ResetWiFiNetworkDiagnosticsCounts() override; +#endif + + static DiagnosticDataProviderImplNxp & GetDefaultInstance(); + +private: + DiagnosticDataProviderImplNxp() = default; +}; + +DiagnosticDataProvider & GetDiagnosticDataProviderImpl(); + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/FactoryDataProviderImpl.cpp b/src/platform/nxp/zephyr/FactoryDataProviderImpl.cpp new file mode 100644 index 00000000000000..85c6f9d047bd1c --- /dev/null +++ b/src/platform/nxp/zephyr/FactoryDataProviderImpl.cpp @@ -0,0 +1,246 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* -------------------------------------------------------------------------- */ +/* Includes */ +/* -------------------------------------------------------------------------- */ + +#include "FactoryDataProviderImpl.h" + +/* mbedtls */ +#include "mbedtls/aes.h" +#include "mbedtls/sha256.h" + +/* -------------------------------------------------------------------------- */ +/* Private macros */ +/* -------------------------------------------------------------------------- */ + +#define HASH_ID 0xCE47BA5E + +/* -------------------------------------------------------------------------- */ +/* Class implementation */ +/* -------------------------------------------------------------------------- */ + +namespace chip { +namespace DeviceLayer { + +FactoryDataProviderImpl FactoryDataProviderImpl::sInstance; + +CHIP_ERROR FactoryDataProviderImpl::SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, + uint32_t * contentAddr) +{ + CHIP_ERROR err = CHIP_ERROR_NOT_FOUND; + uint8_t type = 0; + uint32_t index = 0; + uint8_t * factoryDataAddress = &mFactoryData.factoryDataBuffer[0]; + uint32_t factoryDataSize = sizeof(mFactoryData.factoryDataBuffer); + uint16_t currentLen = 0; + + while (index < factoryDataSize) + { + /* Read the type */ + memcpy((uint8_t *) &type, factoryDataAddress + index, sizeof(type)); + index += sizeof(type); + + /* Read the len */ + memcpy((uint8_t *) ¤tLen, factoryDataAddress + index, sizeof(currentLen)); + index += sizeof(currentLen); + + /* Check if the type gotten is the expected one */ + if (searchedType == type) + { + /* If pBuf is null it means that we only want to know if the Type has been found */ + if (pBuf != NULL) + { + /* If the buffer given is too small, fill only the available space */ + if (bufLength < currentLen) + { + currentLen = (uint16_t) bufLength; + } + memcpy((uint8_t *) pBuf, factoryDataAddress + index, currentLen); + } + length = (uint16_t) currentLen; + if (contentAddr != NULL) + { + *contentAddr = (uint32_t) factoryDataAddress + index; + } + err = CHIP_NO_ERROR; + break; + } + else if (type == 0) + { + /* No more type available , break the loop */ + break; + } + else + { + /* Jump to next data */ + index += currentLen; + } + } + + return err; +} + +CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign, MutableByteSpan & outSignBuffer) +{ + Crypto::P256ECDSASignature signature; + Crypto::P256Keypair keypair; + + VerifyOrReturnError(IsSpanUsable(outSignBuffer), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsSpanUsable(digestToSign), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(outSignBuffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); + + // In a non-exemplary implementation, the public key is not needed here. It is used here merely because + // Crypto::P256Keypair is only (currently) constructable from raw keys if both private/public keys are present. + Crypto::P256PublicKey dacPublicKey; + uint16_t certificateSize = 0; + uint32_t certificateAddr; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacCertificateId, NULL, 0, certificateSize, &certificateAddr)); + MutableByteSpan dacCertSpan((uint8_t *) certificateAddr, certificateSize); + + /* Extract Public Key of DAC certificate from itself */ + ReturnErrorOnFailure(Crypto::ExtractPubkeyFromX509Cert(dacCertSpan, dacPublicKey)); + + /* Get private key of DAC certificate from reserved section */ + uint16_t keySize = 0; + uint32_t keyAddr; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacPrivateKeyId, NULL, 0, keySize, &keyAddr)); + MutableByteSpan dacPrivateKeySpan((uint8_t *) keyAddr, keySize); + + ReturnErrorOnFailure(LoadKeypairFromRaw(ByteSpan(dacPrivateKeySpan.data(), dacPrivateKeySpan.size()), + ByteSpan(dacPublicKey.Bytes(), dacPublicKey.Length()), keypair)); + + ReturnErrorOnFailure(keypair.ECDSA_sign_msg(digestToSign.data(), digestToSign.size(), signature)); + + return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer); +} + +CHIP_ERROR FactoryDataProviderImpl::LoadKeypairFromRaw(ByteSpan privateKey, ByteSpan publicKey, Crypto::P256Keypair & keypair) +{ + Crypto::P256SerializedKeypair serialized_keypair; + ReturnErrorOnFailure(serialized_keypair.SetLength(privateKey.size() + publicKey.size())); + memcpy(serialized_keypair.Bytes(), publicKey.data(), publicKey.size()); + memcpy(serialized_keypair.Bytes() + publicKey.size(), privateKey.data(), privateKey.size()); + return keypair.Deserialize(serialized_keypair); +} + +CHIP_ERROR FactoryDataProviderImpl::Init(void) +{ + int ret; + CHIP_ERROR res; + const struct device * flashDevice; + uint8_t currentBlock[16]; + off_t factoryDataOffset = FIXED_PARTITION_OFFSET(factory_partition); + + flashDevice = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller)); + + /* Read the factory data header from flash */ + ret = flash_read(flashDevice, factoryDataOffset, (void *) &mFactoryData, sizeof(FactoryDataProviderImpl::Header)); + if (ret != 0) + { + return CHIP_ERROR_READ_FAILED; + } + + /* Check ID is valid */ + if (mFactoryData.header.hashId != HASH_ID) + { + return CHIP_ERROR_NOT_FOUND; + } + + // TODO: add HASH compute + check + + factoryDataOffset += sizeof(FactoryDataProviderImpl::Header); + + /* Load the buffer into RAM by reading each 16 bytes blocks */ + for (int i = 0; (uint32_t) i < (mFactoryData.header.size / 16U); i++) + { + ret = flash_read(flashDevice, factoryDataOffset + i * 16, (void *) ¤tBlock[0], sizeof(currentBlock)); + if (ret != 0) + { + return CHIP_ERROR_READ_FAILED; + } + + if (pAes128Key != NULL) + { + /* Decrypt data if a key has been set */ + res = ReadEncryptedData(&mFactoryData.factoryDataBuffer[i * 16], ¤tBlock[0]); + if (res != CHIP_NO_ERROR) + { + return res; + } + } + else + { + /* No key was set, copy the data as is */ + memcpy(&mFactoryData.factoryDataBuffer[i * 16], ¤tBlock[0], sizeof(currentBlock)); + } + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProviderImpl::SetAes128Key(const uint8_t * keyAes128) +{ + CHIP_ERROR error = CHIP_ERROR_INVALID_ARGUMENT; + if (keyAes128 != nullptr) + { + pAes128Key = keyAes128; + error = CHIP_NO_ERROR; + } + return error; +} + +CHIP_ERROR FactoryDataProviderImpl::SetEncryptionMode(EncryptionMode mode) +{ + CHIP_ERROR error = CHIP_ERROR_INVALID_ARGUMENT; + + /* + * Currently the fwk_factory_data_provider module supports only ecb mode. + * Therefore return an error if encrypt mode is not ecb + */ + if (mode == encrypt_ecb) + { + encryptMode = mode; + error = CHIP_NO_ERROR; + } + return error; +} + +CHIP_ERROR FactoryDataProviderImpl::ReadEncryptedData(uint8_t * dest, uint8_t * source) +{ + mbedtls_aes_context aesCtx; + + mbedtls_aes_init(&aesCtx); + + if (mbedtls_aes_setkey_dec(&aesCtx, pAes128Key, 128U) != 0) + { + return CHIP_ERROR_INTERNAL; + } + + if (mbedtls_aes_crypt_ecb(&aesCtx, MBEDTLS_AES_DECRYPT, source, dest) != 0) + { + return CHIP_ERROR_INTERNAL; + } + + mbedtls_aes_free(&aesCtx); + + return CHIP_NO_ERROR; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/FactoryDataProviderImpl.h b/src/platform/nxp/zephyr/FactoryDataProviderImpl.h new file mode 100644 index 00000000000000..a0424a7e3f4412 --- /dev/null +++ b/src/platform/nxp/zephyr/FactoryDataProviderImpl.h @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +#include +#include + +namespace chip { +namespace DeviceLayer { + +/** + * @brief This class provides Commissionable data and Device Attestation Credentials. + * + * This implementation is using the SDK fwk_factory_data_provider module. + * + * For more information on this module, the interface description available in + * FactoryDataProvider/fwk_factory_data_provider.h inside the SDK can be checked. + */ + +class FactoryDataProviderImpl : public FactoryDataProvider +{ +public: + static FactoryDataProviderImpl sInstance; + + CHIP_ERROR Init(void); + CHIP_ERROR SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, + uint32_t * contentAddr = NULL); + CHIP_ERROR SignWithDacKey(const ByteSpan & digestToSign, MutableByteSpan & outSignBuffer); + + CHIP_ERROR SetAes128Key(const uint8_t * keyAes128); + CHIP_ERROR SetEncryptionMode(EncryptionMode mode); + +private: + struct Header + { + uint32_t hashId; + uint32_t size; + uint8_t hash[4]; + }; + + struct FactoryData + { + struct Header header; + uint8_t factoryDataBuffer[FIXED_PARTITION_SIZE(factory_partition) - sizeof(struct Header)]; + }; + + FactoryData mFactoryData; + const uint8_t * pAes128Key = nullptr; + EncryptionMode encryptMode = encrypt_ecb; + + CHIP_ERROR ReadEncryptedData(uint8_t * dest, uint8_t * source); + CHIP_ERROR LoadKeypairFromRaw(ByteSpan privateKey, ByteSpan publicKey, Crypto::P256Keypair & keypair); +}; + +inline FactoryDataProvider & FactoryDataPrvd() +{ + return FactoryDataProviderImpl::sInstance; +} + +inline FactoryDataProviderImpl & FactoryDataPrvdImpl() +{ + return FactoryDataProviderImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/InetPlatformConfig.h b/src/platform/nxp/zephyr/InetPlatformConfig.h new file mode 100644 index 00000000000000..644cdea6b20423 --- /dev/null +++ b/src/platform/nxp/zephyr/InetPlatformConfig.h @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific configuration overrides for the CHIP Inet + * Layer on Zephyr platform. + * + */ + +#pragma once + +#include diff --git a/src/platform/nxp/zephyr/KeyValueStoreManagerImpl.h b/src/platform/nxp/zephyr/KeyValueStoreManagerImpl.h new file mode 100644 index 00000000000000..c497842975c401 --- /dev/null +++ b/src/platform/nxp/zephyr/KeyValueStoreManagerImpl.h @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for Zephyr. + * + */ + +#pragma once + +#include diff --git a/src/platform/nxp/zephyr/PlatformManagerImpl.h b/src/platform/nxp/zephyr/PlatformManagerImpl.h new file mode 100644 index 00000000000000..75dcb0e7d7481c --- /dev/null +++ b/src/platform/nxp/zephyr/PlatformManagerImpl.h @@ -0,0 +1,25 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides an implementation of the PlatformManager object. + */ + +#pragma once + +#include diff --git a/src/platform/nxp/zephyr/SystemPlatformConfig.h b/src/platform/nxp/zephyr/SystemPlatformConfig.h new file mode 100644 index 00000000000000..24f8c4d229e235 --- /dev/null +++ b/src/platform/nxp/zephyr/SystemPlatformConfig.h @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific configuration overrides for the CHIP System + * Layer on Zephyr platform. + * + */ + +#pragma once + +#include diff --git a/src/platform/nxp/zephyr/args.gni b/src/platform/nxp/zephyr/args.gni new file mode 100644 index 00000000000000..e24f997ccdf64b --- /dev/null +++ b/src/platform/nxp/zephyr/args.gni @@ -0,0 +1,20 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +declare_args() { + chip_malloc_sys_heap = false + + # Enable factory data support + chip_enable_factory_data = false +} diff --git a/src/platform/nxp/zephyr/nxp-zephyr-mbedtls-config.h b/src/platform/nxp/zephyr/nxp-zephyr-mbedtls-config.h new file mode 100644 index 00000000000000..4b9b0e857113d7 --- /dev/null +++ b/src/platform/nxp/zephyr/nxp-zephyr-mbedtls-config.h @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2024 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if CONFIG_CHIP_CRYPTO_PSA +#define MBEDTLS_PSA_CRYPTO_DRIVERS +#endif /* CONFIG_CHIP_CRYPTO_PSA */ + +#if CONFIG_MCUX_ELS_PKC + +#define MBEDTLS_CIPHER_PADDING_PKCS7 + +#if CONFIG_WIFI_NXP && CONFIG_WPA_SUPP +#include "wpa_supp_els_pkc_mbedtls_config.h" +#endif /* CONFIG_WIFI_NXP && CONFIG_WPA_SUPP */ + +#if CONFIG_MCUX_PSA_CRYPTO_DRIVER_ELS_PKC +#define PSA_CRYPTO_DRIVER_ELS_PKC +#endif /* CONFIG_MCUX_PSA_CRYPTO_DRIVER_ELS_PKC */ + +#endif /* CONFIG_MCUX_ELS_PKC */ + +#undef MBEDTLS_MD4_C +#undef MBEDTLS_ARC4_C diff --git a/src/platform/nxp/zephyr/ota/OTAImageProcessorImpl.cpp b/src/platform/nxp/zephyr/ota/OTAImageProcessorImpl.cpp new file mode 100644 index 00000000000000..0d027b0407a5b8 --- /dev/null +++ b/src/platform/nxp/zephyr/ota/OTAImageProcessorImpl.cpp @@ -0,0 +1,174 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OTAImageProcessorImpl.h" + +#include +#include +#include + +#include +#include +#include +#include + +static struct stream_flash_ctx stream; + +namespace chip { +namespace DeviceLayer { + +CHIP_ERROR OTAImageProcessorImpl::PrepareDownload() +{ + VerifyOrReturnError(mDownloader != nullptr, CHIP_ERROR_INCORRECT_STATE); + + return DeviceLayer::SystemLayer().ScheduleLambda([this] { mDownloader->OnPreparedForDownload(PrepareDownloadImpl()); }); +} + +CHIP_ERROR OTAImageProcessorImpl::PrepareDownloadImpl() +{ + mHeaderParser.Init(); + mParams = {}; + + const struct device * flash_dev; + + flash_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller)); + if (flash_dev == NULL) + { + ChipLogError(SoftwareUpdate, "Failed to get flash device"); + return System::MapErrorZephyr(-EFAULT); + } + + int err = stream_flash_init(&stream, flash_dev, mBuffer, sizeof(mBuffer), FIXED_PARTITION_OFFSET(slot1_partition), + FIXED_PARTITION_SIZE(slot1_partition), NULL); + + if (err) + { + ChipLogError(SoftwareUpdate, "stream_flash_init failed (err %d)", err); + } + + return System::MapErrorZephyr(err); +} + +CHIP_ERROR OTAImageProcessorImpl::Finalize() +{ + int err = stream_flash_buffered_write(&stream, NULL, 0, true); + + if (err) + { + ChipLogError(SoftwareUpdate, "stream_flash_buffered_write failed (err %d)", err); + } + + return System::MapErrorZephyr(err); +} + +CHIP_ERROR OTAImageProcessorImpl::Abort() +{ + ChipLogError(SoftwareUpdate, "Image upgrade aborted"); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Apply() +{ + // Schedule update of image + int err = boot_request_upgrade(BOOT_UPGRADE_PERMANENT); + +#ifdef CONFIG_CHIP_OTA_REQUESTOR_REBOOT_ON_APPLY + if (!err) + { + return SystemLayer().StartTimer( + System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_OTA_REQUESTOR_REBOOT_DELAY_MS), + [](System::Layer *, void * /* context */) { + PlatformMgr().HandleServerShuttingDown(); + k_msleep(CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS); + sys_reboot(SYS_REBOOT_WARM); + }, + nullptr /* context */); + } + else + { + return System::MapErrorZephyr(err); + } +#else + return System::MapErrorZephyr(err); +#endif +} + +CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & aBlock) +{ + VerifyOrReturnError(mDownloader != nullptr, CHIP_ERROR_INCORRECT_STATE); + + CHIP_ERROR error = ProcessHeader(aBlock); + + if (error == CHIP_NO_ERROR) + { + error = System::MapErrorZephyr(stream_flash_buffered_write(&stream, aBlock.data(), aBlock.size(), false)); + mParams.downloadedBytes += aBlock.size(); + } + + // Report the result back to the downloader asynchronously. + return DeviceLayer::SystemLayer().ScheduleLambda([this, error, aBlock] { + if (error == CHIP_NO_ERROR) + { + ChipLogDetail(SoftwareUpdate, "Downloaded %u/%u bytes", static_cast(mParams.downloadedBytes), + static_cast(mParams.totalFileBytes)); + mDownloader->FetchNextData(); + } + else + { + mDownloader->EndDownload(error); + } + }); +} + +bool OTAImageProcessorImpl::IsFirstImageRun() +{ + OTARequestorInterface * requestor = GetRequestorInstance(); + ReturnErrorCodeIf(requestor == nullptr, false); + + uint32_t currentVersion; + ReturnErrorCodeIf(ConfigurationMgr().GetSoftwareVersion(currentVersion) != CHIP_NO_ERROR, false); + + return requestor->GetCurrentUpdateState() == OTARequestorInterface::OTAUpdateStateEnum::kApplying && + requestor->GetTargetVersion() == currentVersion; +} + +CHIP_ERROR OTAImageProcessorImpl::ConfirmCurrentImage() +{ + return System::MapErrorZephyr(boot_write_img_confirmed()); +} + +CHIP_ERROR OTAImageProcessorImpl::ProcessHeader(ByteSpan & aBlock) +{ + if (mHeaderParser.IsInitialized()) + { + OTAImageHeader header; + CHIP_ERROR error = mHeaderParser.AccumulateAndDecode(aBlock, header); + + // Needs more data to decode the header + ReturnErrorCodeIf(error == CHIP_ERROR_BUFFER_TOO_SMALL, CHIP_NO_ERROR); + ReturnErrorOnFailure(error); + + mParams.totalFileBytes = header.mPayloadSize; + mHeaderParser.Clear(); + } + + return CHIP_NO_ERROR; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/ota/OTAImageProcessorImpl.h b/src/platform/nxp/zephyr/ota/OTAImageProcessorImpl.h new file mode 100755 index 00000000000000..e4a8a95ba721ae --- /dev/null +++ b/src/platform/nxp/zephyr/ota/OTAImageProcessorImpl.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +namespace chip { + +class OTADownloader; + +namespace DeviceLayer { + +class OTAImageProcessorImpl : public OTAImageProcessorInterface +{ +public: + static constexpr size_t kBufferSize = CONFIG_CHIP_OTA_REQUESTOR_BUFFER_SIZE; + + void SetOTADownloader(OTADownloader * downloader) { mDownloader = downloader; }; + + CHIP_ERROR PrepareDownload() override; + CHIP_ERROR Finalize() override; + CHIP_ERROR Abort() override; + CHIP_ERROR Apply() override; + CHIP_ERROR ProcessBlock(ByteSpan & aBlock) override; + bool IsFirstImageRun() override; + CHIP_ERROR ConfirmCurrentImage() override; + +private: + CHIP_ERROR PrepareDownloadImpl(); + CHIP_ERROR ProcessHeader(ByteSpan & aBlock); + + OTADownloader * mDownloader = nullptr; + OTAImageHeaderParser mHeaderParser; + uint8_t mBuffer[kBufferSize]; +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/wifi/ConnectivityManagerImplWiFi.cpp b/src/platform/nxp/zephyr/wifi/ConnectivityManagerImplWiFi.cpp new file mode 100644 index 00000000000000..3fefcf709e1b9b --- /dev/null +++ b/src/platform/nxp/zephyr/wifi/ConnectivityManagerImplWiFi.cpp @@ -0,0 +1,178 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* this file behaves like a config.h, comes first */ +#include + +#include +#include + +#include "ConnectivityManagerImplWiFi.h" +#include "WiFiManager.h" + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::TLV; + +namespace chip { +namespace DeviceLayer { + +CHIP_ERROR ConnectivityManagerImplWiFi::InitWiFi() +{ + return WiFiManager::Instance().Init(); +} + +ConnectivityManager::WiFiStationMode ConnectivityManagerImplWiFi::_GetWiFiStationMode(void) +{ + if (mStationMode != ConnectivityManager::WiFiStationMode::kWiFiStationMode_ApplicationControlled) + { + mStationMode = (WiFiManager::StationStatus::DISABLED == WiFiManager().Instance().GetStationStatus()) + ? ConnectivityManager::WiFiStationMode::kWiFiStationMode_Disabled + : ConnectivityManager::WiFiStationMode::kWiFiStationMode_Enabled; + } + return mStationMode; +} + +CHIP_ERROR ConnectivityManagerImplWiFi::_SetWiFiStationMode(ConnectivityManager::WiFiStationMode aMode) +{ + VerifyOrReturnError(ConnectivityManager::WiFiStationMode::kWiFiStationMode_NotSupported != aMode, CHIP_ERROR_INVALID_ARGUMENT); + + mStationMode = aMode; + + return CHIP_NO_ERROR; +} + +bool ConnectivityManagerImplWiFi::_IsWiFiStationEnabled(void) +{ + return (WiFiManager::StationStatus::DISABLED <= WiFiManager().Instance().GetStationStatus()); +} + +bool ConnectivityManagerImplWiFi::_IsWiFiStationApplicationControlled(void) +{ + return (ConnectivityManager::WiFiStationMode::kWiFiStationMode_ApplicationControlled == mStationMode); +} + +bool ConnectivityManagerImplWiFi::_IsWiFiStationConnected(void) +{ + return (WiFiManager::StationStatus::CONNECTED == WiFiManager().Instance().GetStationStatus()); +} + +System::Clock::Timeout ConnectivityManagerImplWiFi::_GetWiFiStationReconnectInterval(void) +{ + return mWiFiStationReconnectInterval; +} + +CHIP_ERROR ConnectivityManagerImplWiFi::_SetWiFiStationReconnectInterval(System::Clock::Timeout val) +{ + mWiFiStationReconnectInterval = val; + return CHIP_NO_ERROR; +} + +bool ConnectivityManagerImplWiFi::_IsWiFiStationProvisioned(void) +{ + // from Matter perspective `provisioned` means that the supplicant has been provided + // with SSID and password (doesn't matter if valid or not) + return (WiFiManager::StationStatus::CONNECTING <= WiFiManager().Instance().GetStationStatus()); +} + +void ConnectivityManagerImplWiFi::_ClearWiFiStationProvision(void) +{ + if (_IsWiFiStationProvisioned()) + { + if (CHIP_NO_ERROR != WiFiManager().Instance().ClearStationProvisioningData()) + { + ChipLogError(DeviceLayer, "Cannot clear WiFi station provisioning data"); + } + } +} + +bool ConnectivityManagerImplWiFi::_CanStartWiFiScan() +{ + return (WiFiManager::StationStatus::DISABLED != WiFiManager().Instance().GetStationStatus() && + WiFiManager::StationStatus::SCANNING != WiFiManager().Instance().GetStationStatus() && + WiFiManager::StationStatus::CONNECTING != WiFiManager().Instance().GetStationStatus()); +} + +void ConnectivityManagerImplWiFi::_OnWiFiStationProvisionChange() +{ + // do nothing +} + +void ConnectivityManagerImplWiFi::_OnWiFiScanDone() {} + +CHIP_ERROR ConnectivityManagerImplWiFi::_GetAndLogWiFiStatsCounters(void) +{ + // TODO: when network statistics are enabled + return CHIP_NO_ERROR; +} + +ConnectivityManager::WiFiAPMode ConnectivityManagerImplWiFi::_GetWiFiAPMode(void) +{ + /* AP mode is unsupported */ + return ConnectivityManager::WiFiAPMode::kWiFiAPMode_NotSupported; +} + +CHIP_ERROR ConnectivityManagerImplWiFi::_SetWiFiAPMode(ConnectivityManager::WiFiAPMode mode) +{ + /* AP mode is unsupported */ + VerifyOrReturnError(ConnectivityManager::WiFiAPMode::kWiFiAPMode_NotSupported == mode || + ConnectivityManager::WiFiAPMode::kWiFiAPMode_Disabled == mode, + CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + return CHIP_NO_ERROR; +} + +bool ConnectivityManagerImplWiFi::_IsWiFiAPActive(void) +{ + /* AP mode is unsupported */ + return false; +} + +bool ConnectivityManagerImplWiFi::_IsWiFiAPApplicationControlled(void) +{ + /* AP mode is unsupported */ + return false; +} + +void ConnectivityManagerImplWiFi::_DemandStartWiFiAP(void) +{ /* AP mode is unsupported */ +} + +void ConnectivityManagerImplWiFi::_StopOnDemandWiFiAP(void) +{ /* AP mode is unsupported */ +} + +void ConnectivityManagerImplWiFi::_MaintainOnDemandWiFiAP(void) +{ /* AP mode is unsupported */ +} + +System::Clock::Timeout ConnectivityManagerImplWiFi::_GetWiFiAPIdleTimeout(void) +{ + /* AP mode is unsupported */ + return System::Clock::kZero; +} + +void ConnectivityManagerImplWiFi::_SetWiFiAPIdleTimeout(System::Clock::Timeout val) +{ /* AP mode is unsupported */ +} + +} // namespace DeviceLayer +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI diff --git a/src/platform/nxp/zephyr/wifi/ConnectivityManagerImplWiFi.h b/src/platform/nxp/zephyr/wifi/ConnectivityManagerImplWiFi.h new file mode 100644 index 00000000000000..ec9c1d12027af9 --- /dev/null +++ b/src/platform/nxp/zephyr/wifi/ConnectivityManagerImplWiFi.h @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +#include + +namespace chip { +namespace Inet { +class IPAddress; +} // namespace Inet +} // namespace chip + +namespace chip { +namespace DeviceLayer { + +class ConnectivityManagerImplWiFi +{ + friend class ConnectivityManager; + +protected: + CHIP_ERROR InitWiFi(); + +private: + // Wi-Fi station + ConnectivityManager::WiFiStationMode _GetWiFiStationMode(void); + CHIP_ERROR _SetWiFiStationMode(ConnectivityManager::WiFiStationMode val); + bool _IsWiFiStationEnabled(void); + bool _IsWiFiStationApplicationControlled(void); + bool _IsWiFiStationConnected(void); + System::Clock::Timeout _GetWiFiStationReconnectInterval(void); + CHIP_ERROR _SetWiFiStationReconnectInterval(System::Clock::Timeout val); + bool _IsWiFiStationProvisioned(void); + void _ClearWiFiStationProvision(void); + CHIP_ERROR _GetAndLogWiFiStatsCounters(void); + bool _CanStartWiFiScan(); + void _OnWiFiScanDone(); + void _OnWiFiStationProvisionChange(); + + // Wi-Fi access point - not supported + ConnectivityManager::WiFiAPMode _GetWiFiAPMode(void); + CHIP_ERROR _SetWiFiAPMode(ConnectivityManager::WiFiAPMode val); + bool _IsWiFiAPActive(void); + bool _IsWiFiAPApplicationControlled(void); + void _DemandStartWiFiAP(void); + void _StopOnDemandWiFiAP(void); + void _MaintainOnDemandWiFiAP(void); + System::Clock::Timeout _GetWiFiAPIdleTimeout(void); + void _SetWiFiAPIdleTimeout(System::Clock::Timeout val); + + ConnectivityManager::WiFiStationMode mStationMode{ ConnectivityManager::WiFiStationMode::kWiFiStationMode_Disabled }; + ConnectivityManager::WiFiStationState mStationState{ ConnectivityManager::WiFiStationState::kWiFiStationState_NotConnected }; + System::Clock::Timeout mWiFiStationReconnectInterval{}; + + static const char * _WiFiStationModeToStr(ConnectivityManager::WiFiStationMode mode); + static const char * _WiFiAPModeToStr(ConnectivityManager::WiFiAPMode mode); + static const char * _WiFiStationStateToStr(ConnectivityManager::WiFiStationState state); + static const char * _WiFiAPStateToStr(ConnectivityManager::WiFiAPState state); +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/wifi/NxpWifiDriver.cpp b/src/platform/nxp/zephyr/wifi/NxpWifiDriver.cpp new file mode 100644 index 00000000000000..06a0b48f1e8c77 --- /dev/null +++ b/src/platform/nxp/zephyr/wifi/NxpWifiDriver.cpp @@ -0,0 +1,298 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NxpWifiDriver.h" + +#include + +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::DeviceLayer::Internal; +using namespace ::chip::DeviceLayer::PersistedStorage; +using namespace ::chip::app::Clusters::NetworkCommissioning; + +namespace chip { +namespace DeviceLayer { +namespace NetworkCommissioning { + +size_t NxpWifiDriver::WiFiNetworkIterator::Count() +{ + VerifyOrReturnValue(mDriver != nullptr, 0); + return mDriver->mStagingNetwork.IsConfigured() ? 1 : 0; +} + +bool NxpWifiDriver::WiFiNetworkIterator::Next(Network & item) +{ + // we assume only one network is actually supported + // TODO: verify if this can be extended + if (mExhausted || 0 == Count()) + { + return false; + } + + memcpy(item.networkID, mDriver->mStagingNetwork.ssid, mDriver->mStagingNetwork.ssidLen); + item.networkIDLen = static_cast(mDriver->mStagingNetwork.ssidLen); + item.connected = false; + + mExhausted = true; + + WiFiManager::WiFiInfo wifiInfo; + if (CHIP_NO_ERROR == WiFiManager::Instance().GetWiFiInfo(wifiInfo)) + { + if (WiFiManager::StationStatus::CONNECTED <= WiFiManager::Instance().GetStationStatus()) + { + if (wifiInfo.mSsidLen == item.networkIDLen && 0 == memcmp(wifiInfo.mSsid, item.networkID, wifiInfo.mSsidLen)) + { + item.connected = true; + } + } + } + return true; +} + +bool NxpWifiScanResponseIterator::Next(WiFiScanResponse & item) +{ + if (mResultId < mResultCount) + { + item = mResults[mResultId++]; + return true; + } + return false; +} + +void NxpWifiScanResponseIterator::Release() +{ + mResultId = mResultCount = 0; + Platform::MemoryFree(mResults); + mResults = nullptr; +} + +void NxpWifiScanResponseIterator::Add(const WiFiScanResponse & result) +{ + void * newResults = Platform::MemoryRealloc(mResults, (mResultCount + 1) * sizeof(WiFiScanResponse)); + + if (newResults) + { + mResults = static_cast(newResults); + mResults[mResultCount++] = result; + } +} + +CHIP_ERROR NxpWifiDriver::Init(NetworkStatusChangeCallback * networkStatusChangeCallback) +{ + mpNetworkStatusChangeCallback = networkStatusChangeCallback; + + LoadFromStorage(); + + if (mStagingNetwork.IsConfigured()) + { + WiFiManager::ConnectionHandling handling{ [] { Instance().OnNetworkStatusChanged(Status::kSuccess); }, + [] { Instance().OnNetworkStatusChanged(Status::kUnknownError); }, + System::Clock::Seconds32{ kWiFiConnectNetworkTimeoutSeconds } }; + ReturnErrorOnFailure( + WiFiManager::Instance().Connect(mStagingNetwork.GetSsidSpan(), mStagingNetwork.GetPassSpan(), handling)); + } + + return CHIP_NO_ERROR; +} + +void NxpWifiDriver::OnNetworkStatusChanged(Status status) +{ + if (status == Status::kSuccess) + { + ConnectivityMgr().SetWiFiStationMode(ConnectivityManager::kWiFiStationMode_Enabled); + } + + if (mpNetworkStatusChangeCallback) + { + mpNetworkStatusChangeCallback->OnNetworkingStatusChange(status, NullOptional, NullOptional); + } + + if (mpConnectCallback) + { + mpConnectCallback->OnResult(status, CharSpan(), 0); + mpConnectCallback = nullptr; + } +} + +void NxpWifiDriver::Shutdown() +{ + mpNetworkStatusChangeCallback = nullptr; +} + +CHIP_ERROR NxpWifiDriver::CommitConfiguration() +{ + ReturnErrorOnFailure(KeyValueStoreMgr().Put(kPassKey, mStagingNetwork.pass, mStagingNetwork.passLen)); + ReturnErrorOnFailure(KeyValueStoreMgr().Put(kSsidKey, mStagingNetwork.ssid, mStagingNetwork.ssidLen)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR NxpWifiDriver::RevertConfiguration() +{ + // Abort Connection Recovery if it is in progress during reverting configuration. + // This is needed to stop recovery process after failsafe timer expiring. + WiFiManager::Instance().AbortConnectionRecovery(); + + LoadFromStorage(); + + if (WiFiManager::StationStatus::CONNECTING <= WiFiManager::Instance().GetStationStatus()) + { + WiFiManager::WiFiInfo wifiInfo; + ReturnErrorOnFailure(WiFiManager::Instance().GetWiFiInfo(wifiInfo)); + if (mStagingNetwork.GetSsidSpan().data_equal(ByteSpan(wifiInfo.mSsid, wifiInfo.mSsidLen))) + { + // we are already connected to this network, so return prematurely + return CHIP_NO_ERROR; + } + } + + if (mStagingNetwork.IsConfigured()) + { + WiFiManager::ConnectionHandling handling{ [] { Instance().OnNetworkStatusChanged(Status::kSuccess); }, + [] { Instance().OnNetworkStatusChanged(Status::kUnknownError); }, + System::Clock::Seconds32{ kWiFiConnectNetworkTimeoutSeconds } }; + ReturnErrorOnFailure( + WiFiManager::Instance().Connect(mStagingNetwork.GetSsidSpan(), mStagingNetwork.GetPassSpan(), handling)); + } + + return CHIP_NO_ERROR; +} + +Status NxpWifiDriver::AddOrUpdateNetwork(ByteSpan ssid, ByteSpan credentials, MutableCharSpan & outDebugText, + uint8_t & outNetworkIndex) +{ + outDebugText = {}; + outNetworkIndex = 0; + + VerifyOrReturnError(!mStagingNetwork.IsConfigured() || ssid.data_equal(mStagingNetwork.GetSsidSpan()), Status::kBoundsExceeded); + VerifyOrReturnError(ssid.size() <= sizeof(mStagingNetwork.ssid), Status::kOutOfRange); + VerifyOrReturnError(credentials.size() <= sizeof(mStagingNetwork.pass), Status::kOutOfRange); + + mStagingNetwork.Erase(); + memcpy(mStagingNetwork.ssid, ssid.data(), ssid.size()); + memcpy(mStagingNetwork.pass, credentials.data(), credentials.size()); + mStagingNetwork.ssidLen = ssid.size(); + mStagingNetwork.passLen = credentials.size(); + + return Status::kSuccess; +} + +Status NxpWifiDriver::RemoveNetwork(ByteSpan networkId, MutableCharSpan & outDebugText, uint8_t & outNetworkIndex) +{ + outDebugText = {}; + outNetworkIndex = 0; + + VerifyOrReturnError(networkId.data_equal(mStagingNetwork.GetSsidSpan()), Status::kNetworkIDNotFound); + mStagingNetwork.Clear(); + + return Status::kSuccess; +} + +Status NxpWifiDriver::ReorderNetwork(ByteSpan networkId, uint8_t index, MutableCharSpan & outDebugText) +{ + outDebugText = {}; + + // Only one network is supported for now + VerifyOrReturnError(index == 0, Status::kOutOfRange); + VerifyOrReturnError(networkId.data_equal(mStagingNetwork.GetSsidSpan()), Status::kNetworkIDNotFound); + + return Status::kSuccess; +} + +void NxpWifiDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * callback) +{ + Status status = Status::kSuccess; + WiFiManager::StationStatus stationStatus; + WiFiManager::ConnectionHandling handling{ [] { Instance().OnNetworkStatusChanged(Status::kSuccess); }, + [] { Instance().OnNetworkStatusChanged(Status::kUnknownError); }, + System::Clock::Seconds32{ kWiFiConnectNetworkTimeoutSeconds } }; + + VerifyOrExit(mpConnectCallback == nullptr, status = Status::kUnknownError); + mpConnectCallback = callback; + + stationStatus = WiFiManager::Instance().GetStationStatus(); + + VerifyOrExit(WiFiManager::StationStatus::CONNECTING != stationStatus, status = Status::kOtherConnectionFailure); + VerifyOrExit(networkId.data_equal(mStagingNetwork.GetSsidSpan()), status = Status::kNetworkIDNotFound); + + WiFiManager::Instance().Connect(mStagingNetwork.GetSsidSpan(), mStagingNetwork.GetPassSpan(), handling); + +exit: + if (mpConnectCallback != nullptr) + { + if (status == Status::kSuccess) + { + /* If the device is already connected to a network, send the success status right now to the cluster + * to make sure we have time to send command response before switch to another network */ + if (stationStatus >= WiFiManager::StationStatus::CONNECTED) + { + mpConnectCallback->OnResult(status, CharSpan(), 0); + mpConnectCallback = nullptr; + } + } + else + { + mpConnectCallback->OnResult(status, CharSpan(), 0); + mpConnectCallback = nullptr; + } + } +} + +void NxpWifiDriver::LoadFromStorage() +{ + WiFiManager::WiFiNetwork network; + + mStagingNetwork = {}; + ReturnOnFailure(KeyValueStoreMgr().Get(kSsidKey, network.ssid, sizeof(network.ssid), &network.ssidLen)); + ReturnOnFailure(KeyValueStoreMgr().Get(kPassKey, network.pass, sizeof(network.pass), &network.passLen)); + mStagingNetwork = network; +} + +void NxpWifiDriver::OnScanWiFiNetworkDone(WiFiManager::WiFiRequestStatus status) +{ + VerifyOrReturn(mScanCallback != nullptr); + mScanCallback->OnFinished(status == WiFiManager::WiFiRequestStatus::SUCCESS ? Status::kSuccess : Status::kUnknownError, + CharSpan(), &mScanResponseIterator); + mScanCallback = nullptr; +} + +void NxpWifiDriver::OnScanWiFiNetworkResult(const WiFiScanResponse & response) +{ + mScanResponseIterator.Add(response); +} + +void NxpWifiDriver::ScanNetworks(ByteSpan ssid, WiFiDriver::ScanCallback * callback) +{ + mScanCallback = callback; + CHIP_ERROR error = WiFiManager::Instance().Scan( + ssid, [](const WiFiScanResponse & response) { Instance().OnScanWiFiNetworkResult(response); }, + [](WiFiManager::WiFiRequestStatus status) { Instance().OnScanWiFiNetworkDone(status); }); + + if (error != CHIP_NO_ERROR) + { + mScanCallback = nullptr; + callback->OnFinished(Status::kUnknownError, CharSpan(), nullptr); + } +} + +} // namespace NetworkCommissioning +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/wifi/NxpWifiDriver.h b/src/platform/nxp/zephyr/wifi/NxpWifiDriver.h new file mode 100644 index 00000000000000..01e4964e2ea046 --- /dev/null +++ b/src/platform/nxp/zephyr/wifi/NxpWifiDriver.h @@ -0,0 +1,112 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "WiFiManager.h" + +#include + +namespace chip { +namespace DeviceLayer { +namespace NetworkCommissioning { + +constexpr uint8_t kMaxWiFiNetworks = 1; +constexpr uint8_t kWiFiScanNetworksTimeOutSeconds = 10; +constexpr uint8_t kWiFiConnectNetworkTimeoutSeconds = 35; + +class NxpWifiScanResponseIterator : public Iterator +{ +public: + size_t Count() override { return mResultCount; } + bool Next(WiFiScanResponse & item) override; + void Release() override; + void Add(const WiFiScanResponse & result); + +private: + size_t mResultId = 0; + size_t mResultCount = 0; + WiFiScanResponse * mResults = nullptr; +}; + +class NxpWifiDriver final : public WiFiDriver +{ +public: + // Define non-volatile storage keys for SSID and password. + // The naming convention is aligned with DefaultStorageKeyAllocator class. + static constexpr const char * kSsidKey = "g/wi/s"; + static constexpr const char * kPassKey = "g/wi/p"; + + class WiFiNetworkIterator final : public NetworkIterator + { + public: + WiFiNetworkIterator(NxpWifiDriver * aDriver) : mDriver(aDriver) {} + size_t Count() override; + bool Next(Network & item) override; + void Release() override { delete this; } + ~WiFiNetworkIterator() = default; + + private: + NxpWifiDriver * mDriver; + bool mExhausted{ false }; + }; + + // BaseDriver + NetworkIterator * GetNetworks() override { return new WiFiNetworkIterator(this); } + CHIP_ERROR Init(NetworkStatusChangeCallback * networkStatusChangeCallback) override; + void Shutdown() override; + + // WirelessDriver + uint8_t GetMaxNetworks() override { return kMaxWiFiNetworks; } + uint8_t GetScanNetworkTimeoutSeconds() override { return kWiFiScanNetworksTimeOutSeconds; } + uint8_t GetConnectNetworkTimeoutSeconds() override { return kWiFiConnectNetworkTimeoutSeconds; } + + CHIP_ERROR CommitConfiguration() override; + CHIP_ERROR RevertConfiguration() override; + + Status RemoveNetwork(ByteSpan networkId, MutableCharSpan & outDebugText, uint8_t & outNetworkIndex) override; + Status ReorderNetwork(ByteSpan networkId, uint8_t index, MutableCharSpan & outDebugText) override; + void ConnectNetwork(ByteSpan networkId, ConnectCallback * callback) override; + + // WiFiDriver + Status AddOrUpdateNetwork(ByteSpan ssid, ByteSpan credentials, MutableCharSpan & outDebugText, + uint8_t & outNetworkIndex) override; + void ScanNetworks(ByteSpan ssid, ScanCallback * callback) override; + + static NxpWifiDriver & Instance() + { + static NxpWifiDriver sInstance; + return sInstance; + } + + void OnNetworkStatusChanged(Status status); + void OnScanWiFiNetworkResult(const WiFiScanResponse & result); + void OnScanWiFiNetworkDone(WiFiManager::WiFiRequestStatus status); + +private: + void LoadFromStorage(); + + ConnectCallback * mpConnectCallback{ nullptr }; + NetworkStatusChangeCallback * mpNetworkStatusChangeCallback{ nullptr }; + WiFiManager::WiFiNetwork mStagingNetwork; + NxpWifiScanResponseIterator mScanResponseIterator; + ScanCallback * mScanCallback{ nullptr }; +}; + +} // namespace NetworkCommissioning +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/wifi/WiFiManager.cpp b/src/platform/nxp/zephyr/wifi/WiFiManager.cpp new file mode 100644 index 00000000000000..946546288761b4 --- /dev/null +++ b/src/platform/nxp/zephyr/wifi/WiFiManager.cpp @@ -0,0 +1,685 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides the wrapper for Zephyr WiFi API + */ + +#include "WiFiManager.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +#include + +// extern function to obtain bssid from status buffer +// It is defined in zephyr/subsys/net/ip/utils.c +extern char * net_sprint_ll_addr_buf(const uint8_t * ll, uint8_t ll_len, char * buf, int buflen); +} + +namespace chip { +namespace DeviceLayer { + +namespace { + +NetworkCommissioning::WiFiScanResponse ToScanResponse(const wifi_scan_result * result) +{ + NetworkCommissioning::WiFiScanResponse response = {}; + + if (result != nullptr) + { + static_assert(sizeof(response.ssid) == sizeof(result->ssid), "SSID length mismatch"); + static_assert(sizeof(response.bssid) == sizeof(result->mac), "BSSID length mismatch"); + + // TODO: Distinguish WPA versions + response.security.Set(result->security == WIFI_SECURITY_TYPE_PSK ? NetworkCommissioning::WiFiSecurity::kWpaPersonal + : NetworkCommissioning::WiFiSecurity::kUnencrypted); + response.channel = result->channel; + response.rssi = result->rssi; + response.ssidLen = result->ssid_length; + memcpy(response.ssid, result->ssid, result->ssid_length); + // TODO: MAC/BSSID is not filled by the Wi-Fi driver + memcpy(response.bssid, result->mac, result->mac_length); + } + + return response; +} + +// Matter expectations towards Wi-Fi version codes are unaligned with +// what wpa_supplicant provides. This function maps supplicant codes +// to the ones defined in the Matter spec (11.14.5.2. WiFiVersionEnum) +app::Clusters::WiFiNetworkDiagnostics::WiFiVersionEnum MapToMatterWiFiVersionCode(wifi_link_mode wifiVersion) +{ + using app::Clusters::WiFiNetworkDiagnostics::WiFiVersionEnum; + + if (wifiVersion < WIFI_1 || wifiVersion > WIFI_6E) + { + ChipLogError(DeviceLayer, "Unsupported Wi-Fi version detected"); + return WiFiVersionEnum::kA; // let's return 'a' by default + } + + switch (wifiVersion) + { + case WIFI_1: + return WiFiVersionEnum::kB; + case WIFI_2: + return WiFiVersionEnum::kA; + case WIFI_6E: + return WiFiVersionEnum::kAx; // treat as 802.11ax + default: + break; + } + + return static_cast(wifiVersion - 1); +} + +// Matter expectations towards Wi-Fi security type codes are unaligned with +// what wpa_supplicant provides. This function maps supplicant codes +// to the ones defined in the Matter spec (11.14.3.1. SecurityType enum) +app::Clusters::WiFiNetworkDiagnostics::SecurityTypeEnum MapToMatterSecurityType(wifi_security_type securityType) +{ + using app::Clusters::WiFiNetworkDiagnostics::SecurityTypeEnum; + + switch (securityType) + { + case WIFI_SECURITY_TYPE_NONE: + return SecurityTypeEnum::kNone; + case WIFI_SECURITY_TYPE_PSK: + case WIFI_SECURITY_TYPE_PSK_SHA256: + return SecurityTypeEnum::kWpa2; + case WIFI_SECURITY_TYPE_SAE: + return SecurityTypeEnum::kWpa3; + default: + break; + } + + return SecurityTypeEnum::kUnspecified; +} + +} // namespace + +const Map + WiFiManager::sStatusMap({ { WIFI_STATE_DISCONNECTED, WiFiManager::StationStatus::DISCONNECTED }, + { WIFI_STATE_INTERFACE_DISABLED, WiFiManager::StationStatus::DISABLED }, + { WIFI_STATE_INACTIVE, WiFiManager::StationStatus::DISABLED }, + { WIFI_STATE_SCANNING, WiFiManager::StationStatus::SCANNING }, + { WIFI_STATE_AUTHENTICATING, WiFiManager::StationStatus::CONNECTING }, + { WIFI_STATE_ASSOCIATING, WiFiManager::StationStatus::CONNECTING }, + { WIFI_STATE_ASSOCIATED, WiFiManager::StationStatus::CONNECTED }, + { WIFI_STATE_4WAY_HANDSHAKE, WiFiManager::StationStatus::PROVISIONING }, + { WIFI_STATE_GROUP_HANDSHAKE, WiFiManager::StationStatus::PROVISIONING }, + { WIFI_STATE_COMPLETED, WiFiManager::StationStatus::FULLY_PROVISIONED } }); + +const Map + WiFiManager::sEventHandlerMap({ { NET_EVENT_WIFI_SCAN_RESULT, WiFiManager::ScanResultHandler }, + { NET_EVENT_WIFI_SCAN_DONE, WiFiManager::ScanDoneHandler }, + { NET_EVENT_WIFI_CONNECT_RESULT, WiFiManager::ConnectHandler }, + { NET_EVENT_WIFI_DISCONNECT_RESULT, WiFiManager::NetworkDrivenDisconnectHandler }, + { NET_EVENT_WIFI_DISCONNECT_COMPLETE, WiFiManager::ApplicationDrivenDisconnectHandler } }); + +void WiFiManager::WifiMgmtEventHandler(net_mgmt_event_callback * cb, uint32_t mgmtEvent, net_if * iface) +{ + if (0 == strcmp(iface->if_dev->dev->name, InetUtils::GetInterface()->if_dev->dev->name)) + { + Platform::UniquePtr eventData(new uint8_t[cb->info_length]); + VerifyOrReturn(eventData); + memcpy(eventData.get(), cb->info, cb->info_length); + sEventHandlerMap[mgmtEvent](std::move(eventData)); + } +} + +CHIP_ERROR WiFiManager::Init() +{ + // TODO: consider moving these to ConnectivityManagerImpl to be prepared for handling multiple interfaces on a single device. + Inet::UDPEndPointImplSockets::SetJoinMulticastGroupHandler([](Inet::InterfaceId interfaceId, const Inet::IPAddress & address) { + const in6_addr addr = InetUtils::ToZephyrAddr(address); + net_if * iface = InetUtils::GetInterface(interfaceId); + VerifyOrReturnError(iface != nullptr, INET_ERROR_UNKNOWN_INTERFACE); + + net_if_mcast_addr * maddr = net_if_ipv6_maddr_add(iface, &addr); + + if (maddr && !net_if_ipv6_maddr_is_joined(maddr) && !net_ipv6_is_addr_mcast_link_all_nodes(&addr)) + { + net_if_ipv6_maddr_join(iface, maddr); + } + + return CHIP_NO_ERROR; + }); + + Inet::UDPEndPointImplSockets::SetLeaveMulticastGroupHandler([](Inet::InterfaceId interfaceId, const Inet::IPAddress & address) { + const in6_addr addr = InetUtils::ToZephyrAddr(address); + net_if * iface = InetUtils::GetInterface(interfaceId); + VerifyOrReturnError(iface != nullptr, INET_ERROR_UNKNOWN_INTERFACE); + + if (!net_ipv6_is_addr_mcast_link_all_nodes(&addr) && !net_if_ipv6_maddr_rm(iface, &addr)) + { + return CHIP_ERROR_INVALID_ADDRESS; + } + + return CHIP_NO_ERROR; + }); + + net_mgmt_init_event_callback(&mWiFiMgmtClbk, WifiMgmtEventHandler, kWifiManagementEvents); + net_mgmt_add_event_callback(&mWiFiMgmtClbk); + + ChipLogDetail(DeviceLayer, "WiFiManager has been initialized"); + + return CHIP_NO_ERROR; +} +CHIP_ERROR WiFiManager::Scan(const ByteSpan & ssid, ScanResultCallback resultCallback, ScanDoneCallback doneCallback, + bool internalScan) +{ + net_if * iface = InetUtils::GetInterface(); + VerifyOrReturnError(nullptr != iface, CHIP_ERROR_INTERNAL); + + mInternalScan = internalScan; + mScanResultCallback = resultCallback; + mScanDoneCallback = doneCallback; + mCachedWiFiState = mWiFiState; + mWiFiState = WIFI_STATE_SCANNING; + mSsidFound = false; + mRecoveryArmed = true; + // TODO Workaround for recovery mechanism to wait before the next scan request until the WiFi supplicant is not busy. + static bool workaroundDone; + + /* If the ssid is not null, it means the scan must target a specific SSID, and only include this one in the scan + * result. To do so, we save the requested ssid and we will filter the scan results accordingly in the scan done + * handler. */ + if ((ssid.size() > 0) && (!mInternalScan)) + { + mNetworkToScan.Erase(); + memcpy(mNetworkToScan.ssid, ssid.data(), ssid.size()); + mNetworkToScan.ssidLen = ssid.size(); + } + + int ret = net_mgmt(NET_REQUEST_WIFI_SCAN, iface, NULL, 0); + + if (ret) + { + ChipLogError(DeviceLayer, "Scan request failed %d", ret); + if (ret == -EBUSY && !workaroundDone) + { + // TODO Wi-Fi driver returned an error during recovery. + // As a workaround schedule the recovery timer one more time in WifiSupplicantWorkaroundTime time. + // This allows the device to run the Scan method without + // rebooting when the "Device or resource busy" error occurs. + DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds32(kWifiSupplicantWorkaroundTime), Recover, nullptr); + workaroundDone = true; + return CHIP_NO_ERROR; + } + else + { + // TODO The workaround has not worked, so reboot the device + ChipLogError(DeviceLayer, "WiFi driver does not respond, resetting the device..."); + workaroundDone = false; + PlatformMgr().Shutdown(); + } + return CHIP_ERROR_INTERNAL; + } + + ChipLogDetail(DeviceLayer, "WiFi scanning started..."); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiManager::ClearStationProvisioningData() +{ + mWiFiParams.mRssi = std::numeric_limits::min(); + memset(&mWiFiParams.mParams, 0, sizeof(mWiFiParams.mParams)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiManager::Connect(const ByteSpan & ssid, const ByteSpan & credentials, const ConnectionHandling & handling) +{ + ChipLogDetail(DeviceLayer, "Connecting to WiFi network: %.*s", ssid.size(), ssid.data()); + + mHandling.mOnConnectionSuccess = handling.mOnConnectionSuccess; + mHandling.mOnConnectionFailed = handling.mOnConnectionFailed; + mHandling.mConnectionTimeout = handling.mConnectionTimeout; + + mWiFiState = WIFI_STATE_ASSOCIATING; + + // Store SSID and credentials and perform the scan to detect the security mode supported by the AP. + // Zephyr WiFi connect request will be issued in the callback when we have the SSID match. + mWantedNetwork.Erase(); + memcpy(mWantedNetwork.ssid, ssid.data(), ssid.size()); + memcpy(mWantedNetwork.pass, credentials.data(), credentials.size()); + mWantedNetwork.ssidLen = ssid.size(); + mWantedNetwork.passLen = credentials.size(); + + return Scan(ssid, nullptr, nullptr, true /* internal scan */); +} + +CHIP_ERROR WiFiManager::Disconnect() +{ + net_if * iface = InetUtils::GetInterface(); + VerifyOrReturnError(nullptr != iface, CHIP_ERROR_INTERNAL); + + mApplicationDisconnectRequested = true; + int status = net_mgmt(NET_REQUEST_WIFI_DISCONNECT, iface, NULL, 0); + + if (status) + { + mApplicationDisconnectRequested = false; + if (status == -EALREADY) + { + ChipLogDetail(DeviceLayer, "Already disconnected"); + } + else + { + ChipLogDetail(DeviceLayer, "Disconnect request failed"); + return CHIP_ERROR_INTERNAL; + } + } + else + { + ChipLogDetail(DeviceLayer, "Disconnect requested"); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiManager::GetWiFiInfo(WiFiInfo & info) const +{ + net_if * iface = InetUtils::GetInterface(); + VerifyOrReturnError(nullptr != iface, CHIP_ERROR_INTERNAL); + struct wifi_iface_status status = { 0 }; + + if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &status, sizeof(struct wifi_iface_status))) + { + ChipLogError(DeviceLayer, "Status request failed"); + return CHIP_ERROR_INTERNAL; + } + + if (status.state >= WIFI_STATE_ASSOCIATED) + { + info.mSecurityType = MapToMatterSecurityType(status.security); + info.mWiFiVersion = MapToMatterWiFiVersionCode(status.link_mode); + info.mRssi = static_cast(status.rssi); + info.mChannel = static_cast(status.channel); + info.mSsidLen = status.ssid_len; + memcpy(info.mSsid, status.ssid, status.ssid_len); + memcpy(info.mBssId, status.bssid, sizeof(status.bssid)); + + return CHIP_NO_ERROR; + } + + return CHIP_ERROR_INTERNAL; +} + +CHIP_ERROR WiFiManager::GetNetworkStatistics(NetworkStatistics & stats) const +{ + net_stats_wifi data{}; + net_mgmt(NET_REQUEST_STATS_GET_WIFI, InetUtils::GetInterface(), &data, sizeof(data)); + + stats.mPacketMulticastRxCount = data.multicast.rx; + stats.mPacketMulticastTxCount = data.multicast.tx; + stats.mPacketUnicastRxCount = data.pkts.rx - data.multicast.rx - data.broadcast.rx; + stats.mPacketUnicastTxCount = data.pkts.tx - data.multicast.tx - data.broadcast.tx; + stats.mBeaconsSuccessCount = data.sta_mgmt.beacons_rx; + stats.mBeaconsLostCount = data.sta_mgmt.beacons_miss; + + return CHIP_NO_ERROR; +} + +void WiFiManager::ScanResultHandler(Platform::UniquePtr data) +{ + // Contrary to other handlers, offload accumulating of the scan results from the CHIP thread to the caller's thread + const struct wifi_scan_result * scanResult = reinterpret_cast(data.get()); + + if (Instance().mInternalScan && + Instance().mWantedNetwork.GetSsidSpan().data_equal(ByteSpan(scanResult->ssid, scanResult->ssid_length))) + { + // Prepare the connection parameters + // In case there are many networks with the same SSID choose the one with the best RSSI + if (scanResult->rssi > Instance().mWiFiParams.mRssi) + { + Instance().ClearStationProvisioningData(); + Instance().mWiFiParams.mParams.ssid_length = static_cast(Instance().mWantedNetwork.ssidLen); + Instance().mWiFiParams.mParams.ssid = Instance().mWantedNetwork.ssid; + // Fallback to the WIFI_SECURITY_TYPE_PSK if the security is unknown + Instance().mWiFiParams.mParams.security = + scanResult->security <= WIFI_SECURITY_TYPE_MAX ? scanResult->security : WIFI_SECURITY_TYPE_PSK; + Instance().mWiFiParams.mParams.psk_length = static_cast(Instance().mWantedNetwork.passLen); + Instance().mWiFiParams.mParams.mfp = (scanResult->mfp == WIFI_MFP_REQUIRED) ? WIFI_MFP_REQUIRED : WIFI_MFP_OPTIONAL; + + // If the security is none, WiFi driver expects the psk to be nullptr + if (Instance().mWiFiParams.mParams.security == WIFI_SECURITY_TYPE_NONE) + { + Instance().mWiFiParams.mParams.psk = nullptr; + } + else + { + Instance().mWiFiParams.mParams.psk = Instance().mWantedNetwork.pass; + } + + Instance().mWiFiParams.mParams.timeout = Instance().mHandling.mConnectionTimeout.count(); + Instance().mWiFiParams.mParams.channel = WIFI_CHANNEL_ANY; + Instance().mWiFiParams.mRssi = scanResult->rssi; + Instance().mSsidFound = true; + } + } + + if (Instance().mScanResultCallback && !Instance().mInternalScan) + { + /* Here we need to check if the scan is targeting a specific network and filter the scan result accordingly, + * to make sure only the targeted SSID is reported */ + if (Instance().mNetworkToScan.GetSsidSpan().size() == 0) + { + Instance().mScanResultCallback(ToScanResponse(scanResult)); + } + else if (Instance().mNetworkToScan.GetSsidSpan().data_equal(ByteSpan(scanResult->ssid, scanResult->ssid_length))) + { + Instance().mScanResultCallback(ToScanResponse(scanResult)); + } + } +} + +void WiFiManager::ScanDoneHandler(Platform::UniquePtr data) +{ + CHIP_ERROR err = SystemLayer().ScheduleLambda([capturedData = data.get()] { + Platform::UniquePtr safePtr(capturedData); + uint8_t * rawData = safePtr.get(); + const wifi_status * status = reinterpret_cast(rawData); + WiFiRequestStatus requestStatus = static_cast(status->status); + + /* Reset the specific network to scan */ + if (Instance().mNetworkToScan.GetSsidSpan().size() > 0) + { + Instance().mNetworkToScan.Erase(); + } + + if (requestStatus == WiFiRequestStatus::FAILURE) + { + ChipLogError(DeviceLayer, "Wi-Fi scan finalization failure (%d)", status->status); + } + else + { + ChipLogProgress(DeviceLayer, "Wi-Fi scan done (%d)", status->status); + } + + if (Instance().mScanDoneCallback && !Instance().mInternalScan) + { + Instance().mScanDoneCallback(requestStatus); + // restore the connection state from before the scan request was issued + Instance().mWiFiState = Instance().mCachedWiFiState; + return; + } + + // Internal scan is supposed to be followed by a connection request if the SSID has been found + if (Instance().mInternalScan) + { + if (Instance().mRecoveryArmed) + { + if (!Instance().mSsidFound) + { + ChipLogProgress(DeviceLayer, "No requested SSID found"); + auto currentTimeout = Instance().CalculateNextRecoveryTime(); + ChipLogProgress(DeviceLayer, "Starting connection recover: re-scanning... (next attempt in %d ms)", + currentTimeout.count()); + DeviceLayer::SystemLayer().StartTimer(currentTimeout, Recover, nullptr); + return; + } + else + { + Instance().AbortConnectionRecovery(); + } + } + + Instance().mWiFiState = WIFI_STATE_ASSOCIATING; + net_if * iface = InetUtils::GetInterface(); + VerifyOrReturn(nullptr != iface, CHIP_ERROR_INTERNAL); + + if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &(Instance().mWiFiParams.mParams), sizeof(wifi_connect_req_params))) + { + ChipLogError(DeviceLayer, "Connection request failed"); + if (Instance().mHandling.mOnConnectionFailed) + { + Instance().mHandling.mOnConnectionFailed(); + } + Instance().mWiFiState = WIFI_STATE_DISCONNECTED; + return; + } + ChipLogProgress(DeviceLayer, "Connection to %*s requested [RSSI=%d]", Instance().mWiFiParams.mParams.ssid_length, + Instance().mWiFiParams.mParams.ssid, Instance().mWiFiParams.mRssi); + Instance().mInternalScan = false; + } + }); + + if (CHIP_NO_ERROR == err) + { + // the ownership has been transferred to the worker thread - release the buffer + data.release(); + } +} + +void WiFiManager::SendRouterSolicitation(System::Layer * layer, void * param) +{ + net_if * iface = InetUtils::GetInterface(); + if (iface && iface->if_dev->link_addr.type == NET_LINK_ETHERNET) + { + net_if_start_rs(iface); + Instance().mRouterSolicitationCounter++; + if (Instance().mRouterSolicitationCounter < kRouterSolicitationMaxCount) + { + DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds32(kRouterSolicitationIntervalMs), + SendRouterSolicitation, nullptr); + } + else + { + Instance().mRouterSolicitationCounter = 0; + } + } +} + +void WiFiManager::ConnectHandler(Platform::UniquePtr data) +{ + CHIP_ERROR err = SystemLayer().ScheduleLambda([capturedData = data.get()] { + Platform::UniquePtr safePtr(capturedData); + uint8_t * rawData = safePtr.get(); + const wifi_status * status = reinterpret_cast(rawData); + WiFiRequestStatus requestStatus = static_cast(status->status); + + if (requestStatus == WiFiRequestStatus::FAILURE || requestStatus == WiFiRequestStatus::TERMINATED) + { + ChipLogProgress(DeviceLayer, "Connection to WiFi network failed or was terminated by another request"); + Instance().mWiFiState = WIFI_STATE_DISCONNECTED; + if (Instance().mHandling.mOnConnectionFailed) + { + Instance().mHandling.mOnConnectionFailed(); + } + } + else // The connection has been established successfully. + { + // Workaround needed until sending Router Solicitation after connect will be done by the driver. + DeviceLayer::SystemLayer().StartTimer( + System::Clock::Milliseconds32(chip::Crypto::GetRandU16() % kMaxInitialRouterSolicitationDelayMs), + SendRouterSolicitation, nullptr); + + ChipLogProgress(DeviceLayer, "Connected to WiFi network"); + Instance().mWiFiState = WIFI_STATE_COMPLETED; + if (Instance().mHandling.mOnConnectionSuccess) + { + Instance().mHandling.mOnConnectionSuccess(); + } + Instance().PostConnectivityStatusChange(kConnectivity_Established); + + // Workaround needed to re-initialize mDNS server after Wi-Fi interface is operative + chip::DeviceLayer::ChipDeviceEvent event; + event.Type = chip::DeviceLayer::DeviceEventType::kDnssdInitialized; + + CHIP_ERROR error = chip::DeviceLayer::PlatformMgr().PostEvent(&event); + if (error != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Cannot post event [error: %s]", ErrorStr(error)); + } + } + // Ensure fresh recovery for future connection requests. + Instance().ResetRecoveryTime(); + // cleanup the provisioning data as it is configured per each connect request + Instance().ClearStationProvisioningData(); + }); + + if (CHIP_NO_ERROR == err) + { + // the ownership has been transferred to the worker thread - release the buffer + data.release(); + } +} + +void WiFiManager::NetworkDrivenDisconnectHandler(Platform::UniquePtr) +{ + // Workaround: schedule the application level connection recovery in kSupplicantReconnectionTimeoutMs to give WPA supplicant + // some time to restore it. + if (!Instance().mRecoveryArmed) + { + Instance().mRecoveryArmed = true; + DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds32(kSupplicantReconnectionTimeoutMs), Recover, nullptr); + } + + SystemLayer().ScheduleLambda([] { + ChipLogProgress(DeviceLayer, "WiFi station disconnected"); + Instance().mWiFiState = WIFI_STATE_DISCONNECTED; + Instance().PostConnectivityStatusChange(kConnectivity_Lost); + }); +} + +void WiFiManager::ApplicationDrivenDisconnectHandler(Platform::UniquePtr) +{ + if (!Instance().mRecoveryArmed) + { + return; + } + + if (!Instance().mApplicationDisconnectRequested) + { + Instance().AbortConnectionRecovery(); + } + else + { + Instance().mApplicationDisconnectRequested = false; + SystemLayer().ScheduleLambda([] { Recover(nullptr, nullptr); }); + } +} + +WiFiManager::StationStatus WiFiManager::GetStationStatus() const +{ + return WiFiManager::sStatusMap[mWiFiState]; +} + +void WiFiManager::PostConnectivityStatusChange(ConnectivityChange changeType) +{ + ChipDeviceEvent networkEvent{}; + networkEvent.Type = DeviceEventType::kWiFiConnectivityChange; + networkEvent.WiFiConnectivityChange.Result = changeType; + PlatformMgr().PostEventOrDie(&networkEvent); +} + +System::Clock::Milliseconds32 WiFiManager::CalculateNextRecoveryTime() +{ + if (mConnectionRecoveryTimeMs > kConnectionRecoveryMaxIntervalMs) + { + // Find the new random jitter value in range [-jitter, +jitter]. + int32_t jitter = chip::Crypto::GetRandU32() % (2 * jitter + 1) - jitter; + mConnectionRecoveryTimeMs = kConnectionRecoveryMaxIntervalMs + jitter; + return System::Clock::Milliseconds32(mConnectionRecoveryTimeMs); + } + else + { + uint32_t currentRecoveryTimeout = mConnectionRecoveryTimeMs; + mConnectionRecoveryTimeMs = mConnectionRecoveryTimeMs * 2; + return System::Clock::Milliseconds32(currentRecoveryTimeout); + } +} + +void WiFiManager::Recover(System::Layer *, void *) +{ + // Prevent scheduling recovery if we are already connected to the network. + if (Instance().mWiFiState == WIFI_STATE_COMPLETED) + { + Instance().AbortConnectionRecovery(); + return; + } + + // If kConnectionRecoveryMaxOverallInterval has a non-zero value prevent endless re-scan. + if (0 != kConnectionRecoveryMaxRetries && (++Instance().mConnectionRecoveryCounter >= kConnectionRecoveryMaxRetries)) + { + Instance().AbortConnectionRecovery(); + return; + } + + Instance().Scan(Instance().mWantedNetwork.GetSsidSpan(), nullptr, nullptr, true /* internal scan */); +} + +void WiFiManager::ResetRecoveryTime() +{ + mConnectionRecoveryTimeMs = kConnectionRecoveryMinIntervalMs; + mConnectionRecoveryCounter = 0; +} + +void WiFiManager::AbortConnectionRecovery() +{ + DeviceLayer::SystemLayer().CancelTimer(Recover, nullptr); + Instance().ResetRecoveryTime(); + Instance().mRecoveryArmed = false; +} + +CHIP_ERROR WiFiManager::SetLowPowerMode(bool onoff) +{ + net_if * iface = InetUtils::GetInterface(); + VerifyOrReturnError(nullptr != iface, CHIP_ERROR_INTERNAL); + + wifi_ps_config currentConfig{}; + if (net_mgmt(NET_REQUEST_WIFI_PS_CONFIG, iface, ¤tConfig, sizeof(currentConfig))) + { + ChipLogError(DeviceLayer, "Get current low power mode config request failed"); + return CHIP_ERROR_INTERNAL; + } + + if ((currentConfig.ps_params.enabled == WIFI_PS_ENABLED && onoff == false) || + (currentConfig.ps_params.enabled == WIFI_PS_DISABLED && onoff == true)) + { + wifi_ps_params params{ .enabled = onoff ? WIFI_PS_ENABLED : WIFI_PS_DISABLED }; + if (net_mgmt(NET_REQUEST_WIFI_PS, iface, ¶ms, sizeof(params))) + { + ChipLogError(DeviceLayer, "Set low power mode request failed"); + return CHIP_ERROR_INTERNAL; + } + ChipLogProgress(DeviceLayer, "Successfully set low power mode [%d]", onoff); + return CHIP_NO_ERROR; + } + + ChipLogDetail(DeviceLayer, "Low power mode is already in requested state [%d]", onoff); + return CHIP_NO_ERROR; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/zephyr/wifi/WiFiManager.h b/src/platform/nxp/zephyr/wifi/WiFiManager.h new file mode 100644 index 00000000000000..29f2ef299af1aa --- /dev/null +++ b/src/platform/nxp/zephyr/wifi/WiFiManager.h @@ -0,0 +1,253 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides the wrapper for Zephyr wpa_supplicant API + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +extern "C" { +#include +#include +} + +struct net_if; +struct wpa_ssid; +using WpaNetwork = struct wpa_ssid; + +namespace chip { +namespace DeviceLayer { + +// emulation of dictionary - might be moved to utils +template +class Map +{ + struct Pair + { + T1 key; + T2 value; + }; + +public: + Map(const Pair (&list)[N]) + { + int idx{ 0 }; + for (const auto & pair : list) + { + mMap[idx++] = pair; + } + } + + T2 operator[](const T1 & key) const + { + for (const auto & it : mMap) + { + if (key == it.key) + return it.value; + } + + return T2{}; + } + + Map() = delete; + Map(const Map &) = delete; + Map(Map &&) = delete; + Map & operator=(const Map &) = delete; + Map & operator=(Map &&) = delete; + ~Map() = default; + +private: + Pair mMap[N]; +}; + +class WiFiManager +{ +public: + enum WiFiRequestStatus : int + { + SUCCESS = 0, + FAILURE = 1, + TERMINATED = 2 + }; + + using ScanResultCallback = void (*)(const NetworkCommissioning::WiFiScanResponse &); + using ScanDoneCallback = void (*)(WiFiRequestStatus); + using ConnectionCallback = void (*)(); + + enum class StationStatus : uint8_t + { + NONE, + DISCONNECTED, + DISABLED, + SCANNING, + CONNECTING, + CONNECTED, + PROVISIONING, + FULLY_PROVISIONED, + UNKNOWN + }; + + static WiFiManager & Instance() + { + static WiFiManager sInstance; + return sInstance; + } + + struct ConnectionHandling + { + ConnectionCallback mOnConnectionSuccess{}; + ConnectionCallback mOnConnectionFailed{}; + System::Clock::Seconds32 mConnectionTimeout{}; + }; + + struct WiFiInfo + { + uint8_t mBssId[DeviceLayer::Internal::kWiFiBSSIDLength]; + app::Clusters::WiFiNetworkDiagnostics::SecurityTypeEnum mSecurityType{}; + app::Clusters::WiFiNetworkDiagnostics::WiFiVersionEnum mWiFiVersion{}; + uint16_t mChannel{}; + int8_t mRssi{}; + uint8_t mSsid[DeviceLayer::Internal::kMaxWiFiSSIDLength]; + size_t mSsidLen{ 0 }; + }; + + struct NetworkStatistics + { + uint32_t mPacketMulticastRxCount{}; + uint32_t mPacketMulticastTxCount{}; + uint32_t mPacketUnicastRxCount{}; + uint32_t mPacketUnicastTxCount{}; + uint32_t mBeaconsSuccessCount{}; + uint32_t mBeaconsLostCount{}; + }; + + struct WiFiNetwork + { + uint8_t ssid[DeviceLayer::Internal::kMaxWiFiSSIDLength]; + size_t ssidLen = 0; + uint8_t pass[DeviceLayer::Internal::kMaxWiFiKeyLength]; + size_t passLen = 0; + + bool IsConfigured() const { return ssidLen > 0; } + ByteSpan GetSsidSpan() const { return ByteSpan(ssid, ssidLen); } + ByteSpan GetPassSpan() const { return ByteSpan(pass, passLen); } + void Clear() { ssidLen = 0; } + void Erase() + { + memset(ssid, 0, DeviceLayer::Internal::kMaxWiFiSSIDLength); + memset(pass, 0, DeviceLayer::Internal::kMaxWiFiKeyLength); + ssidLen = 0; + passLen = 0; + } + }; + + static constexpr uint16_t kRouterSolicitationIntervalMs = 4000; + static constexpr uint16_t kMaxInitialRouterSolicitationDelayMs = 1000; + static constexpr uint8_t kRouterSolicitationMaxCount = 3; + static constexpr uint32_t kConnectionRecoveryMinIntervalMs = CONFIG_CHIP_WIFI_CONNECTION_RECOVERY_MINIMUM_INTERVAL; + static constexpr uint32_t kConnectionRecoveryMaxIntervalMs = CONFIG_CHIP_WIFI_CONNECTION_RECOVERY_MAXIMUM_INTERVAL; + static constexpr uint32_t kConnectionRecoveryJitterMs = CONFIG_CHIP_WIFI_CONNECTION_RECOVERY_JITTER; + static constexpr uint32_t kConnectionRecoveryMaxRetries = CONFIG_CHIP_WIFI_CONNECTION_RECOVERY_MAX_RETRIES_NUMBER; + static constexpr uint32_t kSupplicantReconnectionTimeoutMs = 60000; + + static_assert(kConnectionRecoveryMinIntervalMs < kConnectionRecoveryMaxIntervalMs); + static_assert(kConnectionRecoveryJitterMs <= kConnectionRecoveryMaxIntervalMs); + + CHIP_ERROR Init(); + CHIP_ERROR Scan(const ByteSpan & ssid, ScanResultCallback resultCallback, ScanDoneCallback doneCallback, + bool internalScan = false); + CHIP_ERROR Connect(const ByteSpan & ssid, const ByteSpan & credentials, const ConnectionHandling & handling); + StationStatus GetStationStatus() const; + CHIP_ERROR ClearStationProvisioningData(); + CHIP_ERROR Disconnect(); + CHIP_ERROR GetWiFiInfo(WiFiInfo & info) const; + CHIP_ERROR GetNetworkStatistics(NetworkStatistics & stats) const; + void AbortConnectionRecovery(); + CHIP_ERROR SetLowPowerMode(bool onoff); + +private: + using NetEventHandler = void (*)(Platform::UniquePtr); + + struct ConnectionParams + { + wifi_connect_req_params mParams; + int8_t mRssi{ std::numeric_limits::min() }; + }; + + constexpr static uint32_t kWifiManagementEvents = NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE | + NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_COMPLETE | + NET_EVENT_WIFI_IFACE_STATUS; + + // Event handling + static void WifiMgmtEventHandler(net_mgmt_event_callback * cb, uint32_t mgmtEvent, net_if * iface); + static void ScanResultHandler(Platform::UniquePtr data); + static void ScanDoneHandler(Platform::UniquePtr data); + static void ConnectHandler(Platform::UniquePtr data); + static void NetworkDrivenDisconnectHandler(Platform::UniquePtr data); + static void ApplicationDrivenDisconnectHandler(Platform::UniquePtr data); + static void PostConnectivityStatusChange(ConnectivityChange changeType); + static void SendRouterSolicitation(System::Layer * layer, void * param); + + // Connection Recovery feature + // This feature allows re-scanning and re-connecting the connection to the known network after + // a reboot or when a connection is lost. The following attempts will occur with increasing interval. + // The connection recovery interval starts from kConnectionRecoveryMinIntervalMs and is doubled + // with each occurrence until reaching kConnectionRecoveryMaxIntervalMs. + // When the connection recovery interval reaches the maximum value the randomized kConnectionRecoveryJitterMs + // from the range [-jitter, +jitter] is added to the value to avoid the periodicity. + // To avoid frequent recovery attempts when the signal to an access point is poor quality + // The connection recovery interval will be cleared after the defined delay in kConnectionRecoveryDelayToReset. + static void Recover(System::Layer * layer, void * param); + void ResetRecoveryTime(); + System::Clock::Milliseconds32 CalculateNextRecoveryTime(); + + ConnectionParams mWiFiParams{}; + ConnectionHandling mHandling; + wifi_iface_state mWiFiState; + wifi_iface_state mCachedWiFiState; + net_mgmt_event_callback mWiFiMgmtClbk{}; + ScanResultCallback mScanResultCallback{ nullptr }; + ScanDoneCallback mScanDoneCallback{ nullptr }; + WiFiNetwork mWantedNetwork{}; + WiFiNetwork mNetworkToScan{}; + bool mInternalScan{ false }; + uint8_t mRouterSolicitationCounter = 0; + bool mSsidFound{ false }; + uint32_t mConnectionRecoveryCounter{ 0 }; + uint32_t mConnectionRecoveryTimeMs{ kConnectionRecoveryMinIntervalMs }; + bool mRecoveryArmed{ false }; + bool mApplicationDisconnectRequested{ false }; + // TODO Workaround for recovery mechanism to wait before the next scan request until the WiFi supplicant is not busy. + static constexpr uint32_t kWifiSupplicantWorkaroundTime = 8000; + + static const Map sStatusMap; + static const Map sEventHandlerMap; +}; + +} // namespace DeviceLayer +} // namespace chip