diff --git a/examples/lighting-app/silabs/SiWx917/.gn b/examples/lighting-app/silabs/SiWx917/.gn new file mode 100644 index 00000000000000..4c078f6acefdcc --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.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 = "freertos" + chip_openthread_ftd = true + + import("//args.gni") +} diff --git a/examples/lighting-app/silabs/SiWx917/BUILD.gn b/examples/lighting-app/silabs/SiWx917/BUILD.gn new file mode 100644 index 00000000000000..3a812b966d3361 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/BUILD.gn @@ -0,0 +1,385 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/efr32_sdk.gni") +import("//build_overrides/pigweed.gni") + +import("${build_root}/config/defaults.gni") +import("${efr32_sdk_build_root}/efr32_executable.gni") +import("${efr32_sdk_build_root}/efr32_sdk.gni") + +import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") +import("${chip_root}/src/platform/device.gni") + +if (chip_enable_pw_rpc) { + import("//build_overrides/pigweed.gni") + import("$dir_pw_build/target_types.gni") +} + +assert(current_os == "freertos") + +efr32_project_dir = "${chip_root}/examples/lighting-app/silabs/efr32" +examples_plat_dir = "${chip_root}/examples/platform/silabs/efr32" +examples_common_plat_dir = "${chip_root}/examples/platform/silabs" + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false + + # Monitor & log memory usage at runtime. + enable_heap_monitoring = false + + # Enable Sleepy end device + enable_sleepy_device = false + + # OTA timeout in seconds + OTA_periodic_query_timeout = 86400 + + # Wifi related stuff - they are overridden by gn -args="use_wf200=true" + use_wf200 = false + use_rs911x = false + use_rs911x_sockets = false + sl_wfx_config_softap = false + sl_wfx_config_scan = true + + # Disable LCD on supported devices + disable_lcd = false + + # Argument to Disable IPv4 for wifi(rs911) + chip_enable_wifi_ipv4 = false + + # Argument to force enable WPA3 security on rs91x + rs91x_wpa3_only = false +} + +declare_args() { + # Enables LCD Qr Code on supported devices + show_qr_code = !disable_lcd +} + +# qr code cannot be true if lcd is disabled +assert(!(disable_lcd && show_qr_code)) + +# Sanity check +assert(!(chip_enable_wifi && chip_enable_openthread)) +assert(!(use_rs911x && chip_enable_openthread)) +assert(!(use_wf200 && chip_enable_openthread)) +if (chip_enable_wifi) { + assert(use_rs911x || use_wf200) + enable_openthread_cli = false + import("${chip_root}/src/platform/silabs/EFR32/wifi_args.gni") +} + +# ThunderBoards, Explorer Kit and MGM240L do not support LCD (No LCD) +if (silabs_board == "BRD4166A" || silabs_board == "BRD2601B" || + silabs_board == "BRD2703A" || silabs_board == "BRD4319A") { + show_qr_code = false + disable_lcd = true +} + +# WiFi settings +if (chip_enable_wifi) { + # disabling LCD for MG24 for wifi + if (silabs_board == "BRD4186A" || silabs_board == "BRD4187A") { + show_qr_code = false + disable_lcd = true + } + wifi_sdk_dir = "${chip_root}/src/platform/silabs/EFR32/wifi" + efr32_lwip_defs = [ "LWIP_NETIF_API=1" ] + if (lwip_ipv4) { + efr32_lwip_defs += [ + "LWIP_IPV4=1", + + # adds following options to provide + # them to .cpp source files + # flags ported from lwipopts file + # TODO: move lwipopts to one location + "LWIP_ARP=1", + "LWIP_ICMP=1", + "LWIP_IGMP=1", + "LWIP_DHCP=1", + "LWIP_DNS=0", + ] + } else { + efr32_lwip_defs += [ "LWIP_IPV4=0" ] + } + if (lwip_ipv6) { + efr32_lwip_defs += [ "LWIP_IPV6=1" ] + } else { + efr32_lwip_defs += [ "LWIP_IPV6=0" ] + } + + if (use_rs911x) { + wiseconnect_sdk_root = + "${chip_root}/third_party/silabs/wiseconnect-wifi-bt-sdk" + import("${examples_plat_dir}/rs911x/rs911x.gni") + } else { + import("${examples_plat_dir}/wf200/wf200.gni") + } +} + +efr32_sdk("sdk") { + sources = [ + "${efr32_project_dir}/include/CHIPProjectConfig.h", + "${examples_plat_dir}/FreeRTOSConfig.h", + ] + + include_dirs = [ + "${chip_root}/src/platform/silabs/EFR32", + "${efr32_project_dir}/include", + "${examples_plat_dir}", + "${chip_root}/src/lib", + "${examples_common_plat_dir}", + ] + + defines = [ + "BOARD_ID=${silabs_board}", + "OTA_PERIODIC_TIMEOUT=${OTA_periodic_query_timeout}", + ] + + if (enable_heap_monitoring) { + defines += [ "HEAP_MONITORING" ] + } + + if (chip_enable_pw_rpc) { + defines += [ + "HAL_VCOM_ENABLE=1", + "PW_RPC_ENABLED", + ] + } + + # WiFi Settings + if (chip_enable_wifi) { + if (use_rs911x) { + defines += rs911x_defs + include_dirs += rs911x_plat_incs + } else if (use_wf200) { + defines += wf200_defs + include_dirs += wf200_plat_incs + } + + if (use_rs911x_sockets) { + include_dirs += [ "${examples_plat_dir}/wifi/rsi-sockets" ] + defines += rs911x_sock_defs + } else { + # Using LWIP instead of the native TCP/IP stack + defines += efr32_lwip_defs + } + + if (sl_wfx_config_softap) { + defines += [ "SL_WFX_CONFIG_SOFTAP" ] + } + if (sl_wfx_config_scan) { + defines += [ "SL_WFX_CONFIG_SCAN" ] + } + } +} + +efr32_executable("lighting_app") { + output_name = "chip-efr32-lighting-example.out" + include_dirs = [ "include" ] + defines = [] + + sources = [ + "${examples_common_plat_dir}/heap_4_silabs.c", + "${examples_plat_dir}/BaseApplication.cpp", + "${examples_plat_dir}/efr32_utils.cpp", + "${examples_plat_dir}/init_efrPlatform.cpp", + "${examples_plat_dir}/matter_config.cpp", + "src/AppTask.cpp", + "src/LightingManager.cpp", + "src/ZclCallbacks.cpp", + "src/main.cpp", + ] + + if (use_wstk_leds) { + sources += [ "${examples_plat_dir}/LEDWidget.cpp" ] + } + + if (chip_enable_pw_rpc || chip_build_libshell || enable_openthread_cli || + use_wf200 || use_rs911x) { + sources += [ "${examples_plat_dir}/uart.cpp" ] + } + + deps = [ + ":sdk", + "${chip_root}/examples/lighting-app/lighting-common", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/src/lib", + "${chip_root}/src/setup_payload", + ] + + # OpenThread Settings + if (chip_enable_openthread) { + deps += [ + "${chip_root}/third_party/openthread:openthread", + "${chip_root}/third_party/openthread:openthread-platform", + "${examples_plat_dir}:efr-matter-shell", + ] + } + + if (chip_enable_ota_requestor) { + defines += [ "EFR32_OTA_ENABLED" ] + sources += [ "${examples_plat_dir}/OTAConfig.cpp" ] + } + + # WiFi Settings + if (chip_enable_wifi) { + if (use_rs911x) { + sources += rs911x_src_plat + + # All the stuff from wiseconnect + sources += rs911x_src_sapi + + # Apparently - the rsi library needs this (though we may not use use it) + sources += rs911x_src_sock + include_dirs += rs911x_inc_plat + + if (use_rs911x_sockets) { + # + # Using native sockets inside RS911x + # + include_dirs += rs911x_sock_inc + } else { + # + # We use LWIP - not built-in sockets + # + sources += rs911x_src_lwip + } + } else if (use_wf200) { + sources += wf200_plat_src + include_dirs += wf200_plat_incs + } + + if (chip_enable_wifi_ipv4) { + defines += [ "CHIP_DEVICE_CONFIG_ENABLE_IPV4" ] + } + + if (rs91x_wpa3_only) { + # TODO: Change this macro once WF200 support is provided + defines += [ "WIFI_ENABLE_SECURITY_WPA3=1" ] + } + } + + if (!disable_lcd) { + sources += [ + "${examples_plat_dir}/display/demo-ui.c", + "${examples_plat_dir}/display/lcd.cpp", + ] + + include_dirs += [ "${examples_plat_dir}/display" ] + defines += [ + "DISPLAY_ENABLED", + "IS_DEMO_LIGHT=1", + ] + if (show_qr_code) { + defines += [ "QR_CODE_ENABLED" ] + + deps += [ "${chip_root}/examples/common/QRCode" ] + } + } + + if (chip_enable_pw_rpc) { + defines += [ + "PW_RPC_ENABLED", + "PW_RPC_ATTRIBUTE_SERVICE=1", + "PW_RPC_BUTTON_SERVICE=1", + "PW_RPC_DESCRIPTOR_SERVICE=1", + "PW_RPC_DEVICE_SERVICE=1", + "PW_RPC_LIGHTING_SERVICE=1", + "PW_RPC_OTCLI_SERVICE=1", + "PW_RPC_THREAD_SERVICE=1", + "PW_RPC_TRACING_SERVICE=1", + ] + + sources += [ + "${chip_root}/examples/common/pigweed/RpcService.cpp", + "${chip_root}/examples/common/pigweed/efr32/PigweedLoggerMutex.cpp", + "${examples_common_plat_dir}/PigweedLogger.cpp", + "${examples_common_plat_dir}/Rpc.cpp", + ] + + deps += [ + "$dir_pw_hdlc:rpc_channel_output", + "$dir_pw_stream:sys_io_stream", + "$dir_pw_trace", + "$dir_pw_trace_tokenized", + "$dir_pw_trace_tokenized:trace_rpc_service", + "${chip_root}/config/efr32/lib/pw_rpc:pw_rpc", + "${chip_root}/examples/common/pigweed:attributes_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:button_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:descriptor_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:device_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:lighting_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:ot_cli_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:thread_service.nanopb_rpc", + "${examples_plat_dir}/pw_sys_io:pw_sys_io_efr32", + ] + + deps += pw_build_LINK_DEPS + + include_dirs += [ + "${chip_root}/examples/common", + "${chip_root}/examples/common/pigweed/efr32", + ] + } + + if (enable_heap_monitoring) { + sources += [ "${examples_common_plat_dir}/MemMonitoring.cpp" ] + defines += [ "HEAP_MONITORING" ] + } + + ldscript = "${examples_plat_dir}/ldscripts/${silabs_family}.ld" + + inputs = [ ldscript ] + + ldflags = [ "-T" + rebase_path(ldscript, root_build_dir) ] + + if (chip_print_memory_usage) { + ldflags += [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } + + # WiFi Settings + if (chip_enable_wifi) { + ldflags += [ + "-Wl,--defsym", + "-Wl,SILABS_WIFI=1", + ] + } + + # Attestation Credentials + if (chip_build_platform_attestation_credentials_provider) { + deps += [ "${examples_plat_dir}:efr32-attestation-credentials" ] + } + + # Factory Data Provider + if (use_efr32_factory_data_provider) { + deps += [ "${examples_plat_dir}:efr32-factory-data-provider" ] + } + + output_dir = root_out_dir +} + +group("efr32") { + deps = [ ":lighting_app" ] +} + +group("default") { + deps = [ ":efr32" ] +} diff --git a/examples/lighting-app/silabs/SiWx917/README.md b/examples/lighting-app/silabs/SiWx917/README.md new file mode 100644 index 00000000000000..ae7565f492c620 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/README.md @@ -0,0 +1,424 @@ +# Matter EFR32 Lighting Example + +An example showing the use of CHIP on the Silicon Labs EFR32 MG12 and MG24. + +
+ +- [Matter EFR32 Lighting Example](#matter-efr32-lighting-example) + - [Introduction](#introduction) + - [Building](#building) + - [Flashing the Application](#flashing-the-application) + - [Viewing Logging Output](#viewing-logging-output) + - [Running the Complete Example](#running-the-complete-example) + - [Notes](#notes) + - [Running RPC console](#running-rpc-console) + - [Device Tracing](#device-tracing) + - [Memory settings](#memory-settings) + - [OTA Software Update](#ota-software-update) + - [Group Communication (Multicast)](#group-communication-multicast) + - [Building options](#building-options) + - [Disabling logging](#disabling-logging) + - [Debug build / release build](#debug-build--release-build) + - [Disabling LCD](#disabling-lcd) + - [KVS maximum entry count](#kvs-maximum-entry-count) + +
+ +> **NOTE:** Silicon Laboratories now maintains a public matter GitHub repo with +> frequent releases thoroughly tested and validated. Developers looking to +> develop matter products with silabs hardware are encouraged to use our latest +> release with added tools and documentation. +> [Silabs Matter Github](https://github.com/SiliconLabs/matter/releases) + + + +## Introduction + +The EFR32 lighting example provides a baseline demonstration of a Light control +device, built using Matter and the Silicon Labs gecko SDK. It can be controlled +by a Chip controller over an Openthread or Wifi network.. + +The EFR32 device can be commissioned over Bluetooth Low Energy where the device +and the Chip controller will exchange security information with the Rendez-vous +procedure. If using Thread, Thread Network credentials are then provided to the +EFR32 device which will then join the Thread network. + +If the LCD is enabled, the LCD on the Silabs WSTK shows a QR Code containing the +needed commissioning information for the BLE connection and starting the +Rendez-vous procedure. + +The lighting example is intended to serve both as a means to explore the +workings of Matter as well as a template for creating real products based on the +Silicon Labs platform. + + + +## Building + +- Download the + [Simplicity Commander](https://www.silabs.com/mcu/programming-options) + command line tool, and ensure that `commander` is your shell search path. + (For Mac OS X, `commander` is located inside + `Commander.app/Contents/MacOS/`.) + +- Download and install a suitable ARM gcc tool chain: + [GNU Arm Embedded Toolchain 9-2019-q4-major](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) + +- Install some additional tools (likely already present for CHIP developers): + + - Linux: `sudo apt-get install git ninja-build` + + - Mac OS X: `brew install ninja` + +- Supported hardware: + + - > For the latest supported hardware please refer to the + > [Hardware Requirements](https://github.com/SiliconLabs/matter/blob/latest/docs/silabs/general/HARDWARE_REQUIREMENTS.md) + > in the Silicon Labs Matter Github Repo + + MG12 boards: + + - BRD4161A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@19dBm + - BRD4162A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@10dBm + - BRD4163A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@10dBm, + 868MHz@19dBm + - BRD4164A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@19dBm + - BRD4166A / SLTB004A / Thunderboard Sense 2 / 2.4GHz@10dBm + - BRD4170A / SLWSTK6000B / Multiband Wireless Starter Kit / 2.4GHz@19dBm, + 915MHz@19dBm + - BRD4304A / SLWSTK6000B / MGM12P Module / 2.4GHz@19dBm + + MG21 boards: Currently not supported due to RAM limitation. + + - BRD4180A / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@20dBm + + MG24 boards : + + - BRD2601B / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@10dBm + - BRD2703A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@10dBm + - BRD4186A / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@10dBm + - BRD4186C / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@10dBm + - BRD4187A / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@20dBm + - BRD4187C / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@20dBm + + MG12 boards: + + - BRD4161A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@19dBm + - BRD4162A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@10dBm + - BRD4163A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@10dBm, + 868MHz@19dBm + - BRD4164A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@19dBm + - BRD4166A / SLTB004A / Thunderboard Sense 2 / 2.4GHz@10dBm + - BRD4170A / SLWSTK6000B / Multiband Wireless Starter Kit / 2.4GHz@19dBm, + 915MHz@19dBm + - BRD4304A / SLWSTK6000B / MGM12P Module / 2.4GHz@19dBm + + MG21 boards: Currently not supported due to RAM limitation. + + - BRD4180A / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@20dBm + + MG24 boards : + + - BRD2601B / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@10dBm + - BRD2703A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@10dBm + - BRD4186A / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@10dBm + - BRD4186C / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@10dBm + - BRD4187A / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@20dBm + - BRD4187C / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@20dBm + +* Build the example application: + + cd ~/connectedhomeip + ./scripts/examples/gn_efr32_example.sh ./examples/lighting-app/efr32/ ./out/lighting-app BRD4161A + +- To delete generated executable, libraries and object files use: + + $ cd ~/connectedhomeip + $ rm -rf ./out/ + + OR use GN/Ninja directly + + $ cd ~/connectedhomeip/examples/lighting-app/efr32 + $ git submodule update --init + $ source third_party/connectedhomeip/scripts/activate.sh + $ export EFR32_BOARD=BRD4161A + $ gn gen out/debug + $ ninja -C out/debug + +- To delete generated executable, libraries and object files use: + + $ cd ~/connectedhomeip/examples/lighting-app/efr32 + $ rm -rf out/ + +* Build the example as Sleepy End Device (SED) + + $ ./scripts/examples/gn_efr32_example.sh ./examples/lighting-app/efr32/ ./out/lighting-app_SED BRD4161A --sed + + or use gn as previously mentioned but adding the following arguments: + + $ gn gen out/debug '--args=silabs_board="BRD4161A" enable_sleepy_device=true chip_openthread_ftd=false' + +* Build the example with pigweed RPC + + $ ./scripts/examples/gn_efr32_example.sh examples/lighting-app/efr32/ out/lighting_app_rpc BRD4161A 'import("//with_pw_rpc.gni")' + + or use GN/Ninja Directly + + $ cd ~/connectedhomeip/examples/lighting-app/efr32 + $ git submodule update --init + $ source third_party/connectedhomeip/scripts/activate.sh + $ export EFR32_BOARD=BRD4161A + $ gn gen out/debug --args='import("//with_pw_rpc.gni")' + $ ninja -C out/debug + + [Running Pigweed RPC console](#running-pigweed-rpc-console) + +For more build options, help is provided when running the build script without +arguments + + ./scripts/examples/gn_efr32_example.sh + + + +## Flashing the Application + +- On the command line: + + $ cd ~/connectedhomeip/examples/lighting-app/efr32 + $ python3 out/debug/chip-efr32-lighting-example.flash.py + +- Or with the Ozone debugger, just load the .out file. + + + +## Viewing Logging Output + +The example application is built to use the SEGGER Real Time Transfer (RTT) +facility for log output. RTT is a feature built-in to the J-Link Interface MCU +on the WSTK development board. It allows bi-directional communication with an +embedded application without the need for a dedicated UART. + +Using the RTT facility requires downloading and installing the _SEGGER J-Link +Software and Documentation Pack_ +([web site](https://www.segger.com/downloads/jlink#J-LinkSoftwareAndDocumentationPack)). + +Alternatively, SEGGER Ozone J-Link debugger can be used to view RTT logs too +after flashing the .out file. + +- Download the J-Link installer by navigating to the appropriate URL and + agreeing to the license agreement. + +- [JLink_Linux_x86_64.deb](https://www.segger.com/downloads/jlink/JLink_Linux_x86_64.deb) +- [JLink_MacOSX.pkg](https://www.segger.com/downloads/jlink/JLink_MacOSX.pkg) + +* Install the J-Link software + + $ cd ~/Downloads + $ sudo dpkg -i JLink_Linux_V*_x86_64.deb + +* In Linux, grant the logged in user the ability to talk to the development + hardware via the linux tty device (/dev/ttyACMx) by adding them to the + dialout group. + + $ sudo usermod -a -G dialout ${USER} + +Once the above is complete, log output can be viewed using the JLinkExe tool in +combination with JLinkRTTClient as follows: + +- Run the JLinkExe tool with arguments to autoconnect to the WSTK board: + + For MG12 use: + + $ JLinkExe -device EFR32MG12PXXXF1024 -if JTAG -speed 4000 -autoconnect 1 + + For MG21 use: + + $ JLinkExe -device EFR32MG21AXXXF1024 -if SWD -speed 4000 -autoconnect 1 + +- In a second terminal, run the JLinkRTTClient to view logs: + + $ JLinkRTTClient + + + +## Running the Complete Example + +- It is assumed here that you already have an OpenThread border router + configured and running. If not see the following guide + [Openthread_border_router](https://github.com/project-chip/connectedhomeip/blob/master/docs/guides/openthread_border_router_pi.md) + for more information on how to setup a border router on a raspberryPi. + + Take note that the RCP code is available directly through + [Simplicity Studio 5](https://www.silabs.com/products/development-tools/software/simplicity-studio/simplicity-studio-5) + under File->New->Project Wizard->Examples->Thread : ot-rcp + +- User interface : **LCD** The LCD on Silabs WSTK shows a QR Code. This QR + Code is be scanned by the CHIP Tool app For the Rendez-vous procedure over + BLE + + * On devices that do not have or support the LCD Display like the BRD4166A Thunderboard Sense 2, + a URL can be found in the RTT logs. + + [SVR] Copy/paste the below URL in a browser to see the QR Code: + [SVR] https://project-chip.github.io/connectedhomeip/qrcode.html?data=CH%3AI34NM%20-00%200C9SS0 + + **LED 0** shows the overall state of the device and its connectivity. The + following states are possible: + + - _Short Flash On (50 ms on/950 ms off)_ ; The device is in the + unprovisioned (unpaired) state and is waiting for a commissioning + application to connect. + + - _Rapid Even Flashing_ ; (100 ms on/100 ms off)_ — The device is in the + unprovisioned state and a commissioning application is connected through + Bluetooth LE. + + - _Short Flash Off_ ; (950ms on/50ms off)_ — The device is fully + provisioned, but does not yet have full Thread network or service + connectivity. + + - _Solid On_ ; The device is fully provisioned and has full Thread + network and service connectivity. + + **LED 1** Simulates the Light The following states are possible: + + - _Solid On_ ; Light is on + - _Off_ ; Light is off + + **Push Button 0** + + - _Press and Release_ : Start, or restart, BLE advertisement in fast mode. It will advertise in this mode + for 30 seconds. The device will then switch to a slower interval advertisement. + After 15 minutes, the advertisement stops. + + - _Pressed and hold for 6 s_ : Initiates the factory reset of the device. + Releasing the button within the 6-second window cancels the factory reset + procedure. **LEDs** blink in unison when the factory reset procedure is + initiated. + + **Push Button 1** Toggles the light state On/Off + +* You can provision and control the Chip device using the python controller, + Chip tool standalone, Android or iOS app + +* You can provision and control the Chip device using the python controller, + Chip tool standalone, Android or iOS app + + [CHIPTool](https://github.com/project-chip/connectedhomeip/blob/master/examples/chip-tool/README.md) + + Here is an example with the CHIPTool: + + chip-tool pairing ble-thread 1 hex: 20202021 3840 + + chip-tool onoff on 1 1 + +### Notes + +- Depending on your network settings your router might not provide native ipv6 + addresses to your devices (Border router / PC). If this is the case, you + need to add a static ipv6 addresses on both device and then an ipv6 route to + the border router on your PC + + - On Border Router: `sudo ip addr add dev 2002::2/64` + + - On PC(Linux): `sudo ip addr add dev 2002::1/64` + + - Add Ipv6 route on PC(Linux) + `sudo ip route add /64 via 2002::2` + + + +## Running RPC console + +- As part of building the example with RPCs enabled the chip_rpc python + interactive console is installed into your venv. The python wheel files are + also created in the output folder: out/debug/chip_rpc_console_wheels. To + install the wheel files without rebuilding: + `pip3 install out/debug/chip_rpc_console_wheels/*.whl` + +- To use the chip-rpc console after it has been installed run: + `chip-console --device /dev/tty. -b 115200 -o //pw_log.out` + +- Then you can simulate a button press or release using the following command + where : idx = 0 or 1 for Button PB0 or PB1 action = 0 for PRESSED, 1 for + RELEASE Test toggling the LED with + `rpcs.chip.rpc.Button.Event(idx=1, pushed=True)` + +- You can also Get and Set the light directly using the RPCs: + `rpcs.chip.rpc.Lighting.Get()` + + `rpcs.chip.rpc.Lighting.Set(on=True, level=128, color=protos.chip.rpc.LightingColor(hue=5, saturation=5))` + +## Device Tracing + +Device tracing is available to analyze the device performance. To turn on +tracing, build with RPC enabled. See Build the example with pigweed RPC. + +Obtain tracing json file. + + $ ./{PIGWEED_REPO}/pw_trace_tokenized/py/pw_trace_tokenized/get_trace.py -d {PORT} -o {OUTPUT_FILE} \ + -t {ELF_FILE} {PIGWEED_REPO}/pw_trace_tokenized/pw_trace_protos/trace_rpc.proto + +## Memory settings + +While most of the RAM usage in CHIP is static, allowing easier debugging and +optimization with symbols analysis, we still need some HEAP for the crypto and +OpenThread. Size of the HEAP can be modified by changing the value of the +`configTOTAL_HEAP_SIZE` define inside of the FreeRTOSConfig.h file of this +example. Please take note that a HEAP size smaller than 13k can and will cause a +Mbedtls failure during the BLE rendez-vous or CASE session + +To track memory usage you can set `enable_heap_monitoring = true` either in the +BUILD.gn file or pass it as a build argument to gn. This will print on the RTT +console the RAM usage of each individual task and the number of Memory +allocation and Free. While this is not extensive monitoring you're welcome to +modify `examples/platform/efr32/MemMonitoring.cpp` to add your own memory +tracking code inside the `trackAlloc` and `trackFree` function + +## OTA Software Update + +For the description of Software Update process with EFR32 example applications +see +[EFR32 OTA Software Update](../../../docs/guides/silabs_efr32_software_update.md) + +## Group Communication (Multicast) + +With this lighting example you can also use group communication to send Lighting +commands to multiples devices at once. Please refer to the +[chip-tool documentation](../../chip-tool/README.md) _Configuring the server +side for Group Commands_ and _Using the Client to Send Group (Multicast) Matter +Commands_ + +## Building options + +All of Silabs's examples within the Matter repo have all the features enabled by +default, as to provide the best end user experience. However some of those +features can easily be toggled on or off. Here is a short list of options to be +passed to the build scripts. + +### Disabling logging + +`chip_progress_logging, chip_detail_logging, chip_automation_logging` + + $ ./scripts/examples/gn_efr32_example.sh ./examples/lighting-app/efr32 ./out/lighting-app BRD4164A "chip_detail_logging=false chip_automation_logging=false chip_progress_logging=false" + +### Debug build / release build + +`is_debug` + + $ ./scripts/examples/gn_efr32_example.sh ./examples/lighting-app/efr32 ./out/lighting-app BRD4164A "is_debug=false" + +### Disabling LCD + +`show_qr_code` + + $ ./scripts/examples/gn_efr32_example.sh ./examples/lighting-app/efr32 ./out/lighting-app BRD4164A "show_qr_code=false" + +### KVS maximum entry count + +`kvs_max_entries` + + Set the maximum Kvs entries that can be stored in NVM (Default 75) + Thresholds: 30 <= kvs_max_entries <= 255 + + $ ./scripts/examples/gn_efr32_example.sh ./examples/lighting-app/efr32 ./out/lighting-app BRD4164A kvs_max_entries=50 diff --git a/examples/lighting-app/silabs/SiWx917/args.gni b/examples/lighting-app/silabs/SiWx917/args.gni new file mode 100644 index 00000000000000..d216faa0a07dae --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/args.gni @@ -0,0 +1,30 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("${chip_root}/config/standalone/args.gni") +import("${chip_root}/src/platform/silabs/EFR32/args.gni") + +efr32_sdk_target = get_label_info(":sdk", "label_no_toolchain") + +chip_enable_ota_requestor = true + +pw_log_BACKEND = "${chip_root}/src/lib/support/pw_log_chip" +pw_assert_BACKEND = "$dir_pw_assert_log:check_backend" +chip_enable_openthread = true +pw_rpc_CONFIG = "$dir_pw_rpc:disable_global_mutex" + +openthread_external_platform = + "${chip_root}/third_party/openthread/platforms/efr32:libopenthread-efr32" diff --git a/examples/lighting-app/silabs/SiWx917/build_for_wifi_args.gni b/examples/lighting-app/silabs/SiWx917/build_for_wifi_args.gni new file mode 100644 index 00000000000000..363d2be9e6f362 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/build_for_wifi_args.gni @@ -0,0 +1,25 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("${chip_root}/config/standalone/args.gni") + +efr32_sdk_target = get_label_info(":sdk", "label_no_toolchain") +chip_enable_openthread = false +import("${chip_root}/src/platform/silabs/EFR32/wifi_args.gni") + +chip_enable_ota_requestor = true + +pw_log_BACKEND = "${chip_root}/src/lib/support/pw_log_chip" +pw_assert_BACKEND = "$dir_pw_assert_log:check_backend" diff --git a/examples/lighting-app/silabs/SiWx917/build_for_wifi_gnfile.gn b/examples/lighting-app/silabs/SiWx917/build_for_wifi_gnfile.gn new file mode 100644 index 00000000000000..d391814190d09f --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/build_for_wifi_gnfile.gn @@ -0,0 +1,28 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.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 = "freertos" + chip_enable_wifi = true + import("//build_for_wifi_args.gni") +} diff --git a/examples/lighting-app/silabs/SiWx917/build_overrides b/examples/lighting-app/silabs/SiWx917/build_overrides new file mode 120000 index 00000000000000..995884e6163eb5 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/build_overrides @@ -0,0 +1 @@ +../../../build_overrides \ No newline at end of file diff --git a/examples/lighting-app/silabs/SiWx917/include/AppConfig.h b/examples/lighting-app/silabs/SiWx917/include/AppConfig.h new file mode 100644 index 00000000000000..ffadaf9706cd2e --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/include/AppConfig.h @@ -0,0 +1,30 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 "efr32_utils.h" + +// ---- Lighting Example App Config ---- + +#define APP_TASK_NAME "Lit" + +// Time it takes in ms for the simulated actuator to move from one +// state to another. +#define ACTUATOR_MOVEMENT_PERIOS_MS 10 diff --git a/examples/lighting-app/silabs/SiWx917/include/AppEvent.h b/examples/lighting-app/silabs/SiWx917/include/AppEvent.h new file mode 100644 index 00000000000000..7a19b719edad25 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/include/AppEvent.h @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * 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 + +struct AppEvent; +typedef void (*EventHandler)(AppEvent *); + +struct AppEvent +{ + enum AppEventTypes + { + kEventType_Button = 0, + kEventType_Timer, + kEventType_Light, + kEventType_Install, + }; + + uint16_t Type; + + union + { + struct + { + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + uint8_t Action; + int32_t Actor; + } LightEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/lighting-app/silabs/SiWx917/include/AppTask.h b/examples/lighting-app/silabs/SiWx917/include/AppTask.h new file mode 100644 index 00000000000000..df80995592fd95 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/include/AppTask.h @@ -0,0 +1,131 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 + +/********************************************************** + * Includes + *********************************************************/ + +#include +#include + +#include "AppEvent.h" +#include "BaseApplication.h" +#include "FreeRTOS.h" +#include "LightingManager.h" +#include "sl_simple_button_instances.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include +#include +#include + +/********************************************************** + * Defines + *********************************************************/ + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) + +/********************************************************** + * AppTask Declaration + *********************************************************/ + +class AppTask : public BaseApplication +{ + +public: + AppTask() = default; + + static AppTask & GetAppTask() { return sAppTask; } + + /** + * @brief AppTask task main loop function + * + * @param pvParameter FreeRTOS task parameter + */ + static void AppTaskMain(void * pvParameter); + + CHIP_ERROR StartAppTask(); + + /** + * @brief Event handler when a button is pressed + * Function posts an event for button processing + * + * @param buttonHandle APP_LIGHT_SWITCH or APP_FUNCTION_BUTTON + * @param btnAction button action - SL_SIMPLE_BUTTON_PRESSED, + * SL_SIMPLE_BUTTON_RELEASED or SL_SIMPLE_BUTTON_DISABLED + */ + void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction) override; + + /** + * @brief Callback called by the identify-server when an identify command is received + * + * @param identify identify structure the command applies on + */ + static void OnIdentifyStart(Identify * identify); + + /** + * @brief Callback called by the identify-server when an identify command is stopped or finished + * + * @param identify identify structure the command applies on + */ + static void OnIdentifyStop(Identify * identify); + + void PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction); + +private: + static AppTask sAppTask; + + static void ActionInitiated(LightingManager::Action_t aAction, int32_t aActor); + static void ActionCompleted(LightingManager::Action_t aAction); + static void LightActionEventHandler(AppEvent * aEvent); + + static void UpdateClusterState(intptr_t context); + + /** + * @brief AppTask initialisation function + * + * @return CHIP_ERROR + */ + CHIP_ERROR Init(); + + /** + * @brief PB0 Button event processing function + * Press and hold will trigger a factory reset timer start + * Press and release will restart BLEAdvertising if not commisionned + * + * @param aEvent button event being processed + */ + static void ButtonHandler(AppEvent * aEvent); + + /** + * @brief PB1 Button event processing function + * Function triggers a switch action sent to the CHIP task + * + * @param aEvent button event being processed + */ + static void SwitchActionEventHandler(AppEvent * aEvent); +}; diff --git a/examples/lighting-app/silabs/SiWx917/include/CHIPProjectConfig.h b/examples/lighting-app/silabs/SiWx917/include/CHIPProjectConfig.h new file mode 100644 index 00000000000000..4b3d8f571c9057 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/include/CHIPProjectConfig.h @@ -0,0 +1,135 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID + * + * 0xFFF1: Test vendor + */ +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID + * + * 0x8005: example lighting app + */ +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8005 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION + * + * The hardware version number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a revision of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software versions. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP service currently expects the software version to be in the format + * {MAJOR_VERSION}.0d{MINOR_VERSION} + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "0.1ALPHA" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION + * + * A uint32_t identifying the software version running on the device. + */ +/* The SoftwareVersion attribute of the Basic cluster. */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 0x0001 +#endif + +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + * + * Enable support for Chip-over-BLE (CHIPoBLE). + */ +#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS + * + * Enable recording UTC timestamps. + */ +#define CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS 1 + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) + +/** + * @def CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL + * + * @brief + * Active retransmit interval, or time to wait before retransmission after + * subsequent failures in milliseconds. + * + * This is the default value, that might be adjusted by end device depending on its + * needs (e.g. sleeping period) using Service Discovery TXT record CRA key. + * + */ +#define CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL (2000_ms32) + +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 diff --git a/examples/lighting-app/silabs/SiWx917/include/LightingManager.h b/examples/lighting-app/silabs/SiWx917/include/LightingManager.h new file mode 100644 index 00000000000000..6d286faa30ef96 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/include/LightingManager.h @@ -0,0 +1,90 @@ +/* + * + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include + +#include + +class LightingManager +{ +public: + enum Action_t + { + ON_ACTION = 0, + OFF_ACTION, + + INVALID_ACTION + } Action; + + enum State_t + { + kState_OffInitiated = 0, + kState_OffCompleted, + kState_OnInitiated, + kState_OnCompleted, + } State; + + CHIP_ERROR Init(); + bool IsLightOn(); + void EnableAutoTurnOff(bool aOn); + void SetAutoTurnOffDuration(uint32_t aDurationInSecs); + bool IsActionInProgress(); + bool InitiateAction(int32_t aActor, Action_t aAction); + + typedef void (*Callback_fn_initiated)(Action_t, int32_t aActor); + typedef void (*Callback_fn_completed)(Action_t); + void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB); + + static void OnTriggerOffWithEffect(OnOffEffect * effect); + +private: + friend LightingManager & LightMgr(void); + State_t mState; + + Callback_fn_initiated mActionInitiated_CB; + Callback_fn_completed mActionCompleted_CB; + + bool mAutoTurnOff; + uint32_t mAutoTurnOffDuration; + bool mAutoTurnOffTimerArmed; + bool mOffEffectArmed; + + void CancelTimer(void); + void StartTimer(uint32_t aTimeoutMs); + + static void TimerEventHandler(TimerHandle_t xTimer); + static void AutoTurnOffTimerEventHandler(AppEvent * aEvent); + static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); + static void OffEffectTimerEventHandler(AppEvent * aEvent); + + static LightingManager sLight; +}; + +inline LightingManager & LightMgr(void) +{ + return LightingManager::sLight; +} diff --git a/examples/lighting-app/silabs/SiWx917/src/AppTask.cpp b/examples/lighting-app/silabs/SiWx917/src/AppTask.cpp new file mode 100644 index 00000000000000..850649df25e27d --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/src/AppTask.cpp @@ -0,0 +1,333 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" +#include "AppConfig.h" +#include "AppEvent.h" + +#ifdef ENABLE_WSTK_LEDS +#include "LEDWidget.h" +#include "sl_simple_led_instances.h" +#endif // ENABLE_WSTK_LEDS + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#ifdef ENABLE_WSTK_LEDS +#define SYSTEM_STATE_LED &sl_led_led0 +#define LIGHT_LED &sl_led_led1 +#endif // ENABLE_WSTK_LEDS + +#define APP_FUNCTION_BUTTON &sl_button_btn0 +#define APP_LIGHT_SWITCH &sl_button_btn1 + +using namespace chip; +using namespace ::chip::DeviceLayer; + +namespace { + +#ifdef ENABLE_WSTK_LEDS +LEDWidget sLightLED; +#endif // ENABLE_WSTK_LEDS + +EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; + +/********************************************************** + * Identify Callbacks + *********************************************************/ + +namespace { +void OnTriggerIdentifyEffectCompleted(chip::System::Layer * systemLayer, void * appState) +{ + ChipLogProgress(Zcl, "Trigger Identify Complete"); + sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; + +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + AppTask::GetAppTask().StopStatusLEDTimer(); +#endif +} +} // namespace + +void OnTriggerIdentifyEffect(Identify * identify) +{ + sIdentifyEffect = identify->mCurrentEffectIdentifier; + + if (identify->mCurrentEffectIdentifier == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE) + { + ChipLogProgress(Zcl, "IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE - Not supported, use effect varriant %d", + identify->mEffectVariant); + sIdentifyEffect = static_cast(identify->mEffectVariant); + } + +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + AppTask::GetAppTask().StartStatusLEDTimer(); +#endif + + switch (sIdentifyEffect) + { + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK: + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE: + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY: + (void) chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(5), OnTriggerIdentifyEffectCompleted, + identify); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_FINISH_EFFECT: + (void) chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerIdentifyEffectCompleted, identify); + (void) chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(1), OnTriggerIdentifyEffectCompleted, + identify); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT: + (void) chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerIdentifyEffectCompleted, identify); + sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; + break; + default: + ChipLogProgress(Zcl, "No identifier effect"); + } +} + +Identify gIdentify = { + chip::EndpointId{ 1 }, + AppTask::GetAppTask().OnIdentifyStart, + AppTask::GetAppTask().OnIdentifyStop, + EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED, + OnTriggerIdentifyEffect, +}; + +} // namespace + +using namespace chip::TLV; +using namespace ::chip::DeviceLayer; + +AppTask AppTask::sAppTask; + +CHIP_ERROR AppTask::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; +#ifdef DISPLAY_ENABLED + GetLCD().Init((uint8_t *) "Lighting-App"); +#endif + + err = BaseApplication::Init(&gIdentify); + if (err != CHIP_NO_ERROR) + { + SILABS_LOG("BaseApplication::Init() failed"); + appError(err); + } + + err = LightMgr().Init(); + if (err != CHIP_NO_ERROR) + { + SILABS_LOG("LightMgr::Init() failed"); + appError(err); + } + + LightMgr().SetCallbacks(ActionInitiated, ActionCompleted); + +#ifdef ENABLE_WSTK_LEDS + sLightLED.Init(LIGHT_LED); + sLightLED.Set(LightMgr().IsLightOn()); +#endif // ENABLE_WSTK_LEDS + + return err; +} + +CHIP_ERROR AppTask::StartAppTask() +{ + return BaseApplication::StartAppTask(AppTaskMain); +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + QueueHandle_t sAppEventQueue = *(static_cast(pvParameter)); + + CHIP_ERROR err = sAppTask.Init(); + if (err != CHIP_NO_ERROR) + { + SILABS_LOG("AppTask.Init() failed"); + appError(err); + } + +#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) + sAppTask.StartStatusLEDTimer(); +#endif + + SILABS_LOG("App Task started"); + + while (true) + { + BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10)); + while (eventReceived == pdTRUE) + { + sAppTask.DispatchEvent(&event); + eventReceived = xQueueReceive(sAppEventQueue, &event, 0); + } + } +} + +void AppTask::OnIdentifyStart(Identify * identify) +{ + ChipLogProgress(Zcl, "onIdentifyStart"); + +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + sAppTask.StartStatusLEDTimer(); +#endif +} + +void AppTask::OnIdentifyStop(Identify * identify) +{ + ChipLogProgress(Zcl, "onIdentifyStop"); + +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + sAppTask.StopStatusLEDTimer(); +#endif +} + +void AppTask::LightActionEventHandler(AppEvent * aEvent) +{ + bool initiated = false; + LightingManager::Action_t action; + int32_t actor; + CHIP_ERROR err = CHIP_NO_ERROR; + + if (aEvent->Type == AppEvent::kEventType_Light) + { + action = static_cast(aEvent->LightEvent.Action); + actor = aEvent->LightEvent.Actor; + } + else if (aEvent->Type == AppEvent::kEventType_Button) + { + action = (LightMgr().IsLightOn()) ? LightingManager::OFF_ACTION : LightingManager::ON_ACTION; + actor = AppEvent::kEventType_Button; + } + else + { + err = APP_ERROR_UNHANDLED_EVENT; + } + + if (err == CHIP_NO_ERROR) + { + initiated = LightMgr().InitiateAction(actor, action); + + if (!initiated) + { + SILABS_LOG("Action is already in progress or active."); + } + } +} + +void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction) +{ + if (buttonHandle == NULL) + { + return; + } + + AppEvent button_event = {}; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.Action = btnAction; + + if (buttonHandle == APP_LIGHT_SWITCH && btnAction == SL_SIMPLE_BUTTON_PRESSED) + { + button_event.Handler = LightActionEventHandler; + sAppTask.PostEvent(&button_event); + } + else if (buttonHandle == APP_FUNCTION_BUTTON) + { + button_event.Handler = BaseApplication::ButtonHandler; + sAppTask.PostEvent(&button_event); + } +} + +void AppTask::ActionInitiated(LightingManager::Action_t aAction, int32_t aActor) +{ + // Action initiated, update the light led + bool lightOn = aAction == LightingManager::ON_ACTION; + SILABS_LOG("Turning light %s", (lightOn) ? "On" : "Off") + +#ifdef ENABLE_WSTK_LEDS + sLightLED.Set(lightOn); +#endif // ENABLE_WSTK_LEDS + +#ifdef DISPLAY_ENABLED + sAppTask.GetLCD().WriteDemoUI(lightOn); +#endif + + if (aActor == AppEvent::kEventType_Button) + { + sAppTask.mSyncClusterToButtonAction = true; + } +} + +void AppTask::ActionCompleted(LightingManager::Action_t aAction) +{ + // action has been completed bon the light + if (aAction == LightingManager::ON_ACTION) + { + SILABS_LOG("Light ON") + } + else if (aAction == LightingManager::OFF_ACTION) + { + SILABS_LOG("Light OFF") + } + + if (sAppTask.mSyncClusterToButtonAction) + { + chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(nullptr)); + sAppTask.mSyncClusterToButtonAction = false; + } +} + +void AppTask::PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Light; + event.LightEvent.Actor = aActor; + event.LightEvent.Action = aAction; + event.Handler = LightActionEventHandler; + PostEvent(&event); +} + +void AppTask::UpdateClusterState(intptr_t context) +{ + uint8_t newValue = LightMgr().IsLightOn(); + + // write the new on/off value + EmberAfStatus status = OnOffServer::Instance().setOnOffValue(1, newValue, false); + + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + SILABS_LOG("ERR: updating on/off %x", status); + } +} diff --git a/examples/lighting-app/silabs/SiWx917/src/LightingManager.cpp b/examples/lighting-app/silabs/SiWx917/src/LightingManager.cpp new file mode 100644 index 00000000000000..31a4ca0ba91e7c --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/src/LightingManager.cpp @@ -0,0 +1,322 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 "LightingManager.h" + +#include "AppConfig.h" +#include "AppTask.h" +#include + +using namespace chip; +using namespace ::chip::DeviceLayer; + +LightingManager LightingManager::sLight; + +TimerHandle_t sLightTimer; + +namespace { + +/********************************************************** + * OffWithEffect Callbacks + *********************************************************/ + +OnOffEffect gEffect = { + chip::EndpointId{ 1 }, + LightMgr().OnTriggerOffWithEffect, + EMBER_ZCL_ON_OFF_EFFECT_IDENTIFIER_DELAYED_ALL_OFF, + static_cast(EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_FADE_TO_OFF_IN_0P8_SECONDS), +}; + +} // namespace + +CHIP_ERROR LightingManager::Init() +{ + // Create FreeRTOS sw timer for light timer. + sLightTimer = xTimerCreate("lightTmr", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = light obj context + TimerEventHandler // timer callback handler + ); + + if (sLightTimer == NULL) + { + SILABS_LOG("sLightTimer timer create failed"); + return APP_ERROR_CREATE_TIMER_FAILED; + } + + bool currentLedState; + // read current on/off value on endpoint one. + chip::DeviceLayer::PlatformMgr().LockChipStack(); + OnOffServer::Instance().getOnOffValue(1, ¤tLedState); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + + mState = currentLedState ? kState_OnCompleted : kState_OffCompleted; + mAutoTurnOffTimerArmed = false; + mAutoTurnOff = false; + mAutoTurnOffDuration = 0; + mOffEffectArmed = false; + + return CHIP_NO_ERROR; +} + +void LightingManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB) +{ + mActionInitiated_CB = aActionInitiated_CB; + mActionCompleted_CB = aActionCompleted_CB; +} + +bool LightingManager::IsActionInProgress() +{ + return (mState == kState_OffInitiated || mState == kState_OnInitiated); +} + +bool LightingManager::IsLightOn() +{ + return (mState == kState_OnCompleted); +} + +void LightingManager::EnableAutoTurnOff(bool aOn) +{ + mAutoTurnOff = aOn; +} + +void LightingManager::SetAutoTurnOffDuration(uint32_t aDurationInSecs) +{ + mAutoTurnOffDuration = aDurationInSecs; +} + +bool LightingManager::InitiateAction(int32_t aActor, Action_t aAction) +{ + bool action_initiated = false; + State_t new_state; + + // Initiate Turn On/Off Action only when the previous one is complete. + if (((mState == kState_OffCompleted) || mOffEffectArmed) && aAction == ON_ACTION) + { + action_initiated = true; + + new_state = kState_OnInitiated; + } + else if (mState == kState_OnCompleted && aAction == OFF_ACTION && mOffEffectArmed == false) + { + action_initiated = true; + + new_state = kState_OffInitiated; + } + + if (action_initiated) + { + if (mAutoTurnOffTimerArmed && new_state == kState_OffInitiated) + { + // If auto turn off timer has been armed and someone initiates turning off, + // cancel the timer and continue as normal. + mAutoTurnOffTimerArmed = false; + + CancelTimer(); + } + + if (mOffEffectArmed && new_state == kState_OnInitiated) + { + CancelTimer(); + mOffEffectArmed = false; + } + + StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS); + + // Since the timer started successfully, update the state and trigger callback + mState = new_state; + + if (mActionInitiated_CB) + { + mActionInitiated_CB(aAction, aActor); + } + } + + return action_initiated; +} + +void LightingManager::StartTimer(uint32_t aTimeoutMs) +{ + if (xTimerIsTimerActive(sLightTimer)) + { + SILABS_LOG("app timer already started!"); + CancelTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sLightTimer, (aTimeoutMs / portTICK_PERIOD_MS), 100) != pdPASS) + { + SILABS_LOG("sLightTimer timer start() failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } +} + +void LightingManager::CancelTimer(void) +{ + if (xTimerStop(sLightTimer, 0) == pdFAIL) + { + SILABS_LOG("sLightTimer stop() failed"); + appError(APP_ERROR_STOP_TIMER_FAILED); + } +} + +void LightingManager::TimerEventHandler(TimerHandle_t xTimer) +{ + // Get light obj context from timer id. + LightingManager * light = static_cast(pvTimerGetTimerID(xTimer)); + + // The timer event handler will be called in the context of the timer task + // once sLightTimer expires. Post an event to apptask queue with the actual handler + // so that the event can be handled in the context of the apptask. + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = light; + if (light->mAutoTurnOffTimerArmed) + { + event.Handler = AutoTurnOffTimerEventHandler; + } + else if (light->mOffEffectArmed) + { + event.Handler = OffEffectTimerEventHandler; + } + else + { + event.Handler = ActuatorMovementTimerEventHandler; + } + AppTask::GetAppTask().PostEvent(&event); +} + +void LightingManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) +{ + LightingManager * light = static_cast(aEvent->TimerEvent.Context); + int32_t actor = AppEvent::kEventType_Timer; + + // Make sure auto turn off timer is still armed. + if (!light->mAutoTurnOffTimerArmed) + { + return; + } + + light->mAutoTurnOffTimerArmed = false; + + SILABS_LOG("Auto Turn Off has been triggered!"); + + light->InitiateAction(actor, OFF_ACTION); +} + +void LightingManager::OffEffectTimerEventHandler(AppEvent * aEvent) +{ + LightingManager * light = static_cast(aEvent->TimerEvent.Context); + int32_t actor = AppEvent::kEventType_Timer; + + // Make sure auto turn off timer is still armed. + if (!light->mOffEffectArmed) + { + return; + } + + light->mOffEffectArmed = false; + + SILABS_LOG("OffEffect completed"); + + light->InitiateAction(actor, OFF_ACTION); +} + +void LightingManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent) +{ + Action_t actionCompleted = INVALID_ACTION; + + LightingManager * light = static_cast(aEvent->TimerEvent.Context); + + if (light->mState == kState_OffInitiated) + { + light->mState = kState_OffCompleted; + actionCompleted = OFF_ACTION; + } + else if (light->mState == kState_OnInitiated) + { + light->mState = kState_OnCompleted; + actionCompleted = ON_ACTION; + } + + if (actionCompleted != INVALID_ACTION) + { + if (light->mActionCompleted_CB) + { + light->mActionCompleted_CB(actionCompleted); + } + + if (light->mAutoTurnOff && actionCompleted == ON_ACTION) + { + // Start the timer for auto turn off + light->StartTimer(light->mAutoTurnOffDuration * 1000); + + light->mAutoTurnOffTimerArmed = true; + + SILABS_LOG("Auto Turn off enabled. Will be triggered in %u seconds", light->mAutoTurnOffDuration); + } + } +} + +void LightingManager::OnTriggerOffWithEffect(OnOffEffect * effect) +{ + chip::app::Clusters::OnOff::OnOffEffectIdentifier effectId = effect->mEffectIdentifier; + uint8_t effectVariant = effect->mEffectVariant; + uint32_t offEffectDuration = 0; + + // Temporary print outs and delay to test OffEffect behaviour + // Until dimming is supported for dev boards. + if (effectId == EMBER_ZCL_ON_OFF_EFFECT_IDENTIFIER_DELAYED_ALL_OFF) + { + if (effectVariant == EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_FADE_TO_OFF_IN_0P8_SECONDS) + { + offEffectDuration = 800; + ChipLogProgress(Zcl, "EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_FADE_TO_OFF_IN_0P8_SECONDS"); + } + else if (effectVariant == EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_NO_FADE) + { + offEffectDuration = 800; + ChipLogProgress(Zcl, "EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_NO_FADE"); + } + else if (effectVariant == + EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_50_PERCENT_DIM_DOWN_IN_0P8_SECONDS_THEN_FADE_TO_OFF_IN_12_SECONDS) + { + offEffectDuration = 12800; + ChipLogProgress(Zcl, + "EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_50_PERCENT_DIM_DOWN_IN_0P8_SECONDS_THEN_FADE_TO_OFF_" + "IN_12_SECONDS"); + } + } + else if (effectId == EMBER_ZCL_ON_OFF_EFFECT_IDENTIFIER_DYING_LIGHT) + { + if (effectVariant == + EMBER_ZCL_ON_OFF_DYING_LIGHT_EFFECT_VARIANT_20_PERCENTER_DIM_UP_IN_0P5_SECONDS_THEN_FADE_TO_OFF_IN_1_SECOND) + { + offEffectDuration = 1500; + ChipLogProgress( + Zcl, "EMBER_ZCL_ON_OFF_DYING_LIGHT_EFFECT_VARIANT_20_PERCENTER_DIM_UP_IN_0P5_SECONDS_THEN_FADE_TO_OFF_IN_1_SECOND"); + } + } + + LightMgr().mOffEffectArmed = true; + LightMgr().StartTimer(offEffectDuration); +} diff --git a/examples/lighting-app/silabs/SiWx917/src/ZclCallbacks.cpp b/examples/lighting-app/silabs/SiWx917/src/ZclCallbacks.cpp new file mode 100644 index 00000000000000..cfbcbc8a191411 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/src/ZclCallbacks.cpp @@ -0,0 +1,91 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file implements the handler for data model messages. + */ + +#include "AppConfig.h" +#include "LightingManager.h" + +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::app::Clusters; + +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, + uint8_t * value) +{ + ClusterId clusterId = attributePath.mClusterId; + AttributeId attributeId = attributePath.mAttributeId; + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); + + if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) + { + LightMgr().InitiateAction(AppEvent::kEventType_Light, *value ? LightingManager::ON_ACTION : LightingManager::OFF_ACTION); + } + else if (clusterId == LevelControl::Id) + { + ChipLogProgress(Zcl, "Level Control attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + + // WIP Apply attribute change to Light + } + else if (clusterId == ColorControl::Id) + { + ChipLogProgress(Zcl, "Color Control attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + + // WIP Apply attribute change to Light + } + else if (clusterId == OnOffSwitchConfiguration::Id) + { + ChipLogProgress(Zcl, "OnOff Switch Configuration attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + + // WIP Apply attribute change to Light + } + else if (clusterId == Identify::Id) + { + ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + } +} + +/** @brief OnOff Cluster Init + * + * This function is called when a specific cluster is initialized. It gives the + * application an opportunity to take care of cluster initialization procedures. + * It is called exactly once for each endpoint where cluster is present. + * + * @param endpoint Ver.: always + * + * TODO Issue #3841 + * emberAfOnOffClusterInitCallback happens before the stack initialize the cluster + * attributes to the default value. + * The logic here expects something similar to the deprecated Plugins callback + * emberAfPluginOnOffClusterServerPostInitCallback. + * + */ +void emberAfOnOffClusterInitCallback(EndpointId endpoint) +{ + // TODO: implement any additional Cluster Server init actions +} diff --git a/examples/lighting-app/silabs/SiWx917/src/main.cpp b/examples/lighting-app/silabs/SiWx917/src/main.cpp new file mode 100644 index 00000000000000..2594f6f9216e78 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/src/main.cpp @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "AppConfig.h" +#include "init_efrPlatform.h" +#include "sl_simple_button_instances.h" +#include "sl_system_kernel.h" +#include +#include +#include +#include +#ifdef EFR32_ATTESTATION_CREDENTIALS +#include +#else +#include +#endif + +#define BLE_DEV_NAME "SiLabs-Light" +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +using namespace ::chip::Credentials; + +#define UNUSED_PARAMETER(a) (a = a) + +volatile int apperror_cnt; +static chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; + +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + init_efrPlatform(); + if (EFR32MatterConfig::InitMatter(BLE_DEV_NAME) != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + gExampleDeviceInfoProvider.SetStorageDelegate(&chip::Server::GetInstance().GetPersistentStorage()); + chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); + + chip::DeviceLayer::PlatformMgr().LockChipStack(); + // Initialize device attestation config +#ifdef EFR32_ATTESTATION_CREDENTIALS + SetDeviceAttestationCredentialsProvider(Silabs::GetSilabsDacProvider()); +#else + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); +#endif + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + + SILABS_LOG("Starting App Task"); + if (AppTask::GetAppTask().StartAppTask() != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + SILABS_LOG("Starting FreeRTOS scheduler"); + sl_system_kernel_start(); + + // Should never get here. + chip::Platform::MemoryShutdown(); + SILABS_LOG("vTaskStartScheduler() failed"); + appError(CHIP_ERROR_INTERNAL); +} + +void sl_button_on_change(const sl_button_t * handle) +{ + AppTask::GetAppTask().ButtonEventHandler(handle, sl_button_get_state(handle)); +} diff --git a/examples/lighting-app/silabs/SiWx917/third_party/connectedhomeip b/examples/lighting-app/silabs/SiWx917/third_party/connectedhomeip new file mode 120000 index 00000000000000..59307833b4fee9 --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../.. \ No newline at end of file diff --git a/examples/lighting-app/silabs/SiWx917/with_pw_rpc.gni b/examples/lighting-app/silabs/SiWx917/with_pw_rpc.gni new file mode 100644 index 00000000000000..40a8bb79d84b6a --- /dev/null +++ b/examples/lighting-app/silabs/SiWx917/with_pw_rpc.gni @@ -0,0 +1,31 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# add this gni as import in your build args to use pigweed in the example +# 'import("//with_pw_rpc.gni")' + +import("//build_overrides/chip.gni") +import("${chip_root}/config/efr32/lib/pw_rpc/pw_rpc.gni") +import("${chip_root}/examples/platform/silabs/efr32/args.gni") + +efr32_sdk_target = get_label_info(":sdk", "label_no_toolchain") + +chip_enable_pw_rpc = true +chip_enable_openthread = true +chip_build_pw_trace_lib = true + +cpp_standard = "gnu++17" + +# Light app on EFR enables tracing server +pw_trace_BACKEND = "$dir_pw_trace_tokenized" diff --git a/examples/platform/silabs/SiWx917/BUILD.gn b/examples/platform/silabs/SiWx917/BUILD.gn new file mode 100644 index 00000000000000..dbd8473a6c89de --- /dev/null +++ b/examples/platform/silabs/SiWx917/BUILD.gn @@ -0,0 +1,110 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/efr32_sdk.gni") +import("${chip_root}/src/lib/lib.gni") +import("${chip_root}/src/platform/device.gni") +import("${efr32_sdk_build_root}/efr32_sdk.gni") + +config("chip_examples_project_config") { + include_dirs = [ "project_include" ] + + # Link options that provide a replacement for dynamic memory operations in standard + # library with the FreeRTOS malloc in platform code. + ldflags = [ + # memory allocation -- these must be re-entrant and do locking + "-Wl,--wrap=malloc", + "-Wl,--wrap=free", + "-Wl,--wrap=realloc", + "-Wl,--wrap=calloc", + "-Wl,--wrap=MemoryAlloc", + + # Wrap these in case internal newlib call them (e.g. strdup will) + # directly call _malloc_r) + "-Wl,--wrap=_malloc_r", + "-Wl,--wrap=_realloc_r", + "-Wl,--wrap=_free_r", + "-Wl,--wrap=_calloc_r", + ] +} + +source_set("openthread_core_config_efr32_chip_examples") { + if (chip_enable_openthread) { + sources = [ "project_include/OpenThreadConfig.h" ] + + public_deps = [ "${efr32_sdk_build_root}:efr32_sdk" ] + + if (use_silabs_thread_lib) { + public_deps += [ "${efr32_sdk_build_root}:openthread_core_config_efr32" ] + } else { + public_deps += [ "${chip_root}/third_party/openthread/platforms/efr32:openthread_core_config_efr32" ] + } + + public_configs = [ ":chip_examples_project_config" ] + } +} + +source_set("efr-matter-shell") { + if (chip_build_libshell) { + defines = [ "ENABLE_CHIP_SHELL" ] + + sources = [ "matter_shell.cpp" ] + include_dirs = [ "." ] + + public_deps = [ + "${chip_root}/examples/shell/shell_common:shell_common", + "${chip_root}/src/lib/shell:shell", + "${chip_root}/src/lib/shell:shell_core", + ] + } +} + +config("attestation-credentials-config") { + include_dirs = [ "${chip_root}" ] + + defines = [ + # Set to 1 to enable EFR32 attestation credentials + "EFR32_ATTESTATION_CREDENTIALS", + ] +} + +source_set("efr32-attestation-credentials") { + sources = [ + "../SilabsDeviceAttestationCreds.cpp", + "../SilabsDeviceAttestationCreds.h", + ] + + public_deps = [ + "${chip_root}/src/credentials", + "${chip_root}/src/platform:platform_base", + ] + + public_configs = [ ":attestation-credentials-config" ] +} + +source_set("efr32-factory-data-provider") { + sources = [ + "EFR32DeviceDataProvider.cpp", + "EFR32DeviceDataProvider.h", + ] + + public_deps = [ + "${chip_root}/src/credentials", + "${chip_root}/src/platform:platform_base", + "${chip_root}/src/setup_payload", + ] + + #public_configs = [ "" ] +} diff --git a/examples/platform/silabs/SiWx917/BaseApplication.cpp b/examples/platform/silabs/SiWx917/BaseApplication.cpp new file mode 100644 index 00000000000000..85748b35359d3f --- /dev/null +++ b/examples/platform/silabs/SiWx917/BaseApplication.cpp @@ -0,0 +1,571 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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. + */ + +/********************************************************** + * Includes + *********************************************************/ + +#include "AppConfig.h" +#include "AppEvent.h" +#include "AppTask.h" + +#ifdef ENABLE_WSTK_LEDS +#include "LEDWidget.h" +#include "sl_simple_led_instances.h" +#endif // ENABLE_WSTK_LEDS + +#ifdef DISPLAY_ENABLED +#include "lcd.h" +#ifdef QR_CODE_ENABLED +#include "qrcodegen.h" +#endif // QR_CODE_ENABLED +#endif // DISPLAY_ENABLED + +#include "EFR32DeviceDataProvider.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if CHIP_ENABLE_OPENTHREAD +#include +#include +#include +#endif // CHIP_ENABLE_OPENTHREAD + +#ifdef SL_WIFI +#include "wfx_host_events.h" +#include +#include +#endif // SL_WIFI + +/********************************************************** + * Defines and Constants + *********************************************************/ + +#define FACTORY_RESET_TRIGGER_TIMEOUT 3000 +#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 +#ifndef APP_TASK_STACK_SIZE +#define APP_TASK_STACK_SIZE (4096) +#endif +#define APP_TASK_PRIORITY 2 +#define APP_EVENT_QUEUE_SIZE 10 +#define EXAMPLE_VENDOR_ID 0xcafe + +#ifdef ENABLE_WSTK_LEDS +#define SYSTEM_STATE_LED &sl_led_led0 +#endif // ENABLE_WSTK_LEDS + +#define APP_FUNCTION_BUTTON &sl_button_btn0 + +using namespace chip; +using namespace ::chip::DeviceLayer; + +namespace { + +/********************************************************** + * Variable declarations + *********************************************************/ + +TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. +TimerHandle_t sLightTimer; + +TaskHandle_t sAppTaskHandle; +QueueHandle_t sAppEventQueue; + +#ifdef ENABLE_WSTK_LEDS +LEDWidget sStatusLED; +#endif // ENABLE_WSTK_LEDS + +#ifdef SL_WIFI +app::Clusters::NetworkCommissioning::Instance + sWiFiNetworkCommissioningInstance(0 /* Endpoint Id */, &(NetworkCommissioning::SlWiFiDriver::GetInstance())); +#endif /* SL_WIFI */ + +#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) + +bool sIsProvisioned = false; +bool sIsEnabled = false; +bool sIsAttached = false; +bool sHaveBLEConnections = false; + +#endif // CHIP_DEVICE_CONFIG_ENABLE_SED + +EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; + +uint8_t sAppEventQueueBuffer[APP_EVENT_QUEUE_SIZE * sizeof(AppEvent)]; +StaticQueue_t sAppEventQueueStruct; + +StackType_t appStack[APP_TASK_STACK_SIZE / sizeof(StackType_t)]; +StaticTask_t appTaskStruct; + +BaseApplication::Function_t mFunction; +bool mFunctionTimerActive; + +Identify * gIdentifyptr = nullptr; + +#ifdef DISPLAY_ENABLED +SilabsLCD slLCD; +#endif + +} // namespace + +/********************************************************** + * AppTask Definitions + *********************************************************/ + +CHIP_ERROR BaseApplication::StartAppTask(TaskFunction_t taskFunction) +{ + sAppEventQueue = xQueueCreateStatic(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent), sAppEventQueueBuffer, &sAppEventQueueStruct); + if (sAppEventQueue == NULL) + { + SILABS_LOG("Failed to allocate app event queue"); + appError(APP_ERROR_EVENT_QUEUE_FAILED); + } + + // Start App task. + sAppTaskHandle = + xTaskCreateStatic(taskFunction, APP_TASK_NAME, ArraySize(appStack), &sAppEventQueue, 1, appStack, &appTaskStruct); + if (sAppTaskHandle == nullptr) + { + SILABS_LOG("Failed to create app task"); + appError(APP_ERROR_CREATE_TASK_FAILED); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR BaseApplication::Init(Identify * identifyObj) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + if (identifyObj == nullptr) + { + SILABS_LOG("Invalid Identify Object!"); + appError(CHIP_ERROR_INVALID_ARGUMENT); + } + + gIdentifyptr = identifyObj; + +#ifdef SL_WIFI + /* + * Wait for the WiFi to be initialized + */ + SILABS_LOG("APP: Wait WiFi Init"); + while (!wfx_hw_ready()) + { + vTaskDelay(10); + } + SILABS_LOG("APP: Done WiFi Init"); + /* We will init server when we get IP */ + + sWiFiNetworkCommissioningInstance.Init(); +#endif + + // Create FreeRTOS sw timer for Function Selection. + sFunctionTimer = xTimerCreate("FnTmr", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = app task obj context + FunctionTimerEventHandler // timer callback handler + ); + if (sFunctionTimer == NULL) + { + SILABS_LOG("funct timer create failed"); + appError(APP_ERROR_CREATE_TIMER_FAILED); + } + + // Create FreeRTOS sw timer for LED Management. + sLightTimer = xTimerCreate("LightTmr", // Text Name + 10, // Default timer period (mS) + true, // reload timer + (void *) this, // Timer Id + LightTimerEventHandler // Timer callback handler + ); + if (sLightTimer == NULL) + { + SILABS_LOG("Light Timer create failed"); + appError(APP_ERROR_CREATE_TIMER_FAILED); + } + + SILABS_LOG("Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + +#ifdef ENABLE_WSTK_LEDS + LEDWidget::InitGpio(); + sStatusLED.Init(SYSTEM_STATE_LED); +#endif // ENABLE_WSTK_LEDS + + ConfigurationMgr().LogDeviceConfig(); + + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); + + if (EFR32::EFR32DeviceDataProvider::GetDeviceDataProvider().GetSetupPayload(QRCode) == CHIP_NO_ERROR) + { + // Print setup info on LCD if available +#ifdef QR_CODE_ENABLED + slLCD.SetQRCode((uint8_t *) QRCode.data(), QRCode.size()); + slLCD.ShowQRCode(true, true); +#else + PrintQrCodeURL(QRCode); +#endif // QR_CODE_ENABLED + } + else + { + SILABS_LOG("Getting QR code failed!"); + } + + return err; +} + +void BaseApplication::FunctionTimerEventHandler(TimerHandle_t xTimer) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = (void *) xTimer; + event.Handler = FunctionEventHandler; + PostEvent(&event); +} + +void BaseApplication::FunctionEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + + // If we reached here, the button was held past FACTORY_RESET_TRIGGER_TIMEOUT, + // initiate factory reset + if (mFunctionTimerActive && mFunction == kFunction_StartBleAdv) + { + SILABS_LOG("Factory Reset Triggered. Release button within %ums to cancel.", FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); + + // Start timer for FACTORY_RESET_CANCEL_WINDOW_TIMEOUT to allow user to + // cancel, if required. + StartFunctionTimer(FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); + +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + StartStatusLEDTimer(); +#endif // CHIP_DEVICE_CONFIG_ENABLE_SED + + mFunction = kFunction_FactoryReset; + +#ifdef ENABLE_WSTK_LEDS + // Turn off all LEDs before starting blink to make sure blink is + // co-ordinated. + sStatusLED.Set(false); + sStatusLED.Blink(500); +#endif // ENABLE_WSTK_LEDS + } + else if (mFunctionTimerActive && mFunction == kFunction_FactoryReset) + { + // Actually trigger Factory Reset + mFunction = kFunction_NoneSelected; + +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + StopStatusLEDTimer(); +#endif // CHIP_DEVICE_CONFIG_ENABLE_SED + + chip::Server::GetInstance().ScheduleFactoryReset(); + } +} + +void BaseApplication::LightEventHandler() +{ + // Collect connectivity and configuration state from the CHIP stack. Because + // the CHIP event loop is being run in a separate task, the stack must be + // locked while these values are queried. However we use a non-blocking + // lock request (TryLockCHIPStack()) to avoid blocking other UI activities + // when the CHIP task is busy (e.g. with a long crypto operation). +#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) + if (PlatformMgr().TryLockChipStack()) + { +#ifdef SL_WIFI + sIsProvisioned = ConnectivityMgr().IsWiFiStationProvisioned(); + sIsEnabled = ConnectivityMgr().IsWiFiStationEnabled(); + sIsAttached = ConnectivityMgr().IsWiFiStationConnected(); +#endif /* SL_WIFI */ +#if CHIP_ENABLE_OPENTHREAD + sIsProvisioned = ConnectivityMgr().IsThreadProvisioned(); + sIsEnabled = ConnectivityMgr().IsThreadEnabled(); + sIsAttached = ConnectivityMgr().IsThreadAttached(); +#endif /* CHIP_ENABLE_OPENTHREAD */ + sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); + PlatformMgr().UnlockChipStack(); + } +#endif // CHIP_DEVICE_CONFIG_ENABLE_SED + + // Update the status LED if factory reset has not been initiated. + // + // If system has "full connectivity", keep the LED On constantly. + // + // If thread and service provisioned, but not attached to the thread network + // yet OR no connectivity to the service OR subscriptions are not fully + // established THEN blink the LED Off for a short period of time. + // + // If the system has ble connection(s) uptill the stage above, THEN blink + // the LEDs at an even rate of 100ms. + // + // Otherwise, blink the LED ON for a very short time. + if (mFunction != kFunction_FactoryReset) + { + if ((gIdentifyptr != nullptr) && (gIdentifyptr->mActive)) + { +#ifdef ENABLE_WSTK_LEDS + sStatusLED.Blink(250, 250); +#endif // ENABLE_WSTK_LEDS + } + else if (sIdentifyEffect != EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT) + { + if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK) + { +#ifdef ENABLE_WSTK_LEDS + sStatusLED.Blink(50, 50); +#endif // ENABLE_WSTK_LEDS + } + if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE) + { +#ifdef ENABLE_WSTK_LEDS + sStatusLED.Blink(1000, 1000); +#endif // ENABLE_WSTK_LEDS + } + if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY) + { +#ifdef ENABLE_WSTK_LEDS + sStatusLED.Blink(300, 700); +#endif // ENABLE_WSTK_LEDS + } + } +#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) + else if (sIsProvisioned && sIsEnabled) + { + if (sIsAttached) + { +#ifdef ENABLE_WSTK_LEDS + sStatusLED.Set(true); +#endif // ENABLE_WSTK_LEDS + } + else + { +#ifdef ENABLE_WSTK_LEDS + sStatusLED.Blink(950, 50); +#endif + } + } + else if (sHaveBLEConnections) + { +#ifdef ENABLE_WSTK_LEDS + sStatusLED.Blink(100, 100); +#endif // ENABLE_WSTK_LEDS + } + else + { +#ifdef ENABLE_WSTK_LEDS + sStatusLED.Blink(50, 950); +#endif // ENABLE_WSTK_LEDS + } +#endif // CHIP_DEVICE_CONFIG_ENABLE_SED + } + +#ifdef ENABLE_WSTK_LEDS + sStatusLED.Animate(); +#endif // ENABLE_WSTK_LEDS +} + +void BaseApplication::ButtonHandler(AppEvent * aEvent) +{ + // To trigger software update: press the APP_FUNCTION_BUTTON button briefly (< + // FACTORY_RESET_TRIGGER_TIMEOUT) To initiate factory reset: press the + // APP_FUNCTION_BUTTON for FACTORY_RESET_TRIGGER_TIMEOUT + + // FACTORY_RESET_CANCEL_WINDOW_TIMEOUT All LEDs start blinking after + // FACTORY_RESET_TRIGGER_TIMEOUT to signal factory reset has been initiated. + // To cancel factory reset: release the APP_FUNCTION_BUTTON once all LEDs + // start blinking within the FACTORY_RESET_CANCEL_WINDOW_TIMEOUT + if (aEvent->ButtonEvent.Action == SL_SIMPLE_BUTTON_PRESSED) + { + if (!mFunctionTimerActive && mFunction == kFunction_NoneSelected) + { + StartFunctionTimer(FACTORY_RESET_TRIGGER_TIMEOUT); + mFunction = kFunction_StartBleAdv; + } + } + else + { + // If the button was released before factory reset got initiated, open the commissioning window and start BLE advertissement + // in fast mode + if (mFunctionTimerActive && mFunction == kFunction_StartBleAdv) + { + CancelFunctionTimer(); + mFunction = kFunction_NoneSelected; + +#ifdef QR_CODE_ENABLED + // TOGGLE QRCode/LCD demo UI + slLCD.ToggleQRCode(); +#endif + +#ifdef SL_WIFI + if (!ConnectivityMgr().IsWiFiStationProvisioned()) +#else + if (!ConnectivityMgr().IsThreadProvisioned()) +#endif /* !SL_WIFI */ + { + // Open Basic CommissioningWindow. Will start BLE advertisements + chip::DeviceLayer::PlatformMgr().LockChipStack(); + CHIP_ERROR err = chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + if (err != CHIP_NO_ERROR) + { + SILABS_LOG("Failed to open the Basic Commissioning Window"); + } + } + else { SILABS_LOG("Network is already provisioned, Ble advertissement not enabled"); } + } + else if (mFunctionTimerActive && mFunction == kFunction_FactoryReset) + { + CancelFunctionTimer(); + +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + StopStatusLEDTimer(); +#endif + + // Change the function to none selected since factory reset has been + // canceled. + mFunction = kFunction_NoneSelected; + SILABS_LOG("Factory Reset has been Canceled"); + } + } +} + +void BaseApplication::CancelFunctionTimer() +{ + if (xTimerStop(sFunctionTimer, 0) == pdFAIL) + { + SILABS_LOG("app timer stop() failed"); + appError(APP_ERROR_STOP_TIMER_FAILED); + } + + mFunctionTimerActive = false; +} + +void BaseApplication::StartFunctionTimer(uint32_t aTimeoutInMs) +{ + if (xTimerIsTimerActive(sFunctionTimer)) + { + SILABS_LOG("app timer already started!"); + CancelFunctionTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sFunctionTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) + { + SILABS_LOG("app timer start() failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } + + mFunctionTimerActive = true; +} + +void BaseApplication::StartStatusLEDTimer() +{ + if (pdPASS != xTimerStart(sLightTimer, 0)) + { + SILABS_LOG("Light Time start failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } +} + +void BaseApplication::StopStatusLEDTimer() +{ +#ifdef ENABLE_WSTK_LEDS + sStatusLED.Set(false); +#endif // ENABLE_WSTK_LEDS + + if (xTimerStop(sLightTimer, 100) != pdPASS) + { + SILABS_LOG("Light Time start failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } +} + +void BaseApplication::LightTimerEventHandler(TimerHandle_t xTimer) +{ + LightEventHandler(); +} + +#ifdef DISPLAY_ENABLED +SilabsLCD & BaseApplication::GetLCD(void) +{ + return slLCD; +} +#endif + +void BaseApplication::PostEvent(const AppEvent * aEvent) +{ + if (sAppEventQueue != NULL) + { + BaseType_t status; + if (xPortIsInsideInterrupt()) + { + BaseType_t higherPrioTaskWoken = pdFALSE; + status = xQueueSendFromISR(sAppEventQueue, aEvent, &higherPrioTaskWoken); + +#ifdef portYIELD_FROM_ISR + portYIELD_FROM_ISR(higherPrioTaskWoken); +#elif portEND_SWITCHING_ISR // portYIELD_FROM_ISR or portEND_SWITCHING_ISR + portEND_SWITCHING_ISR(higherPrioTaskWoken); +#else // portYIELD_FROM_ISR or portEND_SWITCHING_ISR +#error "Must have portYIELD_FROM_ISR or portEND_SWITCHING_ISR" +#endif // portYIELD_FROM_ISR or portEND_SWITCHING_ISR + } + else + { + status = xQueueSend(sAppEventQueue, aEvent, 1); + } + + if (!status) + { + SILABS_LOG("Failed to post event to app task event queue"); + } + } + else + { + SILABS_LOG("Event Queue is NULL should never happen"); + } +} + +void BaseApplication::DispatchEvent(AppEvent * aEvent) +{ + if (aEvent->Handler) + { + aEvent->Handler(aEvent); + } + else + { + SILABS_LOG("Event received with no handler. Dropping event."); + } +} diff --git a/examples/platform/silabs/SiWx917/BaseApplication.h b/examples/platform/silabs/SiWx917/BaseApplication.h new file mode 100644 index 00000000000000..febd7aa68591b2 --- /dev/null +++ b/examples/platform/silabs/SiWx917/BaseApplication.h @@ -0,0 +1,186 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 + +/********************************************************** + * Includes + *********************************************************/ + +#include +#include + +#include "AppEvent.h" +#include "FreeRTOS.h" +#include "sl_simple_button_instances.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include +#include +#include + +#ifdef DISPLAY_ENABLED +#include "demo-ui.h" +#include "lcd.h" +#ifdef QR_CODE_ENABLED +#include "qrcodegen.h" +#endif // QR_CODE_ENABLED +#endif // DISPLAY_ENABLED + +/********************************************************** + * Defines + *********************************************************/ + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) + +/********************************************************** + * BaseApplication Declaration + *********************************************************/ + +class BaseApplication +{ + +public: + BaseApplication() = default; + virtual ~BaseApplication(){}; + + /** + * @brief Create AppTask task and Event Queue + * If an error occurs during creation, application will hang after printing out error code + * + * @return CHIP_ERROR CHIP_NO_ERROR if no errors + */ + CHIP_ERROR StartAppTask(TaskFunction_t taskFunction); + + /** + * @brief PostEvent function that add event to AppTask queue for processing + * + * @param event AppEvent to post + */ + static void PostEvent(const AppEvent * event); + +#ifdef DISPLAY_ENABLED + /** + * @brief Return LCD object + */ + static SilabsLCD & GetLCD(void); +#endif + + /** + * @brief Event handler when a button is pressed + * Function posts an event for button processing + * + * @param buttonHandle APP_LIGHT_SWITCH or APP_FUNCTION_BUTTON + * @param btnAction button action - SL_SIMPLE_BUTTON_PRESSED, + * SL_SIMPLE_BUTTON_RELEASED or SL_SIMPLE_BUTTON_DISABLED + */ + virtual void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction) = 0; + + /** + * @brief Function called to start the LED light timer + */ + static void StartStatusLEDTimer(void); + + /** + * @brief Function to stop LED light timer + * Turns off Status LED before stopping timer + */ + static void StopStatusLEDTimer(void); + + enum Function_t + { + kFunction_NoneSelected = 0, + kFunction_SoftwareUpdate = 0, + kFunction_StartBleAdv = 1, + kFunction_FactoryReset = 2, + + kFunction_Invalid + } Function; + +protected: + CHIP_ERROR Init(Identify * identifyObj); + + /** + * @brief Function called to start the function timer + * + * @param aTimeoutMs timer duration in ms + */ + static void StartFunctionTimer(uint32_t aTimeoutMs); + + /** + * @brief Function to stop function timer + */ + static void CancelFunctionTimer(void); + + /** + * @brief Function call event callback function for processing + * + * @param event triggered event to be processed + */ + void DispatchEvent(AppEvent * event); + + /** + * @brief Function Timer finished callback function + * Post an FunctionEventHandler event + * + * @param xTimer timer that finished + */ + static void FunctionTimerEventHandler(TimerHandle_t xTimer); + + /** + * @brief Timer Event processing function + * Trigger factory if Press and Hold duration is respected + * + * @param aEvent post event being processed + */ + static void FunctionEventHandler(AppEvent * aEvent); + + /** + * @brief PB0 Button event processing function + * Press and hold will trigger a factory reset timer start + * Press and release will restart BLEAdvertising if not commisionned + * + * @param aEvent button event being processed + */ + static void ButtonHandler(AppEvent * aEvent); + + /** + * @brief Light Timer finished callback function + * Calls LED processing function + * + * @param xTimer timer that finished + */ + static void LightTimerEventHandler(TimerHandle_t xTimer); + + /** + * @brief Updates device LEDs + */ + static void LightEventHandler(); + + /********************************************************** + * Protected Attributes declaration + *********************************************************/ + bool mSyncClusterToButtonAction; +}; diff --git a/examples/platform/silabs/SiWx917/EFR32DeviceDataProvider.cpp b/examples/platform/silabs/SiWx917/EFR32DeviceDataProvider.cpp new file mode 100644 index 00000000000000..6e097ffa4db0e2 --- /dev/null +++ b/examples/platform/silabs/SiWx917/EFR32DeviceDataProvider.cpp @@ -0,0 +1,335 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "EFR32DeviceDataProvider.h" +#include +#include +#include +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace EFR32 { + +// using namespace chip::Credentials; +using namespace chip::DeviceLayer::Internal; + +CHIP_ERROR EFR32DeviceDataProvider::GetSetupDiscriminator(uint16_t & setupDiscriminator) +{ + CHIP_ERROR err; + uint32_t setupDiscriminator32; + + err = SILABSConfig::ReadConfigValue(SILABSConfig::kConfigKey_SetupDiscriminator, setupDiscriminator32); +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + setupDiscriminator32 = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR; + err = CHIP_NO_ERROR; + } +#endif // defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR + + VerifyOrReturnLogError(setupDiscriminator32 <= kMaxDiscriminatorValue, CHIP_ERROR_INVALID_ARGUMENT); + setupDiscriminator = static_cast(setupDiscriminator32); + return CHIP_NO_ERROR; +} + +CHIP_ERROR EFR32DeviceDataProvider::GetSpake2pIterationCount(uint32_t & iterationCount) +{ + CHIP_ERROR err = SILABSConfig::ReadConfigValue(SILABSConfig::kConfigKey_Spake2pIterationCount, iterationCount); + +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT) && CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + iterationCount = CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT; + err = CHIP_NO_ERROR; + } +#endif // defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT) && CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT + return err; +} + +CHIP_ERROR EFR32DeviceDataProvider::GetSpake2pSalt(MutableByteSpan & saltBuf) +{ + static constexpr size_t kSpake2pSalt_MaxBase64Len = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length) + 1; + + CHIP_ERROR err = CHIP_NO_ERROR; + char saltB64[kSpake2pSalt_MaxBase64Len] = { 0 }; + size_t saltB64Len = 0; + + err = SILABSConfig::ReadConfigValueStr(SILABSConfig::kConfigKey_Spake2pSalt, saltB64, sizeof(saltB64), saltB64Len); + +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT) + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + saltB64Len = strlen(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT); + ReturnErrorCodeIf(saltB64Len > sizeof(saltB64), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(saltB64, CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT, saltB64Len); + err = CHIP_NO_ERROR; + } +#endif // defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT) + + ReturnErrorOnFailure(err); + + uint8_t saltByteArray[kSpake2pSalt_MaxBase64Len] = { 0 }; + size_t saltLen = chip::Base64Decode32(saltB64, saltB64Len, saltByteArray); + ReturnErrorCodeIf(saltLen > saltBuf.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + + memcpy(saltBuf.data(), saltByteArray, saltLen); + saltBuf.reduce_size(saltLen); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR EFR32DeviceDataProvider::GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen) +{ + static constexpr size_t kSpake2pSerializedVerifier_MaxBase64Len = + BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_VerifierSerialized_Length) + 1; + + CHIP_ERROR err = CHIP_NO_ERROR; + char verifierB64[kSpake2pSerializedVerifier_MaxBase64Len] = { 0 }; + size_t verifierB64Len = 0; + + err = SILABSConfig::ReadConfigValueStr(SILABSConfig::kConfigKey_Spake2pVerifier, verifierB64, sizeof(verifierB64), + verifierB64Len); + +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER) + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + verifierB64Len = strlen(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER); + ReturnErrorCodeIf(verifierB64Len > sizeof(verifierB64), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(verifierB64, CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER, verifierB64Len); + err = CHIP_NO_ERROR; + } +#endif // defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER) + + ReturnErrorOnFailure(err); + + verifierLen = chip::Base64Decode32(verifierB64, verifierB64Len, reinterpret_cast(verifierB64)); + ReturnErrorCodeIf(verifierLen > verifierBuf.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + + memcpy(verifierBuf.data(), verifierB64, verifierLen); + verifierBuf.reduce_size(verifierLen); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR EFR32DeviceDataProvider::GetSetupPayload(MutableCharSpan & payloadBuf) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + uint8_t payloadBitSet[kTotalPayloadDataSizeInBytes] = { 0 }; + size_t bitSetLen = 0; + + err = SILABSConfig::ReadConfigValueBin(SILABSConfig::kConfigKey_SetupPayloadBitSet, payloadBitSet, kTotalPayloadDataSizeInBytes, + bitSetLen); + +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + static constexpr uint8_t kTestSetupPayloadBitset[] = { 0x88, 0xFF, 0x2F, 0x00, 0x44, 0x00, 0xE0, 0x4B, 0x84, 0x68, 0x02 }; + bitSetLen = sizeof(kTestSetupPayloadBitset); + ReturnErrorCodeIf(bitSetLen > kTotalPayloadDataSizeInBytes, CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(payloadBitSet, kTestSetupPayloadBitset, bitSetLen); + err = CHIP_NO_ERROR; + } +#endif // defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER) + + ReturnErrorOnFailure(err); + + size_t prefixLen = strlen(kQRCodePrefix); + + if (payloadBuf.size() < prefixLen + 1) + { + err = CHIP_ERROR_BUFFER_TOO_SMALL; + } + else + { + MutableCharSpan subSpan = payloadBuf.SubSpan(prefixLen, payloadBuf.size() - prefixLen); + memcpy(payloadBuf.data(), kQRCodePrefix, prefixLen); + err = base38Encode(MutableByteSpan(payloadBitSet), subSpan); + // Reduce output span size to be the size of written data + payloadBuf.reduce_size(subSpan.size() + prefixLen); + } + + return err; +} + +CHIP_ERROR EFR32DeviceDataProvider::GetVendorName(char * buf, size_t bufSize) +{ + size_t vendorNameLen = 0; // without counting null-terminator + return SILABSConfig::ReadConfigValueStr(SILABSConfig::kConfigKey_VendorName, buf, bufSize, vendorNameLen); +} + +CHIP_ERROR EFR32DeviceDataProvider::GetVendorId(uint16_t & vendorId) +{ + ChipError err = CHIP_NO_ERROR; + uint32_t vendorId32 = 0; + + err = SILABSConfig::ReadConfigValue(SILABSConfig::kConfigKey_VendorId, vendorId32); + +#if defined(CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID) && CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + vendorId32 = CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID; + err = CHIP_NO_ERROR; + } +#endif // defined(CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID) && CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID + + ReturnErrorOnFailure(err); + vendorId = static_cast(vendorId32); + return err; +} + +CHIP_ERROR EFR32DeviceDataProvider::GetProductName(char * buf, size_t bufSize) +{ + size_t productNameLen = 0; // without counting null-terminator + return SILABSConfig::ReadConfigValueStr(SILABSConfig::kConfigKey_ProductName, buf, bufSize, productNameLen); +} + +CHIP_ERROR EFR32DeviceDataProvider::GetProductId(uint16_t & productId) +{ + ChipError err = CHIP_NO_ERROR; + uint32_t productId32 = 0; + + err = SILABSConfig::ReadConfigValue(SILABSConfig::kConfigKey_ProductId, productId32); + +#if defined(CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID) && CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + productId32 = CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID; + err = CHIP_NO_ERROR; + } +#endif // defined(CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID) && CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID + ReturnErrorOnFailure(err); + + productId = static_cast(productId32); + return err; +} + +CHIP_ERROR EFR32DeviceDataProvider::GetHardwareVersionString(char * buf, size_t bufSize) +{ + size_t hardwareVersionStringLen = 0; // without counting null-terminator + CHIP_ERROR err = + SILABSConfig::ReadConfigValueStr(SILABSConfig::kConfigKey_HardwareVersionString, buf, bufSize, hardwareVersionStringLen); +#if defined(CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING) + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + memcpy(buf, CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING, sizeof(bufSize)); + err = CHIP_NO_ERROR; + } +#endif // CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + return err; +} + +CHIP_ERROR EFR32DeviceDataProvider::GetHardwareVersion(uint16_t & hardwareVersion) +{ + CHIP_ERROR err; + uint32_t hardwareVersion32; + + err = SILABSConfig::ReadConfigValue(SILABSConfig::kConfigKey_HardwareVersion, hardwareVersion32); +#if defined(CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION) + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + hardwareVersion32 = CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION; + err = CHIP_NO_ERROR; + } +#endif // defined(CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION) + + hardwareVersion = static_cast(hardwareVersion32); + return err; +} + +CHIP_ERROR EFR32DeviceDataProvider::GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) +{ + ChipError err = CHIP_ERROR_WRONG_KEY_TYPE; +#if CHIP_ENABLE_ROTATING_DEVICE_ID + static_assert(ConfigurationManager::kRotatingDeviceIDUniqueIDLength >= ConfigurationManager::kMinRotatingDeviceIDUniqueIDLength, + "Length of unique ID for rotating device ID is smaller than minimum."); + + size_t uniqueIdLen = 0; + err = + SILABSConfig::ReadConfigValueBin(SILABSConfig::kConfigKey_UniqueId, uniqueIdSpan.data(), uniqueIdSpan.size(), uniqueIdLen); +#ifdef CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + constexpr uint8_t uniqueId[] = CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID; + + ReturnErrorCodeIf(sizeof(uniqueId) > uniqueIdSpan.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(uniqueIdSpan.data(), uniqueId, sizeof(uniqueId)); + uniqueIdLen = sizeof(uniqueId); + } +#endif // CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID + + ReturnErrorOnFailure(err); + uniqueIdSpan.reduce_size(uniqueIdLen); + +#endif // CHIP_ENABLE_ROTATING_DEVICE_ID + return err; +} + +CHIP_ERROR EFR32DeviceDataProvider::GetSerialNumber(char * buf, size_t bufSize) +{ + size_t serialNumberLen = 0; // without counting null-terminator + return SILABSConfig::ReadConfigValueStr(SILABSConfig::kConfigKey_SerialNum, buf, bufSize, serialNumberLen); +} + +CHIP_ERROR EFR32DeviceDataProvider::GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) +{ + CHIP_ERROR err; + constexpr uint8_t kDateStringLength = 10; // YYYY-MM-DD + char dateStr[kDateStringLength + 1]; + size_t dateLen; + char * parseEnd; + + err = SILABSConfig::ReadConfigValueBin(SILABSConfig::kConfigKey_ManufacturingDate, reinterpret_cast(dateStr), + sizeof(dateStr), dateLen); + SuccessOrExit(err); + + VerifyOrExit(dateLen == kDateStringLength, err = CHIP_ERROR_INVALID_ARGUMENT); + + // Cast does not lose information, because we then check that we only parsed + // 4 digits, so our number can't be bigger than 9999. + year = static_cast(strtoul(dateStr, &parseEnd, 10)); + VerifyOrExit(parseEnd == dateStr + 4, err = CHIP_ERROR_INVALID_ARGUMENT); + + // Cast does not lose information, because we then check that we only parsed + // 2 digits, so our number can't be bigger than 99. + month = static_cast(strtoul(dateStr + 5, &parseEnd, 10)); + VerifyOrExit(parseEnd == dateStr + 7, err = CHIP_ERROR_INVALID_ARGUMENT); + + // Cast does not lose information, because we then check that we only parsed + // 2 digits, so our number can't be bigger than 99. + day = static_cast(strtoul(dateStr + 8, &parseEnd, 10)); + VerifyOrExit(parseEnd == dateStr + 10, err = CHIP_ERROR_INVALID_ARGUMENT); + +exit: + if (err != CHIP_NO_ERROR && err != CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + ChipLogError(DeviceLayer, "Invalid manufacturing date: %s", dateStr); + } + return err; + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +EFR32DeviceDataProvider & EFR32DeviceDataProvider::GetDeviceDataProvider() +{ + static EFR32DeviceDataProvider sDataProvider; + return sDataProvider; +} + +} // namespace EFR32 +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/SiWx917/EFR32DeviceDataProvider.h b/examples/platform/silabs/SiWx917/EFR32DeviceDataProvider.h new file mode 100644 index 00000000000000..99d90496b30d12 --- /dev/null +++ b/examples/platform/silabs/SiWx917/EFR32DeviceDataProvider.h @@ -0,0 +1,67 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace EFR32 { + +/** + * @brief This class provides Commissionable data, Device Attestation Credentials, + * and Device Instance Info. + */ + +class EFR32DeviceDataProvider : public CommissionableDataProvider, + public Internal::GenericDeviceInstanceInfoProvider +{ +public: + EFR32DeviceDataProvider() : + CommissionableDataProvider(), Internal::GenericDeviceInstanceInfoProvider( + ConfigurationManagerImpl::GetDefaultInstance()) + {} + + static EFR32DeviceDataProvider & GetDeviceDataProvider(); + CHIP_ERROR GetSetupPayload(MutableCharSpan & payloadBuf); + + // ===== Members functions that implement the CommissionableDataProvider + CHIP_ERROR GetSetupDiscriminator(uint16_t & setupDiscriminator) override; + CHIP_ERROR SetSetupDiscriminator(uint16_t setupDiscriminator) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetSpake2pIterationCount(uint32_t & iterationCount) override; + CHIP_ERROR GetSpake2pSalt(MutableByteSpan & saltBuf) override; + CHIP_ERROR GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen) override; + // Per spec 5.1.7. Passcode cannot be stored on the device + CHIP_ERROR GetSetupPasscode(uint32_t & setupPasscode) override { return CHIP_ERROR_NOT_IMPLEMENTED; }; + CHIP_ERROR SetSetupPasscode(uint32_t setupPasscode) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + + // ===== Members functions that implement the GenericDeviceInstanceInfoProvider + CHIP_ERROR GetVendorName(char * buf, size_t bufSize) override; + CHIP_ERROR GetVendorId(uint16_t & vendorId) override; + CHIP_ERROR GetProductName(char * buf, size_t bufSize) override; + CHIP_ERROR GetProductId(uint16_t & productId) override; + CHIP_ERROR GetHardwareVersionString(char * buf, size_t bufSize) override; + CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override; + CHIP_ERROR GetSerialNumber(char * buf, size_t bufSize) override; + CHIP_ERROR GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) override; + CHIP_ERROR GetHardwareVersion(uint16_t & hardwareVersion) override; +}; + +} // namespace EFR32 +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/SiWx917/FreeRTOSConfig.h b/examples/platform/silabs/SiWx917/FreeRTOSConfig.h new file mode 100644 index 00000000000000..50f4c24ff31679 --- /dev/null +++ b/examples/platform/silabs/SiWx917/FreeRTOSConfig.h @@ -0,0 +1,274 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * # License + * + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is Third Party Software licensed by Silicon Labs from a third party + * and is governed by the sections of the MSLA applicable to Third Party + * Software and the additional terms set forth below. + * + ******************************************************************************/ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +#include "RTE_Components.h" +#include CMSIS_device_header + +#include "em_assert.h" +#include "em_device.h" + +#if defined(SL_COMPONENT_CATALOG_PRESENT) +#include "sl_component_catalog.h" +#endif + +#if SL_SYSTEM_VIEW +#include "SEGGER_SYSVIEW_FreeRTOS.h" +#endif + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +/* Energy saving modes. */ +#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) +#define configUSE_TICKLESS_IDLE 1 +#else +#define configUSE_TICKLESS_IDLE 0 +#endif // SL_CATALOG_POWER_MANAGER_PRESENT + +#define configTICK_RATE_HZ (1000) +/* Definition used by Keil to replace default system clock source. */ +#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK (1) +#define configCHECK_FOR_STACK_OVERFLOW (2) +#define configUSE_MALLOC_FAILED_HOOK (1) +#define configUSE_IDLE_HOOK (1) + +/* Main functions*/ +/* Run time stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS (0) + +/* Co-routine related definitions. */ +#define configUSE_CO_ROUTINES (0) +#define configMAX_CO_ROUTINE_PRIORITIES (1) + +/* Software timer related definitions. */ +#define configUSE_TIMERS (1) +#define configTIMER_TASK_PRIORITY (40) /* Highest priority */ +#define configTIMER_QUEUE_LENGTH (10) +#define configTIMER_TASK_STACK_DEPTH (1024) + +/* Interrupt priorities used by the kernel port layer itself. These are generic +to all Cortex-M ports, and do not rely on any particular library functions. */ +#define configKERNEL_INTERRUPT_PRIORITY (255) +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY 48 +#define configENABLE_FPU 0 +#define configENABLE_MPU 0 +/* FreeRTOS Secure Side Only and TrustZone Security Extension */ +#define configRUN_FREERTOS_SECURE_ONLY 1 +#define configENABLE_TRUSTZONE 0 +/* FreeRTOS MPU specific definitions. */ +#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS (0) + +#define configCPU_CLOCK_HZ (SystemCoreClock) +#define configUSE_PREEMPTION (1) +#define configUSE_TIME_SLICING (1) +#define configUSE_PORT_OPTIMISED_TASK_SELECTION (0) +#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG (1) /* See into vPortSuppressTicksAndSleep source code for explanation */ +#define configMAX_PRIORITIES (56) +#define configMINIMAL_STACK_SIZE (320) /* Number of words to use for Idle and Timer stacks */ + +#ifdef HEAP_MONITORING +#define configMAX_TASK_NAME_LEN (24) +#else +#define configMAX_TASK_NAME_LEN (10) +#endif // HEAP_MONITORING + +#define configUSE_16_BIT_TICKS (0) +#define configIDLE_SHOULD_YIELD (1) +#define configUSE_MUTEXES (1) +#define configUSE_RECURSIVE_MUTEXES (1) +#define configUSE_COUNTING_SEMAPHORES (1) +#define configUSE_TASK_NOTIFICATIONS 1 +#define configUSE_TRACE_FACILITY 1 +#define configQUEUE_REGISTRY_SIZE (10) +#define configUSE_QUEUE_SETS (0) +#define configUSE_NEWLIB_REENTRANT (1) +#define configENABLE_BACKWARD_COMPATIBILITY (1) +#define configSUPPORT_STATIC_ALLOCATION (1) +#define configSUPPORT_DYNAMIC_ALLOCATION (1) + +#ifndef configTOTAL_HEAP_SIZE +#ifdef SL_WIFI +#define configTOTAL_HEAP_SIZE ((size_t)(34 * 1024)) +#else +#define configTOTAL_HEAP_SIZE ((size_t)(20 * 1024)) +#endif +#endif // configTOTAL_HEAP_SIZE + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet (1) +#define INCLUDE_uxTaskPriorityGet (1) +#define INCLUDE_vTaskDelete (1) +#define INCLUDE_vTaskSuspend (1) +#define INCLUDE_xResumeFromISR (1) +#define INCLUDE_vTaskDelayUntil (1) +#define INCLUDE_vTaskDelay (1) +#define INCLUDE_xTaskGetSchedulerState (1) +#define INCLUDE_xTaskGetCurrentTaskHandle (1) +#define INCLUDE_uxTaskGetStackHighWaterMark (1) +#define INCLUDE_xTaskGetIdleTaskHandle (1) +#define INCLUDE_xTimerGetTimerDaemonTaskHandle (1) +#define INCLUDE_pcTaskGetTaskName (1) +#define INCLUDE_eTaskGetState (1) +#define INCLUDE_xEventGroupSetBitFromISR (1) +#define INCLUDE_xEventGroupSetBitsFromISR (1) +#define INCLUDE_xSemaphoreGetMutexHolder (1) +#define INCLUDE_xTimerPendFunctionCall (1) +#define INCLUDE_xTaskGetHandle (1) + +/* Stop if an assertion fails. */ +#define configASSERT(x) \ + if ((x) == 0) \ + { \ + taskDISABLE_INTERRUPTS(); \ + printf("\nFREERTOS ASSERT ( %s )\n", #x); \ + for (;;) \ + ; \ + } +#define configASSERTNULL(x) \ + if ((x) == NULL) \ + { \ + taskDISABLE_INTERRUPTS(); \ + for (;;) \ + ; \ + } + +/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS +standard names. */ +#define vPortSVCHandler SVC_Handler +#define xPortPendSVHandler PendSV_Handler +/* Ensure Cortex-M port compatibility. */ +#define SysTick_Handler xPortSysTickHandler + +/* Thread local storage pointers used by the SDK */ +#ifndef configNUM_SDK_THREAD_LOCAL_STORAGE_POINTERS +#define configNUM_SDK_THREAD_LOCAL_STORAGE_POINTERS 0 +#endif + +#if defined(__GNUC__) +/* For the linker. */ +#define fabs __builtin_fabs +#endif + +#ifdef __cplusplus +} +#endif diff --git a/examples/platform/silabs/SiWx917/LEDWidget.cpp b/examples/platform/silabs/SiWx917/LEDWidget.cpp new file mode 100644 index 00000000000000..10ffcac363520d --- /dev/null +++ b/examples/platform/silabs/SiWx917/LEDWidget.cpp @@ -0,0 +1,89 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 "LEDWidget.h" + +extern "C" { +#include "sl_simple_led_instances.h" +} + +#include + +using namespace ::chip::System; + +void LEDWidget::InitGpio(void) +{ + // Sets gpio pin mode for ALL board Leds. + sl_simple_led_init_instances(); +} + +void LEDWidget::Init(const sl_led_t * led) +{ + mLastChangeTimeMS = 0; + mBlinkOnTimeMS = 0; + mBlinkOffTimeMS = 0; + mLed = led; + + Set(false); +} + +void LEDWidget::Invert(void) +{ + if (mLed) + { + sl_led_toggle(mLed); + } +} + +void LEDWidget::Set(bool state) +{ + mLastChangeTimeMS = mBlinkOnTimeMS = mBlinkOffTimeMS = 0; + if (mLed) + { + state ? sl_led_turn_on(mLed) : sl_led_turn_off(mLed); + } +} + +void LEDWidget::Blink(uint32_t changeRateMS) +{ + Blink(changeRateMS, changeRateMS); +} + +void LEDWidget::Blink(uint32_t onTimeMS, uint32_t offTimeMS) +{ + mBlinkOnTimeMS = onTimeMS; + mBlinkOffTimeMS = offTimeMS; + Animate(); +} + +void LEDWidget::Animate() +{ + if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0) + { + uint64_t nowMS = chip::System::SystemClock().GetMonotonicMilliseconds64().count(); + uint64_t stateDurMS = sl_led_get_state(mLed) ? mBlinkOnTimeMS : mBlinkOffTimeMS; + uint64_t nextChangeTimeMS = mLastChangeTimeMS + stateDurMS; + + if (nextChangeTimeMS < nowMS) + { + Invert(); + mLastChangeTimeMS = nowMS; + } + } +} diff --git a/examples/platform/silabs/SiWx917/LEDWidget.h b/examples/platform/silabs/SiWx917/LEDWidget.h new file mode 100644 index 00000000000000..d779cb9d3ef4b6 --- /dev/null +++ b/examples/platform/silabs/SiWx917/LEDWidget.h @@ -0,0 +1,41 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 "sl_led.h" +#include + +class LEDWidget +{ +public: + static void InitGpio(void); + void Init(const sl_led_t * led); + void Set(bool state); + void Invert(void); + void Blink(uint32_t changeRateMS); + void Blink(uint32_t onTimeMS, uint32_t offTimeMS); + void Animate(); + +private: + uint64_t mLastChangeTimeMS; + uint32_t mBlinkOnTimeMS; + uint32_t mBlinkOffTimeMS; + const sl_led_t * mLed; +}; diff --git a/examples/platform/silabs/SiWx917/MemMonitoring.cpp b/examples/platform/silabs/SiWx917/MemMonitoring.cpp new file mode 100644 index 00000000000000..9da075e4e79d42 --- /dev/null +++ b/examples/platform/silabs/SiWx917/MemMonitoring.cpp @@ -0,0 +1,111 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MemMonitoring.h" + +#include "AppConfig.h" +#include "FreeRTOS.h" +#include + +#define BLE_STACK_TASK_NAME "Bluetooth stack" +#define BLE_LINK_TASK_NAME "Bluetooth linklayer" + +static StackType_t monitoringStack[MONITORING_STACK_SIZE_byte / sizeof(StackType_t)]; +static StaticTask_t monitoringTaskStruct; + +size_t nbAllocSuccess = 0; +size_t nbFreeSuccess = 0; +size_t largestBlockAllocated = 0; + +void MemMonitoring::startHeapMonitoring() +{ + xTaskCreateStatic(HeapMonitoring, "Monitoring", MONITORING_STACK_SIZE_byte / sizeof(StackType_t), NULL, 1, monitoringStack, + &monitoringTaskStruct); +} + +void MemMonitoring::HeapMonitoring(void * pvParameter) +{ + + UBaseType_t appTaskValue; + UBaseType_t bleEventTaskValue; + UBaseType_t bleTaskValue; + UBaseType_t linkLayerTaskValue; + UBaseType_t openThreadTaskValue; + UBaseType_t eventLoopTaskValue; + + TaskHandle_t eventLoopHandleStruct = xTaskGetHandle(CHIP_DEVICE_CONFIG_CHIP_TASK_NAME); + TaskHandle_t otTaskHandle = xTaskGetHandle(CHIP_DEVICE_CONFIG_THREAD_TASK_NAME); + TaskHandle_t appTaskHandle = xTaskGetHandle(APP_TASK_NAME); + TaskHandle_t bleStackTaskHandle = xTaskGetHandle(BLE_STACK_TASK_NAME); + TaskHandle_t bleLinkTaskHandle = xTaskGetHandle(BLE_LINK_TASK_NAME); + TaskHandle_t bleEventTaskHandle = xTaskGetHandle(CHIP_DEVICE_CONFIG_BLE_APP_TASK_NAME); + +#if CHIP_SYSTEM_CONFIG_USE_LWIP + UBaseType_t lwipTaskValue; + TaskHandle_t lwipHandle = xTaskGetHandle(TCPIP_THREAD_NAME); +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP + + while (true) + { + appTaskValue = uxTaskGetStackHighWaterMark(appTaskHandle); + bleEventTaskValue = uxTaskGetStackHighWaterMark(bleEventTaskHandle); + bleTaskValue = uxTaskGetStackHighWaterMark(bleStackTaskHandle); + linkLayerTaskValue = uxTaskGetStackHighWaterMark(bleLinkTaskHandle); + openThreadTaskValue = uxTaskGetStackHighWaterMark(otTaskHandle); + eventLoopTaskValue = uxTaskGetStackHighWaterMark(eventLoopHandleStruct); +#if CHIP_SYSTEM_CONFIG_USE_LWIP + lwipTaskValue = uxTaskGetStackHighWaterMark(lwipHandle); +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP + + SILABS_LOG("============================="); + SILABS_LOG(" "); + SILABS_LOG("Largest Block allocated 0x%x", largestBlockAllocated); + SILABS_LOG("Number Of Successful Alloc 0x%x", nbAllocSuccess); + SILABS_LOG("Number Of Successful Frees 0x%x", nbFreeSuccess); + SILABS_LOG(" "); + SILABS_LOG("App Task most bytes ever Free 0x%x", (appTaskValue * 4)); + SILABS_LOG("BLE Event most bytes ever Free 0x%x", (bleEventTaskValue * 4)); + SILABS_LOG("BLE Stack most bytes ever Free 0x%x", (bleTaskValue * 4)); + SILABS_LOG("Link Layer Task most bytes ever Free 0x%x", (linkLayerTaskValue * 4)); + SILABS_LOG("OpenThread Task most bytes ever Free 0x%x", (openThreadTaskValue * 4)); + SILABS_LOG("Event Loop Task most bytes ever Free 0x%x", (eventLoopTaskValue * 4)); +#if CHIP_SYSTEM_CONFIG_USE_LWIP + SILABS_LOG("LWIP Task most bytes ever Free 0x%x", (lwipTaskValue * 4)); +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP + SILABS_LOG(" "); + SILABS_LOG("============================="); + vTaskDelay(pdMS_TO_TICKS(5000)); + } +} + +extern "C" void memMonitoringTrackAlloc(void * ptr, size_t size) +{ + if (ptr != NULL) + { + nbAllocSuccess++; + if (largestBlockAllocated < size) + { + largestBlockAllocated = size; + } + } +} + +extern "C" void memMonitoringTrackFree(void * ptr, size_t size) +{ + nbFreeSuccess++; +} diff --git a/examples/platform/silabs/SiWx917/OTAConfig.cpp b/examples/platform/silabs/SiWx917/OTAConfig.cpp new file mode 100644 index 00000000000000..1056cf5a3533b4 --- /dev/null +++ b/examples/platform/silabs/SiWx917/OTAConfig.cpp @@ -0,0 +1,101 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OTAConfig.h" + +#include "application_properties.h" +#include + +#if defined(SL_COMPONENT_CATALOG_PRESENT) +#include "sl_component_catalog.h" +#endif + +// Only include app properties if the Gecko SDK component that does it automatically isn't present +#if !defined(SL_CATALOG_GECKO_BOOTLOADER_INTERFACE_PRESENT) +// Header used for building the image GBL file +#define APP_PROPERTIES_VERSION 1 +#define APP_PROPERTIES_ID \ + { \ + 0 \ + } + +__attribute__((used)) ApplicationProperties_t sl_app_properties = { + /// @brief Magic value indicating that this is an ApplicationProperties_t + /// Must equal @ref APPLICATION_PROPERTIES_MAGIC + .magic = APPLICATION_PROPERTIES_MAGIC, + + /// Version number of this struct + .structVersion = APPLICATION_PROPERTIES_VERSION, + + /// Type of signature this application is signed with + .signatureType = APPLICATION_SIGNATURE_NONE, + + /// Location of the signature. Typically a pointer to the end of application + .signatureLocation = 0, + + /// Information about the application + .app = { + + /// Bitfield representing type of application + /// e.g. @ref APPLICATION_TYPE_BLUETOOTH_APP + .type = APPLICATION_TYPE_THREAD, + + /// Version number for this application + .version = APP_PROPERTIES_VERSION, + + /// Capabilities of this application + .capabilities = 0, + + /// Unique ID (e.g. UUID/GUID) for the product this application is built for + .productId = APP_PROPERTIES_ID, + }, + + /// Pointer to information about the certificate + .cert = NULL, + + /// Pointer to Long Token Data Section + .longTokenSectionAddress = NULL, +}; +#endif // SL_CATALOG_GECKO_BOOTLOADER_INTERFACE_PRESENT + +// Global OTA objects +chip::DefaultOTARequestor gRequestorCore; +chip::DefaultOTARequestorStorage gRequestorStorage; +chip::DeviceLayer::DefaultOTARequestorDriver gRequestorUser; +chip::BDXDownloader gDownloader; +chip::OTAImageProcessorImpl gImageProcessor; + +void OTAConfig::Init() +{ + // Initialize and interconnect the Requestor and Image Processor objects -- START + SetRequestorInstance(&gRequestorCore); + + gRequestorStorage.Init(chip::Server::GetInstance().GetPersistentStorage()); + gRequestorCore.Init(chip::Server::GetInstance(), gRequestorStorage, gRequestorUser, gDownloader); + + // Periodic query timeout must be set prior to requestor being initialized + gRequestorUser.SetPeriodicQueryTimeout(OTA_PERIODIC_TIMEOUT); + gRequestorUser.Init(&gRequestorCore, &gImageProcessor); + + gImageProcessor.SetOTAImageFile("test.txt"); + gImageProcessor.SetOTADownloader(&gDownloader); + + // Connect the Downloader and Image Processor objects + gDownloader.SetImageProcessorDelegate(&gImageProcessor); + // Initialize and interconnect the Requestor and Image Processor objects -- END +} diff --git a/examples/platform/silabs/SiWx917/OTAConfig.h b/examples/platform/silabs/SiWx917/OTAConfig.h new file mode 100644 index 00000000000000..a4f8ac4369e175 --- /dev/null +++ b/examples/platform/silabs/SiWx917/OTAConfig.h @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +class OTAConfig +{ +public: + OTAConfig(){}; + + static void Init(); + static constexpr uint32_t kInitOTARequestorDelaySec = 3; +}; diff --git a/examples/platform/silabs/SiWx917/TemperatureSensor.cpp b/examples/platform/silabs/SiWx917/TemperatureSensor.cpp new file mode 100644 index 00000000000000..69ba106fd69872 --- /dev/null +++ b/examples/platform/silabs/SiWx917/TemperatureSensor.cpp @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 "TemperatureSensor.h" + +#ifdef __cplusplus +extern "C" { +#endif +// This is a C implementation. Need the ifdef __cplusplus else we get linking issues +#include "sl_sensor_rht.h" + +#ifdef __cplusplus +} +#endif + +namespace TemperatureSensor { +constexpr uint16_t kSensorTemperatureOffset = 800; + +sl_status_t Init() +{ + return sl_sensor_rht_init(); +} + +sl_status_t GetTemp(uint32_t * relativeHumidity, int16_t * temperature) +{ + // Sensor resolution 0.001 C + // DataModel resolution 0.01 C + int32_t temp; + sl_status_t status = sl_sensor_rht_get(relativeHumidity, &temp); + *temperature = static_cast(temp / 10) - kSensorTemperatureOffset; + return status; +} +}; // namespace TemperatureSensor diff --git a/examples/platform/silabs/SiWx917/TemperatureSensor.h b/examples/platform/silabs/SiWx917/TemperatureSensor.h new file mode 100644 index 00000000000000..116287e9a37155 --- /dev/null +++ b/examples/platform/silabs/SiWx917/TemperatureSensor.h @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 "sl_status.h" +#include + +namespace TemperatureSensor { +sl_status_t Init(); +sl_status_t GetTemp(uint32_t * relativeHumidity, int16_t * temperature); +}; // namespace TemperatureSensor diff --git a/examples/platform/silabs/SiWx917/args.gni b/examples/platform/silabs/SiWx917/args.gni new file mode 100644 index 00000000000000..1726b62a75d86b --- /dev/null +++ b/examples/platform/silabs/SiWx917/args.gni @@ -0,0 +1,21 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") + +chip_ble_project_config_include = "" +chip_device_project_config_include = "" +chip_project_config_include = "" +chip_inet_project_config_include = "" +chip_system_project_config_include = "" diff --git a/examples/platform/silabs/SiWx917/board_config.h b/examples/platform/silabs/SiWx917/board_config.h new file mode 100644 index 00000000000000..8c495b4fa7f513 --- /dev/null +++ b/examples/platform/silabs/SiWx917/board_config.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes dev borad compile-time configuration constants for efr32. + * + */ + +#pragma once + +/// Dev board suppports OQPSK modulation in 2.4GHz band. +#define RADIO_CONFIG_2P4GHZ_OQPSK_SUPPORT 1 +#define RADIO_CONFIG_915MHZ_OQPSK_SUPPORT 0 + +/// The PA(s) is(are) fed from the DCDC +#if (BRD4166A) +#define RADIO_CONFIG_PA_USES_DCDC 1 +#else +#define RADIO_CONFIG_PA_USES_DCDC 0 +#endif + +#ifndef RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT +#define RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT 0 /// Set to 1 to enable debug counters in radio.c +#endif + +#ifndef RADIO_CONFIG_DMP_SUPPORT +#define RADIO_CONFIG_DMP_SUPPORT 0 /// Set to 1 to enable Dynamic Multi-Protocol support in radio.c +#endif diff --git a/examples/platform/silabs/SiWx917/display/demo-ui-bitmaps.h b/examples/platform/silabs/SiWx917/display/demo-ui-bitmaps.h new file mode 100644 index 00000000000000..4eca9c0c48e7aa --- /dev/null +++ b/examples/platform/silabs/SiWx917/display/demo-ui-bitmaps.h @@ -0,0 +1,356 @@ +/***************************************************************************/ /** + * @file + * @brief User Interface bitmaps for demo. + ******************************************************************************* + * # License + * Copyright 2020 Silicon Laboratories Inc. + *www.silabs.com + ******************************************************************************* + * + * The licensor of this software is Silicon + *Laboratories Inc. Your use of this software is + *governed by the terms of Silicon Labs Master + *Software License Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. + *This software is distributed to you in Source Code + *format and is governed by the sections of the MSLA + *applicable to Source Code. + * + ******************************************************************************/ + +#ifndef SILABS_DEMO_UI_BITMAPS_H +#define SILABS_DEMO_UI_BITMAPS_H + +#define SILICONLABS_BITMAP_WIDTH 128 +#define SILICONLABS_BITMAP_HEIGHT 45 + +#define ZIGBEE_BITMAP_WIDTH 16 +#define ZIGBEE_BITMAP_HEIGHT 16 + +#define RAIL_BITMAP_WIDTH 16 +#define RAIL_BITMAP_HEIGHT 16 + +#define CONNECT_BITMAP_WIDTH 16 +#define CONNECT_BITMAP_HEIGHT 16 + +#define BLUETOOTH_BITMAP_WIDTH 16 +#define BLUETOOTH_BITMAP_HEIGHT 18 + +#define SILABS_BITMAP \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xfd, 0xff, 0xff, 0x01, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0x3f, 0x00, \ + 0x00, 0x00, 0x00, 0xff, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0xfe, \ + 0xff, 0x1f, 0xf8, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f, 0xf0, 0xff, \ + 0xff, 0xff, 0x1f, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f, 0xe0, 0xff, 0xff, 0xff, 0xc3, 0xff, \ + 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0xc0, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0x07, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, 0xc0, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, \ + 0xff, 0x01, 0xc0, 0xff, 0xff, 0x07, 0xfc, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x80, 0xff, \ + 0xff, 0x01, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0xff, 0xff, \ + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x3f, 0x80, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf0, \ + 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x80, 0xff, 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x01, \ + 0x00, 0x00, 0xc0, 0xff, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xe0, 0xff, \ + 0x01, 0xc0, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0xc0, 0xff, 0xff, \ + 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf0, 0x7f, 0x00, 0x80, 0xff, 0xff, 0xff, 0x0f, 0xfc, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8, 0x3f, 0x00, 0x80, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, \ + 0x0f, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xc0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xfe, 0x0f, \ + 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x1f, 0x00, 0xff, 0x07, 0x00, 0x00, 0xf0, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x1f, 0x80, 0xff, 0x07, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0x3f, 0xf8, 0xff, 0xff, 0x1f, 0xc0, 0xff, 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xff, \ + 0x0f, 0xf0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x0f, 0xfc, 0xff, 0x03, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x07, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x3f, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x83, 0xff, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0xfc, 0xff, 0xff, 0xe1, 0xff, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, \ + 0xf8, 0xff, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x03, \ + 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x01, \ + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x80, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, \ + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xc0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0x3f, 0xc0, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xff, \ + 0x1f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + +#define THREAD_BITMAP_WIDTH 16 +#define THREAD_BITMAP_HEIGHT 18 + +#define THREAD_BITMAP \ + 0x1F, 0xF8, 0x07, 0xE0, 0x03, 0xCE, 0x01, 0x9F, 0x01, 0xB3, 0x00, 0x33, 0xF0, 0x3F, 0xF8, 0x1F, 0x0C, 0x03, 0x0C, 0x03, 0x18, \ + 0x03, 0x11, 0x83, 0x01, 0x83, 0x03, 0xC3, 0x07, 0xE3, 0x1F, 0xFB, 0x7f, 0xff, 0xff, 0xff + +#define WIFI_BITMAP_WIDTH 18 +#define WIFI_BITMAP_HEIGHT 18 + +#define WIFI_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0x01, 0xE0, 0x03, 0x00, 0xC7, 0xFF, 0xB8, 0xFF, 0xF7, 0x07, 0xF8, 0x0F, 0xC0, 0x3F, \ + 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0x7F, 0xF8, 0xFF, 0xE1, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F + +#define MATTER_LOGO_WIDTH 18 +#define MATTER_LOGO_HEIGHT 17 + +#define MATTER_LOGO_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xCF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFC, 0x3F, 0x12, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0xF3, 0x3F, 0x8F, \ + 0x7F, 0xFC, 0xFC, 0xFC, 0xE3, 0xF1, 0x87, 0x87, 0xC7, 0xDE, 0x88, 0x33, 0xC7, 0xCF, 0xFC, 0xFF, 0xFF, 0x03 + +// APP Logo, boolean only. must be 64x64 +#if IS_DEMO_SWITCH +#define ON_DEMO_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, \ + 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0xC0, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0x1F, 0xE0, 0xFF, 0xFF, \ + 0x07, 0xF8, 0xFF, 0xFF, 0x1F, 0xE0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x1F, 0xE0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0xE0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x1F, 0xE0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x1F, 0xE0, 0xFF, 0xFF, \ + 0x07, 0xF8, 0xFF, 0xFF, 0x1F, 0xE0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x1F, 0xE0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0xC0, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, \ + 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, \ + 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + +#define OFF_DEMO_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, \ + 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, \ + 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x3F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0x3C, 0x00, 0x00, 0x3C, 0xFC, 0xFF, 0xFF, 0x3F, 0x3C, 0x00, 0x00, 0x3C, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0x3C, 0x00, 0x00, 0x3C, 0xFC, 0xFF, 0xFF, 0x3F, 0x3C, 0x00, 0x00, 0x3C, 0xFC, 0xFF, 0xFF, 0x3F, 0x3C, 0x00, 0x00, \ + 0x3C, 0xFC, 0xFF, 0xFF, 0x3F, 0x3C, 0x00, 0x00, 0x3C, 0xFC, 0xFF, 0xFF, 0x3F, 0x3C, 0x00, 0x00, 0x3C, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0x3C, 0x00, 0x00, 0x3C, 0xFC, 0xFF, 0xFF, 0x3F, 0x3C, 0x00, 0x00, 0x3C, 0xFC, 0xFF, 0xFF, 0x3F, 0x3C, 0x00, 0x00, \ + 0x3C, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, \ + 0x3F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, \ + 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, \ + 0xFF, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +#elif IS_DEMO_LIGHT +#define ON_DEMO_BITMAP \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, \ + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0x1f, 0xfe, 0x07, 0xe0, \ + 0x7f, 0xf8, 0xff, 0xff, 0x3f, 0xfc, 0x00, 0x00, 0x3f, 0xfc, 0xff, 0xff, 0x7f, 0x3c, 0xe0, 0x07, 0x3c, 0xfe, 0xff, 0xff, \ + 0xff, 0x1f, 0xfe, 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, \ + 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, \ + 0xff, 0xf1, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, \ + 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, \ + 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, \ + 0x7f, 0xfc, 0xff, 0x0f, 0x38, 0xfe, 0xff, 0xff, 0x7f, 0x1c, 0xf0, 0x0f, 0x38, 0xfe, 0x03, 0xc0, 0x7f, 0x1c, 0xf0, 0x0f, \ + 0x38, 0xfe, 0x27, 0xe9, 0x7f, 0x1c, 0xf0, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, \ + 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xe7, 0xe7, 0x7f, 0xfc, 0xff, 0xff, 0x7f, 0xfe, 0xef, 0xf7, 0x7f, 0xfe, 0xff, 0xff, \ + 0x7f, 0xfc, 0xef, 0xf7, 0x3f, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xef, 0xf3, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xcf, 0xf3, \ + 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xdf, 0xfb, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xdf, 0xfb, 0x8f, 0xff, 0xff, 0xff, \ + 0xff, 0xe3, 0x9f, 0xf9, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x9f, 0xf9, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xc7, 0x9f, 0xfd, \ + 0xe3, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xbf, 0xfd, 0xf1, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x3f, 0xfc, 0xf8, 0xff, 0xff, 0xff, \ + 0xff, 0x3f, 0x3e, 0x7c, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0x3f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0x3f, \ + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + +#define OFF_DEMO_BITMAP \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xe0, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0x07, 0xfc, 0xff, 0xff, 0xff, \ + 0xff, 0x1f, 0xfe, 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, \ + 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, \ + 0xff, 0xf1, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, \ + 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, \ + 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, \ + 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, \ + 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, \ + 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, \ + 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, \ + 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, \ + 0xff, 0xe3, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, \ + 0xe3, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, \ + 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0x3f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0x3f, \ + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +#elif IS_DEMO_LOCK +#define ON_DEMO_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, \ + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xE0, 0x07, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xF8, 0x1F, 0xF8, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x0F, 0xFC, 0x3F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x7F, \ + 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, \ + 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x80, 0x01, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0xE0, 0x07, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF0, 0x0F, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF8, 0x1F, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF8, 0x1F, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xFC, 0x3F, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0xFC, 0x3F, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF8, 0x1F, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF8, 0x1F, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF0, 0x0F, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xE0, 0x07, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0x80, 0x01, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + +#define OFF_DEMO_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, \ + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xE0, 0x07, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xF8, 0x1F, 0xF8, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x0F, 0xFC, 0x3F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x7F, \ + 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x80, 0x01, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0xE0, 0x07, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF0, 0x0F, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF8, 0x1F, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF8, 0x1F, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xFC, 0x3F, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0xFC, 0x3F, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF8, 0x1F, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF8, 0x1F, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xF0, 0x0F, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0xE0, 0x07, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0x80, 0x01, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, \ + 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, \ + 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +#elif IS_DEMO_THERMOSTAT +#define ON_DEMO_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0x81, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, \ + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, \ + 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, \ + 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, \ + 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +#define OFF_DEMO_BITMAP ON_DEMO_BITMAP + +#else // Unknown demo.... +#define ON_DEMO_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, \ + 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xF0, 0x0F, \ + 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFC, 0x3F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0x7F, 0xFE, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xF0, \ + 0x0F, 0xFF, 0xFF, 0xFF, 0x7F, 0xE0, 0x07, 0xE0, 0x07, 0xFE, 0xFF, 0xFF, 0x7F, 0xC0, 0x03, 0xC0, 0x03, 0xFE, 0xFF, 0xFF, \ + 0x7F, 0xC0, 0x03, 0xC0, 0x03, 0xFE, 0xFF, 0xFF, 0x3F, 0xC0, 0x03, 0xC0, 0x03, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, \ + 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, \ + 0x8F, 0x01, 0x80, 0x01, 0x80, 0xF1, 0xFF, 0xFF, 0xCF, 0x03, 0xC0, 0x03, 0xC0, 0xF3, 0xFF, 0xFF, 0xEF, 0x07, 0xE0, 0x07, \ + 0xE0, 0xF7, 0xFF, 0xFF, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xF8, 0x1F, 0xF8, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x3F, 0xFC, 0x3F, 0xFC, 0xFF, 0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7E, 0x7E, 0xFE, 0xFF, 0xFF, 0x3F, 0xFC, 0x3F, 0xFC, \ + 0x3F, 0xFC, 0xFF, 0xFF, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0xFF, 0xFF, 0x1F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0xE0, 0x07, 0xE0, 0x07, 0xF8, 0xFF, 0xFF, 0x3F, 0xC0, 0x03, 0xC0, 0x03, 0xFC, 0xFF, 0xFF, 0x3F, 0x80, 0x01, 0x80, \ + 0x01, 0xFC, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, \ + 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, \ + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + +#define OFF_DEMO_BITMAP \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, \ + 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, \ + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, \ + 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, \ + 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, \ + 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, \ + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, \ + 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, \ + 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, \ + 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, \ + 0x00, 0xF0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, \ + 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, \ + 0x00, 0xFC, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, \ + 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, \ + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + +#endif + +#endif // SILABS_DEMO_UI_BITMAPS_H diff --git a/examples/platform/silabs/SiWx917/display/demo-ui.c b/examples/platform/silabs/SiWx917/display/demo-ui.c new file mode 100644 index 00000000000000..73a8d52ea71090 --- /dev/null +++ b/examples/platform/silabs/SiWx917/display/demo-ui.c @@ -0,0 +1,136 @@ +/** + * @file + * @brief User Interface core logic for demo. + ******************************************************************************* + * # License + * Copyright 2020 Silicon Laboratories Inc. + *www.silabs.com + ******************************************************************************* + * + * The licensor of this software is Silicon + *Laboratories Inc. Your use of this software is + *governed by the terms of Silicon Labs Master + *Software License Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. + *This software is distributed to you in Source Code + *format and is governed by the sections of the MSLA + *applicable to Source Code. + * + ******************************************************************************/ + +#include "demo-ui.h" +#include "demo-ui-bitmaps.h" +#include "dmd/dmd.h" +#include "em_types.h" +#include "glib.h" +#include +#include + +// Main Logo and App image +#define SILICONLABS_X_POSITION ((glibContext.pDisplayGeometry->xSize - SILICONLABS_BITMAP_WIDTH) / 2) +#define SILICONLABS_Y_POSITION 0 +#define APP_BITMAP_WIDTH 64 +#define APP_BITMAP_HEIGHT 64 +#define APP_X_POSITION ((glibContext.pDisplayGeometry->xSize - APP_BITMAP_WIDTH) / 2) +#define APP_Y_POSITION (glibContext.pDisplayGeometry->ySize - APP_BITMAP_HEIGHT - 5) +#define PROT1_ID_X_POSITION 1 +#define PROT2_ID_X_POSITION 79 + +// Matter Logo +#define PROT2_BITMAP_WIDTH MATTER_LOGO_WIDTH +#define PROT2_BITMAP_HEIGHT MATTER_LOGO_HEIGHT +#define PROT2_X_POSITION 104 +#define PROT2_Y_POSITION (APP_Y_POSITION + (APP_Y_POSITION / 2)) +#define PROT2_BITMAP (matterLogoBitmap) +#define PROT2_BITMAP_CONN (matterLogoBitmap) + +// Networking Protocol Logo +#ifdef SL_WIFI +#define PROT1_BITMAP_WIDTH WIFI_BITMAP_WIDTH +#define PROT1_BITMAP_HEIGHT WIFI_BITMAP_HEIGHT +#define PROT1_X_POSITION 8 +#define PROT1_Y_POSITION (APP_Y_POSITION + (APP_Y_POSITION / 2)) +#define PROT1_BITMAP (networkBitMap) +#define PROT1_BITMAP_CONN (networkBitMap) +#else +#define PROT1_BITMAP_WIDTH THREAD_BITMAP_WIDTH +#define PROT1_BITMAP_HEIGHT THREAD_BITMAP_HEIGHT +#define PROT1_X_POSITION 8 +#define PROT1_Y_POSITION (APP_Y_POSITION + (APP_Y_POSITION / 2)) +#define PROT1_BITMAP (networkBitMap) +#define PROT1_BITMAP_CONN (networkBitMap) +#endif + +/******************************************************************************* + *************************** LOCAL VARIABLES ******************************** + ******************************************************************************/ +static GLIB_Context_t glibContext; /* Global glib context */ + +static const uint8_t siliconlabsBitmap[] = { SILABS_BITMAP }; +static const uint8_t matterLogoBitmap[] = { MATTER_LOGO_BITMAP }; + +static const uint8_t OnStateBitMap[] = { ON_DEMO_BITMAP }; +static const uint8_t OffStateBitMap[] = { OFF_DEMO_BITMAP }; + +#ifdef SL_WIFI +static const uint8_t networkBitMap[] = { WIFI_BITMAP }; +#else +static const uint8_t networkBitMap[] = { THREAD_BITMAP }; +#endif + +// Future usage +// static const uint8_t unconnectedBitMap[] = { QUESTION_MARK_BITMAP }; + +/******************************************************************************* + ************************** LOCAL FUNCTIONS ******************************** + ******************************************************************************/ +static void demoUIDisplayLogo(void) +{ + GLIB_drawBitmap(&glibContext, SILICONLABS_X_POSITION, SILICONLABS_Y_POSITION, SILICONLABS_BITMAP_WIDTH, + SILICONLABS_BITMAP_HEIGHT, siliconlabsBitmap); +} + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ +void demoUIInit(GLIB_Context_t * context) +{ + memcpy(&glibContext, context, sizeof(GLIB_Context_t)); +} + +void demoUIDisplayHeader(char * name) +{ + demoUIDisplayLogo(); + if (APP_NAME_MAX_LENGTH >= strlen(name)) + { + GLIB_drawStringOnLine(&glibContext, name, 5, GLIB_ALIGN_CENTER, 0, 0, true); + } + DMD_updateDisplay(); +} + +void demoUIDisplayApp(bool on) +{ + GLIB_drawBitmap(&glibContext, APP_X_POSITION, APP_Y_POSITION, APP_BITMAP_WIDTH, APP_BITMAP_HEIGHT, + (on ? OnStateBitMap : OffStateBitMap)); + DMD_updateDisplay(); +} + +void demoUIDisplayProtocol(demoUIProtocol protocol, bool isConnected) +{ + GLIB_drawBitmap(&glibContext, (protocol == DEMO_UI_PROTOCOL1 ? PROT1_X_POSITION : PROT2_X_POSITION), + (protocol == DEMO_UI_PROTOCOL1 ? PROT1_Y_POSITION : PROT2_Y_POSITION), + (protocol == DEMO_UI_PROTOCOL1 ? PROT1_BITMAP_WIDTH : PROT2_BITMAP_WIDTH), + (protocol == DEMO_UI_PROTOCOL1 ? PROT1_BITMAP_HEIGHT : PROT2_BITMAP_HEIGHT), + (protocol == DEMO_UI_PROTOCOL1 ? (isConnected ? PROT1_BITMAP_CONN : PROT1_BITMAP) + : (isConnected ? PROT2_BITMAP_CONN : PROT2_BITMAP))); + DMD_updateDisplay(); +} + +void demoUIClearMainScreen(uint8_t * name) +{ + GLIB_clear(&glibContext); + demoUIDisplayHeader((char *) name); + demoUIDisplayApp(false); + demoUIDisplayProtocol(DEMO_UI_PROTOCOL1, false); + demoUIDisplayProtocol(DEMO_UI_PROTOCOL2, false); +} diff --git a/examples/platform/silabs/SiWx917/display/demo-ui.h b/examples/platform/silabs/SiWx917/display/demo-ui.h new file mode 100644 index 00000000000000..6197a4e73c71ef --- /dev/null +++ b/examples/platform/silabs/SiWx917/display/demo-ui.h @@ -0,0 +1,139 @@ +/***************************************************************************/ /** + * @file + * @brief User Interface for demo. + ******************************************************************************* + * # License + * Copyright 2020 Silicon Laboratories Inc. + *www.silabs.com + ******************************************************************************* + * + * The licensor of this software is Silicon + *Laboratories Inc. Your use of this software is + *governed by the terms of Silicon Labs Master + *Software License Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. + *This software is distributed to you in Source Code + *format and is governed by the sections of the MSLA + *applicable to Source Code. + * + ******************************************************************************/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "glib.h" +/**************************************************************************/ /** + * DEMO UI uses the underlying DMD interface and the + *GLIB and exposes several wrapper functions to + *application. These functions are used to display + * different bitmaps for the demo. + * + ******************************************************************************/ + +#define APP_NAME_MAX_LENGTH 20 + +/******************************************************************************* + ******************************** ENUMS ************************************ + ******************************************************************************/ + +typedef enum +{ + DEMO_UI_PROTOCOL1, + DEMO_UI_PROTOCOL2 +} demoUIProtocol; + +typedef enum +{ + DEMO_UI_LIGHT_OFF, + DEMO_UI_LIGHT_ON +} demoUILightState_t; + +typedef enum +{ + DEMO_UI_DIRECTION_PROT1, + DEMO_UI_DIRECTION_PROT2, + DEMO_UI_DIRECTION_SWITCH, + DEMO_UI_DIRECTION_INVALID +} demoUILightDirection_t; + +typedef enum +{ + DEMO_UI_NO_NETWORK, + DEMO_UI_SCANNING, + DEMO_UI_JOINING, + DEMO_UI_FORMING, + DEMO_UI_NETWORK_UP, + DEMO_UI_STATE_UNKNOWN +} demoUIZigBeeNetworkState_t; + +/******************************************************************************* + ****************************** PROTOTYPES ********************************* + ******************************************************************************/ + +/**************************************************************************/ /** + * @brief + * Initilize the GLIB and DMD interfaces. + * + * @param[in] void + * + * @return + * void + *****************************************************************************/ +void demoUIInit(GLIB_Context_t * context); + +/**************************************************************************/ /** + * @brief + * Update the display with Silicon Labs logo and + *application name. + * + * @param[in] name name of the current application. + * + * @return + * void + *****************************************************************************/ +void demoUIDisplayHeader(char * name); + +/**************************************************************************/ /** + * @brief + * Update the display with App image. Bool state only + *for now. + * + * @param[in] on status of App + * + * @return + * void + *****************************************************************************/ +void demoUIDisplayApp(bool on); + +/**************************************************************************/ /** + * @brief + * Update the display to show if the bluetooth is + *connected to the mobile device. + * + * @param[in] bool, true if the Light is connected to + *mobile device, false otherwise. + * + * @return + * void + *****************************************************************************/ +void demoUIDisplayProtocol(demoUIProtocol protocol, bool isConnected); + +/**************************************************************************/ /** + * @brief + * Clear the Lcd screen and display the main screen. + * + * @param[in] name - application name + * @param[in] showPROT1 - show protocol 1 related icon. + * @param[in] showPROT2 - show protocol 2 related icon. + * + * @return + * void + *****************************************************************************/ +void demoUIClearMainScreen(uint8_t * name); + +#ifdef __cplusplus +} +#endif diff --git a/examples/platform/silabs/SiWx917/display/lcd.cpp b/examples/platform/silabs/SiWx917/display/lcd.cpp new file mode 100644 index 00000000000000..6e1f2d2fe93de3 --- /dev/null +++ b/examples/platform/silabs/SiWx917/display/lcd.cpp @@ -0,0 +1,220 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "demo-ui.h" +#include "lcd.h" + +#include "dmd.h" +#include "glib.h" + +#ifdef QR_CODE_ENABLED +#include "qrcodegen.h" +#endif // QR_CODE_ENABLED + +#include "sl_board_control.h" + +#define LCD_SIZE 128 +#define QR_CODE_VERSION 4 +#define QR_CODE_MODULE_SIZE 3 +#define QR_CODE_BORDER_SIZE 0 + +#ifdef QR_CODE_ENABLED +static uint8_t qrCode[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_CODE_VERSION)]; +static uint8_t workBuffer[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_CODE_VERSION)]; +#endif // QR_CODE_ENABLED + +CHIP_ERROR SilabsLCD::Init(uint8_t * name, bool initialState) +{ + EMSTATUS status; + CHIP_ERROR err = CHIP_NO_ERROR; + + // Check if Name is to long + if (name != nullptr) + { + if (APP_NAME_MAX_LENGTH < strlen((char *) name)) + { + SILABS_LOG("App Name too long"); + return CHIP_ERROR_INVALID_ARGUMENT; + } + else + { + strcpy((char *) mName, (char *) name); + } + } + + /* Enable the memory lcd */ + status = sl_board_enable_display(); + if (status != SL_STATUS_OK) + { + SILABS_LOG("Board Display enable fail %d", status); + err = CHIP_ERROR_INTERNAL; + } + + /* Initialize the DMD module for the DISPLAY device driver. */ + status = DMD_init(0); + if (DMD_OK != status) + { + SILABS_LOG("DMD init failed %d", status); + err = CHIP_ERROR_INTERNAL; + } + + /* Initialize the glib context */ + status = GLIB_contextInit(&glibContext); + if (GLIB_OK != status) + { + SILABS_LOG("Glib context init failed %d", status); + err = CHIP_ERROR_INTERNAL; + } + + glibContext.backgroundColor = White; + glibContext.foregroundColor = Black; + status = GLIB_clear(&glibContext); + if (GLIB_OK != status) + { + SILABS_LOG("Glib clear failed %d", status); + err = CHIP_ERROR_INTERNAL; + } + demoUIInit(&glibContext); + + dState.mainState = initialState; + + return err; +} + +/* This function is necessary because currently glib.h cannot be used within a C++ context. */ +void * SilabsLCD::Context() +{ + return (void *) &glibContext; +} + +int SilabsLCD::Clear() +{ + return GLIB_clear(&glibContext); +} + +int SilabsLCD::DrawPixel(void * pContext, int32_t x, int32_t y) +{ + return GLIB_drawPixel((GLIB_Context_t *) pContext, x, y); +} + +int SilabsLCD::Update(void) +{ + return DMD_updateDisplay(); +} + +void SilabsLCD::WriteDemoUI(bool state) +{ +#ifdef QR_CODE_ENABLED + if (mShowQRCode) + { + mShowQRCode = false; + } +#endif + dState.mainState = state; + WriteDemoUI(); +} + +void SilabsLCD::WriteDemoUI() +{ + Clear(); + if (customUI != nullptr) + { + customUI(&glibContext); + } + else + { + demoUIClearMainScreen(mName); + demoUIDisplayApp(dState.mainState); + } +} + +void SilabsLCD::SetCustomUI(customUICB cb) +{ + customUI = cb; +} + +#ifdef QR_CODE_ENABLED +void SilabsLCD::WriteQRCode() +{ + if (!qrcodegen_encodeText((const char *) mQRCodeBuffer, workBuffer, qrCode, qrcodegen_Ecc_LOW, QR_CODE_VERSION, QR_CODE_VERSION, + qrcodegen_Mask_AUTO, true)) + { + SILABS_LOG("qrcodegen_encodeText() failed"); + return; + } + + const int size = qrcodegen_getSize(qrCode); + + GLIB_clear(&glibContext); + + const int displaySize = (2 * QR_CODE_BORDER_SIZE + size) * QR_CODE_MODULE_SIZE; + const int displayX = (LCD_SIZE - displaySize) / 2; + const int displayY = displayX; + + for (int y = 0; y < size; ++y) + { + for (int x = 0; x < size; ++x) + { + if (qrcodegen_getModule(qrCode, x, y)) + { + LCDFillRect(displayX + (QR_CODE_BORDER_SIZE + x) * QR_CODE_MODULE_SIZE, + displayY + (QR_CODE_BORDER_SIZE + y) * QR_CODE_MODULE_SIZE, QR_CODE_MODULE_SIZE, QR_CODE_MODULE_SIZE); + } + } + } + + DMD_updateDisplay(); +} + +void SilabsLCD::SetQRCode(uint8_t * str, uint32_t size) +{ + if (size < chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1) + { + memcpy(mQRCodeBuffer, str, size); + } +} + +void SilabsLCD::ShowQRCode(bool show, bool forceRefresh) +{ + if (show != mShowQRCode || forceRefresh) + { + (show) ? WriteQRCode() : WriteDemoUI(); + mShowQRCode = show; + } +} + +void SilabsLCD::ToggleQRCode(void) +{ + (mShowQRCode) ? WriteDemoUI() : WriteQRCode(); + mShowQRCode = !mShowQRCode; +} + +void SilabsLCD::LCDFillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h) +{ + for (int i = 0; i < h; i++) + { + for (int j = 0; j < w; j++) + { + GLIB_drawPixel(&glibContext, x + j, y + i); + } + } +} +#endif // QR_CODE_ENABLED diff --git a/examples/platform/silabs/SiWx917/display/lcd.h b/examples/platform/silabs/SiWx917/display/lcd.h new file mode 100644 index 00000000000000..d375b7a133c9aa --- /dev/null +++ b/examples/platform/silabs/SiWx917/display/lcd.h @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "AppConfig.h" +#include "glib.h" +#ifdef QR_CODE_ENABLED +#include "qrcodegen.h" +#include +#endif // QR_CODE_ENABLED + +#include "demo-ui.h" + +#define MAX_STR_LEN 48 + +class SilabsLCD +{ + +public: + typedef void (*customUICB)(GLIB_Context_t * context); + CHIP_ERROR Init(uint8_t * name = nullptr, bool initialState = false); + void * Context(); + int Clear(void); + int DrawPixel(void * pContext, int32_t x, int32_t y); + int Update(void); + void WriteDemoUI(bool state); + void SetCustomUI(customUICB cb); + +#ifdef QR_CODE_ENABLED + void SetQRCode(uint8_t * str, uint32_t size); + void ShowQRCode(bool show, bool forceRefresh = false); + void ToggleQRCode(void); +#endif + +private: + typedef struct demoState + { + bool mainState = false; + bool protocol1 = false; /* data */ + } DemoState_t; + + void WriteQRCode(); + void WriteDemoUI(); +#ifdef QR_CODE_ENABLED + void LCDFillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h); + char mQRCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + bool mShowQRCode = true; +#endif + GLIB_Context_t glibContext; + +#ifdef SL_DEMO_NAME + uint8_t mName[] = SL_DEMO_NAME +#else + uint8_t mName[APP_NAME_MAX_LENGTH + 1]; +#endif + customUICB customUI = nullptr; + DemoState_t dState; +}; diff --git a/examples/platform/silabs/SiWx917/efr32_utils.cpp b/examples/platform/silabs/SiWx917/efr32_utils.cpp new file mode 100644 index 00000000000000..bd2bf771c60152 --- /dev/null +++ b/examples/platform/silabs/SiWx917/efr32_utils.cpp @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2022 Silabs. + * 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 "efr32_utils.h" +#include "init_efrPlatform.h" +#include "sl_system_kernel.h" + +#include + +void appError(int err) +{ + SILABS_LOG("!!!!!!!!!!!! App Critical Error: %d !!!!!!!!!!!", err); + portDISABLE_INTERRUPTS(); + while (true) + ; +} + +void appError(CHIP_ERROR error) +{ + appError(static_cast(error.AsInteger())); +} diff --git a/examples/platform/silabs/SiWx917/efr32_utils.h b/examples/platform/silabs/SiWx917/efr32_utils.h new file mode 100644 index 00000000000000..b0d508de5f8fe8 --- /dev/null +++ b/examples/platform/silabs/SiWx917/efr32_utils.h @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2022 Silabs. + * 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 + +// EFR Logging +#ifdef __cplusplus +extern "C" { +#endif + +void silabsInitLog(void); + +void efr32Log(const char * aFormat, ...); +#define SILABS_LOG(...) efr32Log(__VA_ARGS__); +void appError(int err); + +#ifdef __cplusplus +} + +#include +void appError(CHIP_ERROR error); +#endif diff --git a/examples/platform/silabs/SiWx917/init_efrPlatform.cpp b/examples/platform/silabs/SiWx917/init_efrPlatform.cpp new file mode 100644 index 00000000000000..993b4fefe069f8 --- /dev/null +++ b/examples/platform/silabs/SiWx917/init_efrPlatform.cpp @@ -0,0 +1,86 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 "AppConfig.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include + +#include + +#if CHIP_ENABLE_OPENTHREAD +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "platform-efr32.h" + +#if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#include "openthread/heap.h" +#endif // OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#endif // CHIP_ENABLE_OPENTHREAD + +#include "init_efrPlatform.h" +#include "sl_component_catalog.h" +#include "sl_mbedtls.h" +#include "sl_system_init.h" + +#if SL_SYSTEM_VIEW +#include "SEGGER_SYSVIEW.h" +#endif + +void initAntenna(void); + +void init_efrPlatform(void) +{ + sl_system_init(); + sl_mbedtls_init(); +#if SL_SYSTEM_VIEW + SEGGER_SYSVIEW_Conf(); + SEGGER_SYSVIEW_Start(); +#endif + +#if SILABS_LOG_ENABLED + silabsInitLog(); +#endif + +#if CHIP_ENABLE_OPENTHREAD + efr32RadioInit(); + efr32AlarmInit(); +#endif // CHIP_ENABLE_OPENTHREAD +} + +#ifdef __cplusplus +} +#endif diff --git a/examples/platform/silabs/SiWx917/init_efrPlatform.h b/examples/platform/silabs/SiWx917/init_efrPlatform.h new file mode 100644 index 00000000000000..aeb47b8aaed3d1 --- /dev/null +++ b/examples/platform/silabs/SiWx917/init_efrPlatform.h @@ -0,0 +1,29 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*******************************************************************************/ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void init_efrPlatform(void); + +#ifdef __cplusplus +} +#endif diff --git a/examples/platform/silabs/SiWx917/ldscripts/efr32mg12.ld b/examples/platform/silabs/SiWx917/ldscripts/efr32mg12.ld new file mode 100644 index 00000000000000..f9f4f55f8b9a73 --- /dev/null +++ b/examples/platform/silabs/SiWx917/ldscripts/efr32mg12.ld @@ -0,0 +1,242 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/***************************************************************************//** + * Linker script for Silicon Labs EFR32MG12P devices + ******************************************************************************* + * # License + * Copyright 2022 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1048576 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 262144 +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapBase + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.vectors)) + + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + + LONG (__etext) + LONG (__data_start__) + LONG ((__data_end__ - __data_start__) / 4) + + __copy_table_end__ = .; + } > FLASH + + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + __zero_table_end__ = .; + } > FLASH + + __etext = ALIGN (4); + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + . = ALIGN (4); + PROVIDE (__ram_func_section_start = .); + *(.ram) + PROVIDE (__ram_func_section_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY) : + { + __HeapBase = .; + __end__ = .; + end = __end__; + _end = __end__; + KEEP(*(.heap*)) + __HeapLimit = .; + } > RAM + + __main_flash_end__ = ORIGIN(FLASH) + LENGTH(FLASH); + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + KEEP(*(.stack*)) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + .nvm (DSECT) : { + KEEP(*(.simee*)) + } > FLASH + + /* Last page of flash is reserved for the manufacturing token space */ + linker_nvm_end = __main_flash_end__ - 2048; + linker_nvm_begin = linker_nvm_end - SIZEOF(.nvm); + linker_nvm_size = SIZEOF(.nvm); + __nvm3Base = linker_nvm_begin; + __attestation_credentials_base = linker_nvm_end; + + /* Check if data + heap + stack exceeds RAM limit */ + /*ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")*/ + ASSERT( (linker_nvm_begin + SIZEOF(.nvm)) <= __main_flash_end__, "NVM3 is excessing the flash size !") + + /* Check if FLASH usage exceeds FLASH size */ + ASSERT( LENGTH(FLASH) >= (__etext), "FLASH memory overflowed !") + ASSERT((__etext + SIZEOF(.data)) <= __nvm3Base, "FLASH memory overlapped with NVM section.") +} diff --git a/examples/platform/silabs/SiWx917/ldscripts/efr32mg21.ld b/examples/platform/silabs/SiWx917/ldscripts/efr32mg21.ld new file mode 100644 index 00000000000000..2c9de0ddede7d7 --- /dev/null +++ b/examples/platform/silabs/SiWx917/ldscripts/efr32mg21.ld @@ -0,0 +1,289 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/***************************************************************************//** + * Linker script for Silicon Labs EFR32MG21 devices + * @version 5.7.2 + ******************************************************************************* + * # License + * Copyright 2018 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1048576 - 8192 /* 8K is reserved at top of flash on MG21 */ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 98304 +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapBase + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * __Vectors_End + * __Vectors_Size + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.vectors)) + __Vectors_End = .; + __Vectors_Size = __Vectors_End - __Vectors; + __end__ = .; + + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + KEEP(*(.application_properties)) + KEEP(*(.gecko_configuration)) + KEEP(*(.xo_configuration)) + KEEP(*(.gatt_header)) + KEEP(*(.gatt_data)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + + KEEP(*(.eh_frame*)) + } > FLASH + + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + __etext = .; + + /*******************************************************************/ + /* Define flash block for BLE-simee & CHIP-nvm3 */ + /* simee: 9000H (36k) bytes for BLE nvm3 */ + /* chipNvm3_section: 4000H (16k) bytes for CHIP nvm3. */ + /* 8K is reserved for OpenThread's NVM which is mapped directly at */ + /* the top of flash */ + /*******************************************************************/ + + OPENTHREAD_NVM_SIZE = 8192; + + .nvm_dummy (DSECT): + { + __nvm3_dummy_begin = .; + . = ALIGN (8192); + __nvm3_dummy_simee = .; + KEEP(*(.simee)); + . = ALIGN (8192); + __nvm3_dummy_chip = .; + KEEP(*(chipNvm3_section)); + . = ALIGN (8192); + . += OPENTHREAD_NVM_SIZE; + . = ALIGN (8192); + } > FLASH + + /* Set NVM to end of FLASH */ + __nvm3Base = LENGTH(FLASH) - SIZEOF(.nvm_dummy) + (__nvm3_dummy_simee - __nvm3_dummy_begin); + __nvm3ChipBase = LENGTH(FLASH) - SIZEOF(.nvm_dummy) + (__nvm3_dummy_chip - __nvm3_dummy_begin); + + + /*******************************************************************/ + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + . = ALIGN (4); + PROVIDE (__ram_func_section_start = .); + *(.ram) + PROVIDE (__ram_func_section_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __HeapBase = .; + __end__ = .; + end = __end__; + _end = __end__; + KEEP(*(.heap*)) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + KEEP(*(.stack*)) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") + + + /* Check if FLASH usage exceeds FLASH size */ + ASSERT( LENGTH(FLASH) >= (__etext + SIZEOF(.data)), "FLASH memory overflowed !") + ASSERT((__etext + SIZEOF(.data)) <= __nvm3Base, "FLASH memory overlapped with NVM section.") +} \ No newline at end of file diff --git a/examples/platform/silabs/SiWx917/ldscripts/efr32mg24.ld b/examples/platform/silabs/SiWx917/ldscripts/efr32mg24.ld new file mode 100644 index 00000000000000..b057a9af720a7a --- /dev/null +++ b/examples/platform/silabs/SiWx917/ldscripts/efr32mg24.ld @@ -0,0 +1,243 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/***************************************************************************//** + * @file gcc_EFR32MG24.ld + * @brief GNU Linker Script for Cortex-M based device + * @version V2.2.0 + * @date 16. December 2020 + * Linker script for Silicon Labs EFR32MG24 devices + ******************************************************************************* + * # License + * Copyright 2022 Silicon Laboratories, Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08006000, LENGTH = 0x17A000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x40000 +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * __StackSeal (only if ARMv8-M stack sealing is used) + */ + +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.vectors)) + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + + LONG (__etext) + LONG (__data_start__) + LONG ((__data_end__ - __data_start__) / 4) + + __copy_table_end__ = .; + } > FLASH + + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + __zero_table_end__ = .; + __etext = ALIGN(4); + } > FLASH + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + . = ALIGN (4); + PROVIDE (__ram_func_section_start = .); + *(.ram) + PROVIDE (__ram_func_section_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM AT > RAM + + .heap (COPY): + { + __HeapBase = .; + __end__ = .; + end = __end__; + _end = __end__; + KEEP(*(.heap*)) + __HeapLimit = .; + } > RAM + + __main_flash_end__ = ORIGIN(FLASH) + LENGTH(FLASH); + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + KEEP(*(.stack*)) + /* KEEP(*(.stackseal*))*/ + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + .nvm (DSECT) : { + KEEP(*(.simee*)) + } > FLASH + + /* Last page of flash is reserved for the manufacturing token space */ + linker_nvm_end = __main_flash_end__ - 8192; + linker_nvm_begin = linker_nvm_end - SIZEOF(.nvm); + linker_nvm_size = SIZEOF(.nvm); + __nvm3Base = linker_nvm_begin; + __attestation_credentials_base = linker_nvm_end; + + /* Check if data + heap + stack exceeds RAM limit */ + /*ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")*/ + ASSERT( (linker_nvm_begin + SIZEOF(.nvm)) <= __main_flash_end__, "NVM3 is excessing the flash size !") + + /* Check if FLASH usage exceeds FLASH size */ + ASSERT( LENGTH(FLASH) >= (__etext + SIZEOF(.data)), "FLASH memory overflowed !") +} diff --git a/examples/platform/silabs/SiWx917/ldscripts/mgm24.ld b/examples/platform/silabs/SiWx917/ldscripts/mgm24.ld new file mode 100644 index 00000000000000..b057a9af720a7a --- /dev/null +++ b/examples/platform/silabs/SiWx917/ldscripts/mgm24.ld @@ -0,0 +1,243 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/***************************************************************************//** + * @file gcc_EFR32MG24.ld + * @brief GNU Linker Script for Cortex-M based device + * @version V2.2.0 + * @date 16. December 2020 + * Linker script for Silicon Labs EFR32MG24 devices + ******************************************************************************* + * # License + * Copyright 2022 Silicon Laboratories, Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08006000, LENGTH = 0x17A000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x40000 +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * __StackSeal (only if ARMv8-M stack sealing is used) + */ + +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.vectors)) + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + + LONG (__etext) + LONG (__data_start__) + LONG ((__data_end__ - __data_start__) / 4) + + __copy_table_end__ = .; + } > FLASH + + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + __zero_table_end__ = .; + __etext = ALIGN(4); + } > FLASH + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + . = ALIGN (4); + PROVIDE (__ram_func_section_start = .); + *(.ram) + PROVIDE (__ram_func_section_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM AT > RAM + + .heap (COPY): + { + __HeapBase = .; + __end__ = .; + end = __end__; + _end = __end__; + KEEP(*(.heap*)) + __HeapLimit = .; + } > RAM + + __main_flash_end__ = ORIGIN(FLASH) + LENGTH(FLASH); + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + KEEP(*(.stack*)) + /* KEEP(*(.stackseal*))*/ + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + .nvm (DSECT) : { + KEEP(*(.simee*)) + } > FLASH + + /* Last page of flash is reserved for the manufacturing token space */ + linker_nvm_end = __main_flash_end__ - 8192; + linker_nvm_begin = linker_nvm_end - SIZEOF(.nvm); + linker_nvm_size = SIZEOF(.nvm); + __nvm3Base = linker_nvm_begin; + __attestation_credentials_base = linker_nvm_end; + + /* Check if data + heap + stack exceeds RAM limit */ + /*ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")*/ + ASSERT( (linker_nvm_begin + SIZEOF(.nvm)) <= __main_flash_end__, "NVM3 is excessing the flash size !") + + /* Check if FLASH usage exceeds FLASH size */ + ASSERT( LENGTH(FLASH) >= (__etext + SIZEOF(.data)), "FLASH memory overflowed !") +} diff --git a/examples/platform/silabs/SiWx917/matter_config.cpp b/examples/platform/silabs/SiWx917/matter_config.cpp new file mode 100644 index 00000000000000..83e909588d9811 --- /dev/null +++ b/examples/platform/silabs/SiWx917/matter_config.cpp @@ -0,0 +1,243 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2022 Silabs. + * 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 "AppConfig.h" +#include "OTAConfig.h" +#include + +#include + +#include + +#ifdef SL_WIFI +#include "wfx_host_events.h" +#endif /* SL_WIFI */ + +#if PW_RPC_ENABLED +#include "Rpc.h" +#endif + +#ifdef ENABLE_CHIP_SHELL +#include "matter_shell.h" +#endif + +#ifdef HEAP_MONITORING +#include "MemMonitoring.h" +#endif + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; + +#include +// If building with the EFR32-provided crypto backend, we can use the +// opaque keystore +#if CHIP_CRYPTO_PLATFORM +#include +static chip::DeviceLayer::Internal::Efr32PsaOperationalKeystore gOperationalKeystore; +#endif + +#include "EFR32DeviceDataProvider.h" + +#if CHIP_ENABLE_OPENTHREAD +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ================================================================================ +// Matter Networking Callbacks +// ================================================================================ +void LockOpenThreadTask(void) +{ + chip::DeviceLayer::ThreadStackMgr().LockThreadStack(); +} + +void UnlockOpenThreadTask(void) +{ + chip::DeviceLayer::ThreadStackMgr().UnlockThreadStack(); +} + +// ================================================================================ +// EFR32MatterConfig Methods +// ================================================================================ + +CHIP_ERROR EFR32MatterConfig::InitOpenThread(void) +{ + SILABS_LOG("Initializing OpenThread stack"); + ReturnErrorOnFailure(ThreadStackMgr().InitThreadStack()); + +#if CHIP_DEVICE_CONFIG_THREAD_FTD + ReturnErrorOnFailure(ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_Router)); +#else // CHIP_DEVICE_CONFIG_THREAD_FTD +#if CHIP_DEVICE_CONFIG_ENABLE_SED + ReturnErrorOnFailure(ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SleepyEndDevice)); +#else // CHIP_DEVICE_CONFIG_ENABLE_SED + ReturnErrorOnFailure(ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_MinimalEndDevice)); +#endif // CHIP_DEVICE_CONFIG_ENABLE_SED +#endif // CHIP_DEVICE_CONFIG_THREAD_FTD + + SILABS_LOG("Starting OpenThread task"); + return ThreadStackMgrImpl().StartThreadTask(); +} +#endif // CHIP_ENABLE_OPENTHREAD + +#if EFR32_OTA_ENABLED +void EFR32MatterConfig::InitOTARequestorHandler(System::Layer * systemLayer, void * appState) +{ + OTAConfig::Init(); +} +#endif + +void EFR32MatterConfig::ConnectivityEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + // Initialize OTA only when Thread or WiFi connectivity is established + if (((event->Type == DeviceEventType::kThreadConnectivityChange) && + (event->ThreadConnectivityChange.Result == kConnectivity_Established)) || + ((event->Type == DeviceEventType::kInternetConnectivityChange) && + (event->InternetConnectivityChange.IPv6 == kConnectivity_Established))) + { +#if EFR32_OTA_ENABLED + SILABS_LOG("Scheduling OTA Requestor initialization") + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(OTAConfig::kInitOTARequestorDelaySec), + InitOTARequestorHandler, nullptr); +#endif + } +} + +CHIP_ERROR EFR32MatterConfig::InitMatter(const char * appName) +{ + CHIP_ERROR err; + + mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree); + + SILABS_LOG("=================================================="); + SILABS_LOG("%s starting", appName); + SILABS_LOG("=================================================="); + +#if PW_RPC_ENABLED + chip::rpc::Init(); +#endif + +#ifdef HEAP_MONITORING + MemMonitoring::startHeapMonitoring(); +#endif + SetDeviceInstanceInfoProvider(&EFR32::EFR32DeviceDataProvider::GetDeviceDataProvider()); + SetCommissionableDataProvider(&EFR32::EFR32DeviceDataProvider::GetDeviceDataProvider()); + + //============================================== + // Init Matter Stack + //============================================== + SILABS_LOG("Init CHIP Stack"); + // Init Chip memory management before the stack + ReturnErrorOnFailure(chip::Platform::MemoryInit()); + ReturnErrorOnFailure(PlatformMgr().InitChipStack()); + + chip::DeviceLayer::ConnectivityMgr().SetBLEDeviceName(appName); + +#if CHIP_ENABLE_OPENTHREAD + ReturnErrorOnFailure(InitOpenThread()); +#endif + + // Stop Matter event handling while setting up resources + chip::DeviceLayer::PlatformMgr().LockChipStack(); + + // Create initParams with SDK example defaults here + static chip::CommonCaseDeviceServerInitParams initParams; + +#if CHIP_CRYPTO_PLATFORM + // When building with EFR32 crypto, use the opaque key store + // instead of the default (insecure) one. + gOperationalKeystore.Init(); + initParams.operationalKeystore = &gOperationalKeystore; +#endif + + // Initialize the remaining (not overridden) providers to the SDK example defaults + (void) initParams.InitializeStaticResourcesBeforeServerInit(); + +#if CHIP_ENABLE_OPENTHREAD + // Set up OpenThread configuration when OpenThread is included + chip::Inet::EndPointStateOpenThread::OpenThreadEndpointInitParam nativeParams; + nativeParams.lockCb = LockOpenThreadTask; + nativeParams.unlockCb = UnlockOpenThreadTask; + nativeParams.openThreadInstancePtr = chip::DeviceLayer::ThreadStackMgrImpl().OTInstance(); + initParams.endpointNativeParams = static_cast(&nativeParams); +#endif + + // Init Matter Server and Start Event Loop + err = chip::Server::GetInstance().Init(initParams); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + + ReturnErrorOnFailure(err); + + // OTA Requestor initialization will be triggered by the connectivity events + PlatformMgr().AddEventHandler(ConnectivityEventCallback, reinterpret_cast(nullptr)); + + SILABS_LOG("Starting Platform Manager Event Loop"); + ReturnErrorOnFailure(PlatformMgr().StartEventLoopTask()); + +#ifdef SL_WIFI + InitWiFi(); +#endif + +#ifdef ENABLE_CHIP_SHELL + chip::startShellTask(); +#endif + + return CHIP_NO_ERROR; +} + +#ifdef SL_WIFI +void EFR32MatterConfig::InitWiFi(void) +{ +#ifdef WF200_WIFI + // Start wfx bus communication task. + wfx_bus_start(); +#ifdef SL_WFX_USE_SECURE_LINK + wfx_securelink_task_start(); // start securelink key renegotiation task +#endif // SL_WFX_USE_SECURE_LINK +#endif /* WF200_WIFI */ + +#ifdef RS911X_WIFI + /* + * Start up any RSI interface stuff + * (Not required) - Note that wfx_wifi_start will deal with + * starting up a rsi task - which will initialize the SPI interface. + */ +#endif +} +#endif // SL_WIFI + +// ================================================================================ +// FreeRTOS Callbacks +// ================================================================================ +extern "C" void vApplicationIdleHook(void) +{ + // FreeRTOS Idle callback + + // Check CHIP Config nvm3 and repack flash if necessary. + Internal::SILABSConfig::RepackNvm3Flash(); +} diff --git a/examples/platform/silabs/SiWx917/matter_config.h b/examples/platform/silabs/SiWx917/matter_config.h new file mode 100644 index 00000000000000..e0af60356becf9 --- /dev/null +++ b/examples/platform/silabs/SiWx917/matter_config.h @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2022 Silabs. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +class EFR32MatterConfig +{ +public: + static CHIP_ERROR InitMatter(const char * appName); + +private: + static CHIP_ERROR InitOpenThread(void); + static void InitWiFi(void); + static void ConnectivityEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + static void InitOTARequestorHandler(chip::System::Layer * systemLayer, void * appState); +}; diff --git a/examples/platform/silabs/SiWx917/project_include/OpenThreadConfig.h b/examples/platform/silabs/SiWx917/project_include/OpenThreadConfig.h new file mode 100644 index 00000000000000..dccf3c816b7b66 --- /dev/null +++ b/examples/platform/silabs/SiWx917/project_include/OpenThreadConfig.h @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 + * Overrides to default OpenThread configuration. + * + */ + +#pragma once + +#include + +// Disable the SiLabs-supplied OpenThread logging facilities and use +// the facilities provided by the Device Layer (see +// src/platform/silabs/Logging.cpp). +#define OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_APP + +// Turn on a moderate level of logging in OpenThread +// Enable use of external heap allocator (calloc/free) for OpenThread. +#define OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE 1 + +// EFR32MG21A020F1024IM32 has 96k of RAM. Reduce the number of buffers to +// conserve RAM for this Series 2 part. +#if defined(EFR32MG21) +#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 22 +#define OPENTHREAD_CONFIG_CLI_UART_TX_BUFFER_SIZE 512 +#define OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE 512 +#endif + +#define OPENTHREAD_CONFIG_NCP_HDLC_ENABLE 1 +#define OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE 1 + +#define OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_ECDSA_ENABLE 1 + +// disable unused features +#define OPENTHREAD_CONFIG_COAP_API_ENABLE 0 +#define OPENTHREAD_CONFIG_JOINER_ENABLE 0 +#define OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 0 +#define OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 0 +#define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 0 +#define OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE 0 +#define OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE 0 +#define OPENTHREAD_CONFIG_TCP_ENABLE 0 + +// Support udp multicast by enabling Multicast Listener Registration (MLR) +#define OPENTHREAD_CONFIG_MLR_ENABLE 1 + +// Define as 1 to stay awake between fragments while transmitting a large packet, +// and to stay awake after receiving a packet with frame pending set to true. +#define OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS 1 + +// Use the SiLabs-supplied default platform configuration for remainder +// of OpenThread config options. +// +// NB: This file gets included during the build of OpenThread. Hence +// it cannot use "openthread" in the path to the included file. +// +#include "openthread-core-efr32-config.h" diff --git a/examples/platform/silabs/SiWx917/pw_sys_io/BUILD.gn b/examples/platform/silabs/SiWx917/pw_sys_io/BUILD.gn new file mode 100644 index 00000000000000..722d2a7cad24e6 --- /dev/null +++ b/examples/platform/silabs/SiWx917/pw_sys_io/BUILD.gn @@ -0,0 +1,39 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") + +import("$dir_pw_build/target_types.gni") + +examples_plat_dir = "${chip_root}/examples/platform/silabs/efr32" + +config("default_config") { + include_dirs = [ "public" ] +} + +pw_source_set("pw_sys_io_efr32") { + sources = [ "sys_io_efr32.cc" ] + + deps = [ + "$dir_pw_sys_io:default_putget_bytes", + "$dir_pw_sys_io:facade", + ] + + cflags = [ "-Wconversion" ] + + public_configs = [ ":default_config" ] + + include_dirs = [ "${examples_plat_dir}" ] +} diff --git a/examples/platform/silabs/SiWx917/pw_sys_io/public/pw_sys_io_efr32/init.h b/examples/platform/silabs/SiWx917/pw_sys_io/public/pw_sys_io_efr32/init.h new file mode 100644 index 00000000000000..f11f5e928f3e14 --- /dev/null +++ b/examples/platform/silabs/SiWx917/pw_sys_io/public/pw_sys_io_efr32/init.h @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "pw_preprocessor/util.h" + +PW_EXTERN_C_START + +// The actual implement of PreMainInit() in sys_io_BACKEND. +void pw_sys_io_Init(); + +PW_EXTERN_C_END diff --git a/examples/platform/silabs/SiWx917/pw_sys_io/sys_io_efr32.cc b/examples/platform/silabs/SiWx917/pw_sys_io/sys_io_efr32.cc new file mode 100644 index 00000000000000..4bc7d98f7477c4 --- /dev/null +++ b/examples/platform/silabs/SiWx917/pw_sys_io/sys_io_efr32.cc @@ -0,0 +1,81 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pw_sys_io/sys_io.h" +#include +#include +#include +#include + +#include "uart.h" + +int16_t console_getchar(char * chr) +{ + int16_t retVal = 0; + + // Busy wait for pw_rcp reads + while (retVal == 0) + { + retVal = uartConsoleRead(chr, 1); + } + return retVal; +} + +int16_t console_putchar(const char * chr) +{ + return uartConsoleWrite(chr, 1); +} + +extern "C" void pw_sys_io_Init() +{ + uartConsoleInit(); +} + +namespace pw::sys_io { + +Status ReadByte(std::byte * dest) +{ + if (!dest) + return Status::InvalidArgument(); + + int16_t ret = console_getchar(reinterpret_cast(dest)); + return ret < 0 ? Status::FailedPrecondition() : OkStatus(); +} + +Status WriteByte(std::byte b) +{ + int16_t ret = console_putchar(reinterpret_cast(&b)); + return ret < 0 ? Status::FailedPrecondition() : OkStatus(); +} + +// Writes a string using pw::sys_io, and add newline characters at the end. +StatusWithSize WriteLine(const std::string_view & s) +{ + size_t chars_written = 0; + StatusWithSize result = WriteBytes(pw::as_bytes(pw::span(s))); + if (!result.ok()) + { + return result; + } + chars_written += result.size(); + result = WriteBytes(pw::as_bytes(pw::span("\r\n", 2))); + chars_written += result.size(); + + return StatusWithSize(result.status(), chars_written); +} + +} // namespace pw::sys_io diff --git a/examples/platform/silabs/SiWx917/rs911x/hal/efx_spi.c b/examples/platform/silabs/SiWx917/rs911x/hal/efx_spi.c new file mode 100644 index 00000000000000..f01cac3b657c7c --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/hal/efx_spi.c @@ -0,0 +1,324 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Includes + */ +#include +#include +#include + +#include "dmadrv.h" +#include "em_chip.h" +#include "em_cmu.h" +#include "em_core.h" +#include "em_device.h" +#include "em_gpio.h" +#include "em_ldma.h" +#if defined(EFR32MG12) +#include "em_usart.h" +#elif defined(EFR32MG24) +#include "em_eusart.h" +#endif +#include "spidrv.h" + +#include "gpiointerrupt.h" +#include "sl_device_init_clocks.h" +#include "sl_status.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" + +#include "wfx_host_events.h" +#include "wfx_rsi.h" + +#include "rsi_board_configuration.h" +#include "rsi_driver.h" +#include "sl_device_init_dpll.h" +#include "sl_device_init_hfxo.h" + +StaticSemaphore_t xEfxSpiIntfSemaBuffer; +static SemaphoreHandle_t spi_sem; + +#if defined(EFR32MG12) +#include "sl_spidrv_exp_config.h" +extern SPIDRV_Handle_t sl_spidrv_exp_handle; +#endif + +#if defined(EFR32MG24) +#include "sl_spidrv_eusart_exp_config.h" +extern SPIDRV_Handle_t sl_spidrv_eusart_exp_handle; +#endif + +static unsigned int tx_dma_channel; +static unsigned int rx_dma_channel; + +static uint32_t dummy_data; /* Used for DMA - when results don't matter */ +extern void rsi_gpio_irq_cb(uint8_t irqnum); +//#define RS911X_USE_LDMA + +/******************************************************** + * @fn sl_wfx_host_gpio_init(void) + * @brief + * Deal with the PINS that are not associated with SPI - + * Ie. RESET, Wakeup + * @return + * None + **********************************************************/ +void sl_wfx_host_gpio_init(void) +{ + // Enable GPIO clock. + CMU_ClockEnable(cmuClock_GPIO, true); + + GPIO_PinModeSet(WFX_RESET_PIN.port, WFX_RESET_PIN.pin, gpioModePushPull, PINOUT_SET); + GPIO_PinModeSet(WFX_SLEEP_CONFIRM_PIN.port, WFX_SLEEP_CONFIRM_PIN.pin, gpioModePushPull, PINOUT_CLEAR); + + CMU_OscillatorEnable(cmuOsc_LFXO, true, true); + + // Set up interrupt based callback function - trigger on both edges. + GPIOINT_Init(); + GPIO_PinModeSet(WFX_INTERRUPT_PIN.port, WFX_INTERRUPT_PIN.pin, gpioModeInputPull, PINOUT_CLEAR); + GPIO_ExtIntConfig(WFX_INTERRUPT_PIN.port, WFX_INTERRUPT_PIN.pin, SL_WFX_HOST_PINOUT_SPI_IRQ, true, false, true); + GPIOINT_CallbackRegister(SL_WFX_HOST_PINOUT_SPI_IRQ, rsi_gpio_irq_cb); + GPIO_IntDisable(1 << SL_WFX_HOST_PINOUT_SPI_IRQ); /* Will be enabled by RSI */ + + // Change GPIO interrupt priority (FreeRTOS asserts unless this is done here!) + NVIC_SetPriority(GPIO_EVEN_IRQn, WFX_SPI_NVIC_PRIORITY); + NVIC_SetPriority(GPIO_ODD_IRQn, WFX_SPI_NVIC_PRIORITY); +} + +/***************************************************************** + * @fn void sl_wfx_host_reset_chip(void) + * @brief + * To reset the WiFi CHIP + * @return + * None + ****************************************************************/ +void sl_wfx_host_reset_chip(void) +{ + // Pull it low for at least 1 ms to issue a reset sequence + GPIO_PinOutClear(WFX_RESET_PIN.port, WFX_RESET_PIN.pin); + + // Delay for 10ms + vTaskDelay(pdMS_TO_TICKS(10)); + + // Hold pin high to get chip out of reset + GPIO_PinOutSet(WFX_RESET_PIN.port, WFX_RESET_PIN.pin); + + // Delay for 3ms + vTaskDelay(pdMS_TO_TICKS(3)); +} + +/***************************************************************** + * @fn void rsi_hal_board_init(void) + * @brief + * Initialize the board + * @return + * None + ****************************************************************/ +void rsi_hal_board_init(void) +{ + spi_sem = xSemaphoreCreateBinaryStatic(&xEfxSpiIntfSemaBuffer); + xSemaphoreGive(spi_sem); + + /* Assign DMA channel from Handle*/ +#if defined(EFR32MG12) + /* MG12 + rs9116 combination uses USART driver */ + tx_dma_channel = sl_spidrv_exp_handle->txDMACh; + rx_dma_channel = sl_spidrv_exp_handle->rxDMACh; + +#elif defined(EFR32MG24) + /* MG24 + rs9116 combination uses EUSART driver */ + tx_dma_channel = sl_spidrv_eusart_exp_handle->txDMACh; + rx_dma_channel = sl_spidrv_eusart_exp_handle->rxDMACh; +#endif + + /* GPIO INIT of MG12 & MG24 : Reset, Wakeup, Interrupt */ + WFX_RSI_LOG("RSI_HAL: init GPIO"); + sl_wfx_host_gpio_init(); + + /* Reset of Wifi chip */ + WFX_RSI_LOG("RSI_HAL: Reset Wifi"); + sl_wfx_host_reset_chip(); + WFX_RSI_LOG("RSI_HAL: Init done"); +} + +/***************************************************************************** + *@fn static bool rx_dma_complete(unsigned int channel, unsigned int sequenceNo, void *userParam) + * + *@brief + * complete dma + * + * @param[in] channel: + * @param[in] sequenceNO: sequence number + * @param[in] userParam :user parameter + * + * @return + * None + ******************************************************************************/ +static bool rx_dma_complete(unsigned int channel, unsigned int sequenceNo, void * userParam) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // uint8_t *buf = (void *)userParam; + + (void) channel; + (void) sequenceNo; + (void) userParam; + + // WFX_RSI_LOG ("SPI: DMA done [%x,%x,%x,%x]", buf [0], buf [1], buf [2], buf [3]); + xSemaphoreGiveFromISR(spi_sem, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + + return true; +} + +/************************************************************* + * @fn static void receiveDMA(uint8_t *rx_buf, uint16_t xlen) + * @brief + * RX buf was specified + * TX buf was not specified by caller - so we + * transmit dummy data (typically 0) + * @param[in] rx_buf: + * @param[in] xlen: + * @return + * None + *******************************************************************/ +static void receiveDMA(uint8_t * rx_buf, uint16_t xlen) +{ + /* + * The caller wants to receive data - + * The xmit can be dummy data (no src increment for tx) + */ + dummy_data = 0; + DMADRV_PeripheralMemory(rx_dma_channel, MY_USART_RX_SIGNAL, (void *) rx_buf, (void *) &(MY_USART->RXDATA), true, xlen, + dmadrvDataSize1, rx_dma_complete, NULL); + + // Start transmit DMA. + DMADRV_MemoryPeripheral(tx_dma_channel, MY_USART_TX_SIGNAL, (void *) &(MY_USART->TXDATA), (void *) &(dummy_data), false, xlen, + dmadrvDataSize1, NULL, NULL); +} + +/***************************************************************************** + *@fn static void transmitDMA(void *rx_buf, void *tx_buf, uint8_t xlen) + *@brief + * we have a tx_buf. There are some instances where + * a rx_buf is not specified. If one is specified then + * the caller wants results (auto increment src) + * @param[in] rx_buf: + * @param[in] tx_buf: + * @param[in] xlen: + * @return + * None + ******************************************************************************/ +static void transmitDMA(uint8_t * rx_buf, uint8_t * tx_buf, uint16_t xlen) +{ + void * buf; + bool srcinc; + /* + * we have a tx_buf. There are some instances where + * a rx_buf is not specified. If one is specified then + * the caller wants results (auto increment src) + * TODO - the caller specified 8/32 bit - we should use this + * instead of dmadrvDataSize1 always + */ + if (rx_buf == NULL) + { + buf = &dummy_data; + srcinc = false; + } + else + { + buf = rx_buf; + srcinc = true; + /* DEBUG */ rx_buf[0] = 0xAA; + rx_buf[1] = 0x55; + } + DMADRV_PeripheralMemory(rx_dma_channel, MY_USART_RX_SIGNAL, buf, (void *) &(MY_USART->RXDATA), srcinc, xlen, dmadrvDataSize1, + rx_dma_complete, buf); + // Start transmit DMA. + DMADRV_MemoryPeripheral(tx_dma_channel, MY_USART_TX_SIGNAL, (void *) &(MY_USART->TXDATA), (void *) tx_buf, true, xlen, + dmadrvDataSize1, NULL, NULL); +} + +/********************************************************************* + * @fn int16_t rsi_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t xlen, uint8_t mode) + * @brief + * Do a SPI transfer - Mode is 8/16 bit - But every 8 bit is aligned + * @param[in] tx_buf: + * @param[in] rx_buf: + * @param[in] xlen: + * @param[in] mode: + * @return + * None + **************************************************************************/ +int16_t rsi_spi_transfer(uint8_t * tx_buf, uint8_t * rx_buf, uint16_t xlen, uint8_t mode) +{ + // WFX_RSI_LOG ("SPI: Xfer: tx=%x,rx=%x,len=%d",(uint32_t)tx_buf, (uint32_t)rx_buf, xlen); + if (xlen > MIN_XLEN) + { + MY_USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX; + if (xSemaphoreTake(spi_sem, portMAX_DELAY) != pdTRUE) + { + return RSI_FALSE; + } + if (tx_buf == NULL) + { + receiveDMA(rx_buf, xlen); + } + else + { + transmitDMA(rx_buf, tx_buf, xlen); + } + + /* + * receiveDMA() and transmitDMA() are asynchronous + * Our application design assumes that this function is synchronous + * To make it synchronous, we wait to re-acquire the semaphore before exiting this function + * rx_dma_complete() gives back the semaphore when the SPI transfer is done + */ + if (xSemaphoreTake(spi_sem, pdMS_TO_TICKS(RSI_SEM_BLOCK_MIN_TIMER_VALUE_MS)) == pdTRUE) + { + // Transfer complete + // Give back the semaphore before exiting, so that it may be re-acquired + // in this function, just before the next transfer + xSemaphoreGive(spi_sem); + } + // Temporary patch + // Sometimes the xSemaphoreTake() above is getting stuck indefinitely + // As a workaround, if the transfer is not done within RSI_SEM_BLOCK_MIN_TIMER_VALUE_MS + // stop and start it again + // No need to re-acquire the semaphore since this is the function that acquired it + // TODO: Remove this after a permanent solution is found to the problem of the transfer getting stuck + else + { + uint32_t ldma_flags = 0; + uint32_t rem_len = 0; + rem_len = LDMA_TransferRemainingCount(RSI_LDMA_TRANSFER_CHANNEL_NUM); + LDMA_StopTransfer(RSI_LDMA_TRANSFER_CHANNEL_NUM); + ldma_flags = LDMA_IntGet(); + LDMA_IntClear(ldma_flags); + receiveDMA(rx_buf, rem_len); + if (xSemaphoreTake(spi_sem, portMAX_DELAY) == pdTRUE) + { + xSemaphoreGive(spi_sem); + } + } + } + + return RSI_ERROR_NONE; +} diff --git a/examples/platform/silabs/SiWx917/rs911x/hal/rsi_board_configuration.h b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_board_configuration.h new file mode 100644 index 00000000000000..204e7519d29b5b --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_board_configuration.h @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _RSI_BOARD_CONFIGURATION_H_ +#define _RSI_BOARD_CONFIGURATION_H_ + +typedef struct +{ + unsigned char port; + unsigned char pin; +} rsi_pin_t; + +#define PIN(port_id, pin_id) \ + (rsi_pin_t) { .port = gpioPort##port_id, .pin = pin_id } + +#if defined(EFR32MG12_BRD4161A) || defined(BRD4161A) || defined(EFR32MG12_BRD4162A) || defined(BRD4162A) || \ + defined(EFR32MG12_BRD4163A) || defined(BRD4163A) || defined(EFR32MG12_BRD4164A) || defined(BRD4164A) || \ + defined(EFR32MG12_BRD4170A) || defined(BRD4170A) +// BRD4161-63-64 are pin to pin compatible for SPI +#include "brd4161a.h" +#elif defined(EFR32MG24_BRD4186C) || defined(BRD4186C) +#include "brd4186c.h" +#elif defined(EFR32MG24_BRD4187C) || defined(BRD4187C) +#include "brd4187c.h" +#else +#error "Need SPI Pins" +#endif /* EFR32MG12_BRD4161A */ + +#endif /* _RSI_BOARD_CONFIGURATION_H_ */ diff --git a/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal.h b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal.h new file mode 100644 index 00000000000000..4e195433edc57f --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal.h @@ -0,0 +1,111 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _HAL_RSI_HAL_H_ +#define _HAL_RSI_HAL_H_ +#include "rsi_board_configuration.h" + +#define RSI_HAL_NO_COM_PORT /* This will be done by the project */ + +/* Should be enums */ +#define RSI_HAL_RESET_PIN 0 +#define RSI_HAL_MODULE_INTERRUPT 1 +#define RSI_HAL_SLEEP_CONFIRM_PIN 2 +#define RSI_HAL_WAKEUP_INDICATION_PIN 3 +#define RSI_HAL_MODULE_INTERRUPT_PIN 4 + +//! Timer related macros +//! Macro to configure timer type in single shot +#define RSI_HAL_TIMER_TYPE_SINGLE_SHOT 0 + +// Macro to configure timer type in periodic +#define RSI_HAL_TIMER_TYPE_PERIODIC 1 + +// Macro to configure timer in micro seconds mode +#define RSI_HAL_TIMER_MODE_MICRO 0 + +// Macro to configure timer in milli seconds mode +#define RSI_HAL_TIMER_MODE_MILLI 1 + +//! GPIO Pins related Macros +//! Macro to configure GPIO in output mode +#define RSI_HAL_GPIO_OUTPUT_MODE 1 + +// Macro to configure GPIO in input mode +#define RSI_HAL_GPIO_INPUT_MODE 0 + +// Macro to drive low value on GPIO +#define RSI_HAL_GPIO_LOW 0 + +// Macro to drive high value on GPIO +#define RSI_HAL_GPIO_HIGH 1 + +// Macro to drive LDMA channel number +#define RSI_LDMA_TRANSFER_CHANNEL_NUM 3 + +// Macro to drive semaphore block minimun timer in milli seconds +#define RSI_SEM_BLOCK_MIN_TIMER_VALUE_MS 50 + +/****************************************************** + * * Function Declarations + * ******************************************************/ + +void rsi_hal_board_init(void); +void rsi_switch_to_high_clk_freq(void); +void rsi_hal_intr_config(void (*rsi_interrupt_handler)(void)); +void rsi_hal_intr_mask(void); +void rsi_hal_intr_unmask(void); +void rsi_hal_intr_clear(void); +uint8_t rsi_hal_intr_pin_status(void); +void rsi_hal_config_gpio(uint8_t gpio_number, uint8_t mode, uint8_t value); +void rsi_hal_set_gpio(uint8_t gpio_number); +uint8_t rsi_hal_get_gpio(uint8_t gpio_number); +void rsi_hal_clear_gpio(uint8_t gpio_number); +int16_t rsi_spi_transfer(uint8_t * tx_buff, uint8_t * rx_buff, uint16_t transfer_length, uint8_t mode); +int16_t rsi_uart_send(uint8_t * ptrBuf, uint16_t bufLen); +int16_t rsi_uart_recv(uint8_t * ptrBuf, uint16_t bufLen); +int16_t rsi_com_port_send(uint8_t * ptrBuf, uint16_t bufLen); +int16_t rsi_com_port_receive(uint8_t * ptrBuf, uint16_t bufLen); +uint32_t rsi_get_random_number(void); +int32_t rsi_timer_start(uint8_t timer_node, uint8_t mode, uint8_t type, uint32_t duration, void (*rsi_timer_expiry_handler)(void)); +int32_t rsi_timer_stop(uint8_t timer_node); +uint32_t rsi_timer_read(uint8_t timer_node); +void rsi_delay_us(uint32_t delay_us); +void rsi_delay_ms(uint32_t delay_ms); +uint32_t rsi_hal_gettickcount(void); +void SysTick_Handler(void); + +void rsi_interrupt_handler(void); +void ABRD(void); + +void Error_Handler(void); + +/* RTC Related API's */ +uint32_t rsi_rtc_get_time(void); +int32_t rsi_rtc_set_time(uint32_t time); +/* End - RTC Related API's */ + +#ifdef LOGGING_STATS +void rsi_hal_log_stats_intr_config(void (*rsi_give_wakeup_indication)()); +#endif /* LOGGING_STATS */ +#ifdef RSI_WITH_OS +void rsi_os_delay_ms(uint32_t delay_ms); +void PORTD_IRQHandler(void); + +#endif /* RSI_WITH_OS */ + +#endif diff --git a/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_interrupt.c b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_interrupt.c new file mode 100644 index 00000000000000..40e4189635d71c --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_interrupt.c @@ -0,0 +1,161 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "dmadrv.h" +#include "em_chip.h" +#include "em_cmu.h" +#include "em_core.h" +#include "em_device.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" +#include "gpiointerrupt.h" +#include "sl_device_init_clocks.h" +#include "sl_status.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" + +#include "wfx_host_events.h" +#include "wfx_rsi.h" + +#include "rsi_board_configuration.h" +#include "rsi_driver.h" + +typedef void (*UserIntCallBack_t)(void); +UserIntCallBack_t call_back, gpio_callback; +#ifdef LOGGING_STATS +uint8_t current_pin_set, prev_pin_set; +#endif /* LOGGING_STATS */ + +/* ARGSUSED */ +void rsi_gpio_irq_cb(uint8_t irqnum) +{ + + // WFX_RSI_LOG ("RSI: Got Int=%d", irqnum) + if (irqnum != SL_WFX_HOST_PINOUT_SPI_IRQ) + return; + GPIO_IntClear(1 << SL_WFX_HOST_PINOUT_SPI_IRQ); + + // WFX_RSI_LOG ("Got SPI intr, cb=%x", (uint32_t)call_back); + if (call_back != NULL) + (*call_back)(); +} + +/*===================================================*/ +/** + * @fn void rsi_hal_intr_config(void (* rsi_interrupt_handler)()) + * @brief Starts and enables the SPI interrupt + * @param[in] rsi_interrupt_handler() ,call back function to handle interrupt + * @param[out] none + * @return none + * @description This HAL API should contain the code to initialize the register/pins + * related to interrupts and enable the interrupts. + */ +void rsi_hal_intr_config(void (*rsi_interrupt_handler)(void)) +{ + call_back = rsi_interrupt_handler; + WFX_RSI_LOG("RSI:Set SPI intr CB to=%x", (uint32_t) call_back); +} + +/*===================================================*/ +/** + * @fn void rsi_hal_log_stats_intr_config(void (* rsi_give_wakeup_indication)()) + * @brief Checks the interrupt and map/set gpio callback function + * @param[in] rsi_give_wakeup_indication() ,gpio call back function to handle interrupt + * @param[out] none + * @return none + * @description This HAL API should contain the code + * related to mapping of gpio callback function. + */ +#ifdef LOGGING_STATS +void rsi_hal_log_stats_intr_config(void (*rsi_give_wakeup_indication)()) +{ + gpio_callback = rsi_give_wakeup_indication; +} +#endif + +/*===================================================*/ +/** + * @fn void rsi_hal_intr_mask(void) + * @brief Disables the SPI Interrupt + * @param[in] none + * @param[out] none + * @return none + * @description This HAL API should contain the code to mask/disable interrupts. + */ +void rsi_hal_intr_mask(void) +{ + // WFX_RSI_LOG ("RSI:Disable IRQ"); + // NVIC_DisableIRQ(GPIO_ODD_IRQn); + GPIO_IntDisable(1 << SL_WFX_HOST_PINOUT_SPI_IRQ); +} + +/*===================================================*/ +/** + * @fn void rsi_hal_intr_unmask(void) + * @brief Enables the SPI interrupt + * @param[in] none + * @param[out] none + * @return none + * @description This HAL API should contain the code to enable interrupts. + */ +void rsi_hal_intr_unmask(void) +{ + // Unmask/Enable the interrupt + NVIC_EnableIRQ(GPIO_ODD_IRQn); + NVIC_EnableIRQ(GPIO_EVEN_IRQn); + GPIO_IntEnable(1 << SL_WFX_HOST_PINOUT_SPI_IRQ); + // WFX_RSI_LOG ("RSI:Enable IRQ (mask=%x)", GPIO_IntGetEnabled ()); +} + +/*===================================================*/ +/** + * @fn void rsi_hal_intr_clear(void) + * @brief Clears the pending interrupt + * @param[in] none + * @param[out] none + * @return none + * @description This HAL API should contain the code to clear the handled interrupts. + */ +void rsi_hal_intr_clear(void) +{ + GPIO_IntClear(1 << SL_WFX_HOST_PINOUT_SPI_IRQ); +} + +/*===================================================*/ +/** + * @fn void rsi_hal_intr_pin_status(void) + * @brief Checks the SPI interrupt at pin level + * @param[in] none + * @param[out] uint8_t, interrupt status + * @return none + * @description This API is used to check interrupt pin status(pin level whether it is high/low). + */ +uint8_t rsi_hal_intr_pin_status(void) +{ + uint32_t mask; + // Return interrupt pin status(high(1) /low (0)) + mask = GPIO_PinInGet(WFX_INTERRUPT_PIN.port, WFX_INTERRUPT_PIN.pin); + + return !!mask; +} diff --git a/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_ioports.c b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_ioports.c new file mode 100644 index 00000000000000..1ff5bc5fedf4f2 --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_ioports.c @@ -0,0 +1,141 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "dmadrv.h" +#include "em_chip.h" +#include "em_cmu.h" +#include "em_core.h" +#include "em_device.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" +#include "gpiointerrupt.h" +#include "sl_device_init_clocks.h" +#include "sl_status.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" + +#include "wfx_host_events.h" +#include "wfx_rsi.h" + +#include "rsi_board_configuration.h" +#include "rsi_driver.h" + +/*===========================================================*/ +/** + * @fn void rsi_hal_config_gpio(uint8_t gpio_number,uint8_t mode,uint8_t value) + * @brief Configures gpio pin in output mode,with a value + * @param[in] uint8_t gpio_number, gpio pin number to be configured + * @param[in] uint8_t mode , input/output mode of the gpio pin to configure + * 0 - input mode + * 1 - output mode + * @param[in] uint8_t value, default value to be driven if gpio is configured in output mode + * 0 - low + * 1 - high + * @param[out] none + * @return none + * @description This API is used to configure host gpio pin in output mode. + */ +void rsi_hal_config_gpio(uint8_t gpio_number, uint8_t mode, uint8_t value) +{ + + CMU_ClockEnable(cmuClock_GPIO, true); + + // WFX_RSI_LOG ("RSI: CFG GPIO: 0x%x", gpio_number); + switch (gpio_number) + { + case RSI_HAL_RESET_PIN: + GPIO_PinModeSet(WFX_RESET_PIN.port, WFX_RESET_PIN.pin, gpioModePushPull, PINOUT_SET); + break; + default: + break; + } +} + +/*===========================================================*/ +/** + * @fn void rsi_hal_set_gpio(uint8_t gpio_number) + * @brief Makes/drives the gpio value high + * @param[in] uint8_t gpio_number, gpio pin number + * @param[out] none + * @return none + * @description This API is used to drives or makes the host gpio value high. + */ +void rsi_hal_set_gpio(uint8_t gpio_number) +{ + // WFX_RSI_LOG ("RSI: SET GPIO: 0x%x", gpio_number); + switch (gpio_number) + { + case RSI_HAL_RESET_PIN: + GPIO_PinModeSet(WFX_RESET_PIN.port, WFX_RESET_PIN.pin, gpioModeWiredOrPullDown, PINOUT_SET); + break; + default: + break; + } +} + +/*===========================================================*/ +/** + * @fn uint8_t rsi_hal_get_gpio(void) + * @brief get the gpio pin value + * @param[in] uint8_t gpio_number, gpio pin number + * @param[out] none + * @return gpio pin value + * @description This API is used to configure get the gpio pin value. + */ +uint8_t rsi_hal_get_gpio(uint8_t gpio_number) +{ + // WFX_RSI_LOG ("RSI: GET GPIO: 0x%x", gpio_number); + switch (gpio_number) + { + case RSI_HAL_RESET_PIN: + return GPIO_PinInGet(WFX_RESET_PIN.port, WFX_RESET_PIN.pin); + case RSI_HAL_MODULE_INTERRUPT_PIN: + return GPIO_PinInGet(WFX_INTERRUPT_PIN.port, WFX_INTERRUPT_PIN.pin); + default: + break; + } + + return 0; +} + +/*===========================================================*/ +/** + * @fn void rsi_hal_set_gpio(uint8_t gpio_number) + * @brief Makes/drives the gpio value to low + * @param[in] uint8_t gpio_number, gpio pin number + * @param[out] none + * @return none + * @description This API is used to drives or makes the host gpio value low. + */ +void rsi_hal_clear_gpio(uint8_t gpio_number) +{ + // WFX_RSI_LOG ("RSI: CLR GPIO: 0x%x", gpio_number); + switch (gpio_number) + { + case RSI_HAL_RESET_PIN: + return GPIO_PinOutClear(WFX_RESET_PIN.port, WFX_RESET_PIN.pin); + default: + break; + } +} diff --git a/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_rtc.c b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_rtc.c new file mode 100644 index 00000000000000..f57d47a4439bc5 --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_rtc.c @@ -0,0 +1,326 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Includes + */ +#include "em_cmu.h" +#include "em_core.h" +#include "em_rtcc.h" +#include "sl_sleeptimer_config.h" +#include "sl_status.h" +#include +#include + +#define ZONE0 0 +#define CH_SELECTOR 1u +#define RTC_DEFAULT_COUNTER_VALUE 0u +#define RSI_RTC_FREQ_VALUE 0 +#define TIME_ZONE_OFFSET 0u + +#define SLEEPTIMER_EVENT_OF (0x01) +#define SLEEPTIMER_EVENT_COMP (0x02) +#define SLEEPTIMER_ENUM(name) \ + typedef uint8_t name; \ + enum name##_enum +#define TIME_UNIX_EPOCH (1970u) +#define TIME_NTP_EPOCH (1900u) +#define TIME_ZIGBEE_EPOCH (2000u) +#define TIME_NTP_UNIX_EPOCH_DIFF (TIME_UNIX_EPOCH - TIME_NTP_EPOCH) +#define TIME_ZIGBEE_UNIX_EPOCH_DIFF (TIME_ZIGBEE_EPOCH - TIME_UNIX_EPOCH) +#define TIME_DAY_COUNT_NTP_TO_UNIX_EPOCH (TIME_NTP_UNIX_EPOCH_DIFF * 365u + 17u) ///< 70 years and 17 leap days +#define TIME_DAY_COUNT_ZIGBEE_TO_UNIX_EPOCH (TIME_ZIGBEE_UNIX_EPOCH_DIFF * 365u + 7u) ///< 30 years and 7 leap days +#define TIME_SEC_PER_DAY (60u * 60u * 24u) +#define TIME_NTP_EPOCH_OFFSET_SEC (TIME_DAY_COUNT_NTP_TO_UNIX_EPOCH * TIME_SEC_PER_DAY) +#define TIME_ZIGBEE_EPOCH_OFFSET_SEC (TIME_DAY_COUNT_ZIGBEE_TO_UNIX_EPOCH * TIME_SEC_PER_DAY) +#define TIME_DAY_PER_YEAR (365u) +#define TIME_SEC_PER_YEAR (TIME_SEC_PER_DAY * TIME_DAY_PER_YEAR) +#define TIME_UNIX_TIMESTAMP_MAX (0x7FFFFFFF) + +/// Time zone offset from UTC(second). +typedef int32_t sl_sleeptimer_time_zone_offset_t; +/// Timestamp, wall clock time in seconds. +typedef uint32_t sl_sleeptimer_timestamp_t; +/// @brief Time Format. +SLEEPTIMER_ENUM(sl_sleeptimer_time_format_t){ + TIME_FORMAT_UNIX = 0, ///< Number of seconds since January 1, 1970, 00:00. + ///< Type is signed, so represented on 31 bit. + TIME_FORMAT_NTP = 1, ///< Number of seconds since January 1, 1900, 00:00. + ///< Type is unsigned, so represented on 32 bit. + TIME_FORMAT_ZIGBEE_CLUSTER = 2, ///< Number of seconds since January 1, 2000, 00:00. Type is + ///< unsigned, so represented on 32 bit. +}; + +// Initialization flag. +static bool is_sleeptimer_initialized = false; +// Timer frequency in Hz. +static uint32_t timer_frequency; +#if SL_SLEEPTIMER_WALLCLOCK_CONFIG +// Current time count. +static sl_sleeptimer_timestamp_t second_count; +// Tick rest when the frequency is not a divider of the timer width. +static uint32_t overflow_tick_rest = 0; +#endif + +/******************************************************************************* + * Checks if the time stamp, format and time zone are + * within the supported range. + * + * @param time Time stamp to check. + * @param format Format of the time. + * @param time_zone Time zone offset in second. + * + * @return true if the time is valid. False otherwise. + ******************************************************************************/ +static bool is_valid_time(sl_sleeptimer_timestamp_t time, sl_sleeptimer_time_format_t format, + sl_sleeptimer_time_zone_offset_t time_zone) +{ + bool valid_time = false; + + // Check for overflow. + if ((time_zone < ZONE0 && time > (uint32_t) abs(time_zone)) || (time_zone >= ZONE0 && (time <= UINT32_MAX - time_zone))) + { + valid_time = true; + } + if (format == TIME_FORMAT_UNIX) + { + if (time > TIME_UNIX_TIMESTAMP_MAX) + { // Check if Unix time stamp is an + // unsigned 31 bits. + valid_time = false; + } + } + else + { + if ((format == TIME_FORMAT_NTP) && (time >= TIME_NTP_EPOCH_OFFSET_SEC)) + { + valid_time &= true; + } + else if ((format == TIME_FORMAT_ZIGBEE_CLUSTER) && (time <= TIME_UNIX_TIMESTAMP_MAX - TIME_ZIGBEE_EPOCH_OFFSET_SEC)) + { + valid_time &= true; + } + else + { + valid_time = false; + } + } + return valid_time; +} + +/******************************************************************************* + * Gets RTCC timer frequency. + ******************************************************************************/ +uint32_t rsi_rtc_get_hal_timer_frequency(void) +{ + /* CMU_PrescToLog2 converts prescaler dividend to a logarithmic value. It only works for even + * numbers equal to 2^n. + * An unscaled dividend (dividend = argument + 1). + * So we need to send argument subtracted by 1 + */ + return (CMU_ClockFreqGet(cmuClock_RTCC) >> (CMU_PrescToLog2(SL_SLEEPTIMER_FREQ_DIVIDER - 1))); +} + +/****************************************************************************** + * Initializes RTCC sleep timer. + *****************************************************************************/ +void rsi_rtc_init_timer(void) +{ + RTCC_Init_TypeDef rtcc_init = RTCC_INIT_DEFAULT; + RTCC_CCChConf_TypeDef channel = RTCC_CH_INIT_COMPARE_DEFAULT; + + CMU_ClockEnable(cmuClock_RTCC, true); + + rtcc_init.enable = false; + + /* CMU_PrescToLog2 converts prescaler dividend to a logarithmic value. It only works for even + * numbers equal to 2^n. + * An unscaled dividend (dividend = argument + 1). + * So we need to send argument subtracted by 1 + */ + rtcc_init.presc = (RTCC_CntPresc_TypeDef)(CMU_PrescToLog2(SL_SLEEPTIMER_FREQ_DIVIDER - 1)); + + RTCC_Init(&rtcc_init); + + // Compare channel starts disabled and is enabled only when compare match + // interrupt is enabled. + channel.chMode = rtccCapComChModeOff; + RTCC_ChannelInit(CH_SELECTOR, &channel); + + RTCC_IntDisable(_RTCC_IEN_MASK); + RTCC_IntClear(_RTCC_IF_MASK); + RTCC_CounterSet(RTC_DEFAULT_COUNTER_VALUE); + + RTCC_Enable(true); + + NVIC_ClearPendingIRQ(RTCC_IRQn); + NVIC_EnableIRQ(RTCC_IRQn); +} + +/****************************************************************************** + * Enables RTCC interrupts. + *****************************************************************************/ +void rsi_rtc_enable_int(uint8_t local_flag) +{ + uint32_t rtcc_ien = 0u; + + if (local_flag & SLEEPTIMER_EVENT_OF) + { + rtcc_ien |= RTCC_IEN_OF; + } + + if (local_flag & SLEEPTIMER_EVENT_COMP) + { + rtcc_ien |= RTCC_IEN_CC1; + } + + RTCC_IntEnable(rtcc_ien); +} + +/******************************************************************************* + * Get timer frequency. + ******************************************************************************/ +uint32_t rsi_rtc_get_timer_frequency(void) +{ + return timer_frequency; +} + +/****************************************************************************** + * Gets RTCC counter value. + *****************************************************************************/ +uint32_t rsi_rtc_get_counter(void) +{ + return RTCC_CounterGet(); +} + +sl_status_t rsi_rtc_init(void) +{ + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + + if (!is_sleeptimer_initialized) + { + rsi_rtc_init_timer(); + rsi_rtc_enable_int(SLEEPTIMER_EVENT_OF); + timer_frequency = rsi_rtc_get_hal_timer_frequency(); + if (timer_frequency == RSI_RTC_FREQ_VALUE) + { + CORE_EXIT_ATOMIC(); + return SL_STATUS_INVALID_PARAMETER; + } + +#if SL_SLEEPTIMER_WALLCLOCK_CONFIG + second_count = 0; +#endif + + is_sleeptimer_initialized = true; + } + CORE_EXIT_ATOMIC(); + + return SL_STATUS_OK; +} + +#if SL_SLEEPTIMER_WALLCLOCK_CONFIG +/******************************************************************************* + * Retrieves current time. + ******************************************************************************/ +uint32_t rsi_rtc_get_time(void) +{ + uint32_t cnt = 0u; + uint32_t freq = 0u; + sl_sleeptimer_timestamp_t time; + CORE_DECLARE_IRQ_STATE; + + cnt = rsi_rtc_get_counter(); + freq = rsi_rtc_get_timer_frequency(); + + CORE_ENTER_ATOMIC(); + time = second_count + cnt / freq; + if (cnt % freq + overflow_tick_rest >= freq) + { + time++; + } + CORE_EXIT_ATOMIC(); + + return time; +} + +/******************************************************************************* + * Sets current time. + ******************************************************************************/ +sl_status_t rsi_rtc_settime(sl_sleeptimer_timestamp_t time) +{ + uint32_t freq = 0u; + uint32_t counter_sec = 0u; + uint32_t cnt = 0; + CORE_DECLARE_IRQ_STATE; + + if (!is_valid_time(time, TIME_FORMAT_UNIX, TIME_ZONE_OFFSET)) + { + return SL_STATUS_INVALID_CONFIGURATION; + } + + freq = rsi_rtc_get_timer_frequency(); + cnt = rsi_rtc_get_counter(); + + CORE_ENTER_ATOMIC(); + second_count = time; + overflow_tick_rest = 0; + counter_sec = cnt / freq; + + if (second_count >= counter_sec) + { + second_count -= counter_sec; + } + else + { + CORE_EXIT_ATOMIC(); + return SL_STATUS_INVALID_CONFIGURATION; + } + + CORE_EXIT_ATOMIC(); + + return SL_STATUS_OK; +} + +/******************************************************************************* + * @fn int32_t rsi_rtc_set_time(uint32_t time) + * @brief + * Init Sleeptimer and Set current time. + * @param[in] time: + * @return + * None + ******************************************************************************/ +int32_t rsi_rtc_set_time(uint32_t time) +{ + sl_status_t ret_val = SL_STATUS_OK; + ret_val = rsi_rtc_init(); + if (ret_val != SL_STATUS_OK) + { + return -1; + } + else + { + ret_val = rsi_rtc_settime(time); + if (ret_val != SL_STATUS_OK) + { + return -1; + } + } + return 0; +} +#endif // SL_SLEEPTIMER_WALLCLOCK_CONFIG diff --git a/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_timer.c b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_timer.c new file mode 100644 index 00000000000000..c6d6381932d3ea --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/hal/rsi_hal_mcu_timer.c @@ -0,0 +1,322 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Includes + */ + +#include "em_cmu.h" +#ifdef RSI_WITH_OS +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" +#include "timers.h" +#if defined(SysTick) +#undef SysTick_Handler +/* FreeRTOS SysTick interrupt handler prototype */ +extern void SysTick_Handler(void); +/* FreeRTOS tick timer interrupt handler prototype */ +extern void xPortSysTickHandler(void); +#endif /* SysTick */ +#endif /* RSI_WITH_OS */ +#include "wfx_host_events.h" + +/* RSI Driver include file */ +#include "rsi_driver.h" +/* RSI WLAN Config include file */ +#include "rsi_bootup_config.h" +#include "rsi_common_apis.h" +#include "rsi_data_types.h" +#include "rsi_error.h" +#include "rsi_nwk.h" +#include "rsi_socket.h" +#include "rsi_utils.h" +#include "rsi_wlan.h" +#include "rsi_wlan_apis.h" +#include "rsi_wlan_config.h" +#include "wfx_rsi.h" + +#ifndef _use_the_rsi_defined_functions + +StaticTimer_t sRsiTimerBuffer; + +/* + * We (Matter port) need a few functions out of this file + * They are at the top + */ +uint32_t rsi_hal_gettickcount(void) +{ + return xTaskGetTickCount(); +} +void rsi_delay_ms(uint32_t delay_ms) +{ +#ifndef RSI_WITH_OS + uint32_t start; +#endif + if (delay_ms == 0) // Check if delay is 0msec + return; + +#ifdef RSI_WITH_OS + vTaskDelay(pdMS_TO_TICKS(delay_ms)); +#else + start = rsi_hal_gettickcount(); + do + { + } while (rsi_hal_gettickcount() - start < delay_ms); +#endif +} +static struct rsi_timer +{ + void (*func)(void); + TimerHandle_t handle; + uint8_t id; + uint8_t name[3]; +} rsi_timer[WFX_RSI_NUM_TIMERS]; +static void timer_cb(TimerHandle_t thandle) +{ + int x; + for (x = 0; x < WFX_RSI_NUM_TIMERS; x++) + { + if (rsi_timer[x].handle == thandle) + { + (*rsi_timer[x].func)(); + break; + } + } +} + +/* + * Run a one-shot/periodic timer + */ +int32_t rsi_timer_start(uint8_t timer_node, uint8_t mode, uint8_t type, uint32_t duration, void (*rsi_timer_cb)(void)) +{ + int x; + struct rsi_timer * tp; + + if (mode == RSI_HAL_TIMER_MODE_MILLI) + return RSI_ERROR_INVALID_OPTION; /* Not supported for now - Fix this later */ + for (x = 0; x < WFX_RSI_NUM_TIMERS; x++) + { + tp = &rsi_timer[x]; + if (tp->handle == NULL) + { + goto found; + } + } + /* No space */ + return RSI_ERROR_INSUFFICIENT_BUFFER; +found: + tp->name[0] = 'r'; + tp->name[1] = timer_node; + tp->name[2] = 0; + tp->func = rsi_timer_cb; + tp->handle = + xTimerCreateStatic((char *) &tp->name[0], pdMS_TO_TICKS(duration), + ((mode == RSI_HAL_TIMER_TYPE_SINGLE_SHOT) ? pdFALSE : pdTRUE), NULL, timer_cb, &sRsiTimerBuffer); + + if (tp->handle == NULL) + { + return RSI_ERROR_INSUFFICIENT_BUFFER; + } + + (void) xTimerStart(tp->handle, TIMER_TICKS_TO_WAIT_0); + + return RSI_ERROR_NONE; +} +#else /* _use_the_rsi_defined_functions */ + +/* Counts 1ms timeTicks */ +volatile uint32_t msTicks = 0; + +/*===================================================*/ +/** + * @fn int32_t rsi_timer_start(uint8_t timer_no, uint8_t mode,uint8_t type,uint32_t duration,void (* + * rsi_timer_expiry_handler)()) + * @brief Starts and configures timer + * @param[in] timer_node, timer node to be configured. + * @param[in] mode , mode of the timer + * 0 - Micro seconds mode + * 1 - Milli seconds mode + * @param[in] type, type of the timer + * 0 - single shot type + * 1 - periodic type + * @param[in] duration, timer duration + * @param[in] rsi_timer_expiry_handler() ,call back function to handle timer interrupt + * @param[out] none + * @return 0 - success + * !0 - Failure + * @description This HAL API should contain the code to initialize the timer and start the timer + * + */ + +int32_t rsi_timer_start(uint8_t timer_node, uint8_t mode, uint8_t type, uint32_t duration, void (*rsi_timer_expiry_handler)(void)) +{ + + // Initialise the timer + + // register the call back + + // Start timer + + return 0; +} + +/*===================================================*/ +/** + * @fn int32_t rsi_timer_stop(uint8_t timer_no) + * @brief Stops timer + * @param[in] timer_node, timer node to stop + * @param[out] none + * @return 0 - success + * !0 - Failure + * @description This HAL API should contain the code to stop the timer + * + */ + +int32_t rsi_timer_stop(uint8_t timer_node) +{ + + // Stop the timer + + return 0; +} + +/*===================================================*/ +/** + * @fn uint32_t rsi_timer_read(uint8_t timer_node) + * @brief read timer + * @param[in] timer_node, timer node to read + * @param[out] none + * @return timer value + * @description This HAL API should contain API to read the timer + * + */ +uint32_t rsi_timer_read(uint8_t timer_node) +{ + + volatile uint32_t timer_val = 0; + + // read the timer and return timer value + + return timer_val; +} + +/*===================================================*/ +/** + * @fn void rsi_delay_us(uint32_t delay) + * @brief create delay in micro seconds + * @param[in] delay_us, timer delay in micro seconds + * @param[out] none + * @return none + * @description This HAL API should contain the code to create delay in micro seconds + * + */ +void rsi_delay_us(uint32_t delay_us) +{ + + // call the API for delay in micro seconds + + return; +} + +#ifdef RSI_M4_INTERFACE + +extern void SysTick_Handler(void); + +void SysTick_Handler(void) +{ + _dwTickCount++; +} + +uint32_t GetTickCount(void) +{ + return _dwTickCount; // gets the tick count from systic ISR +} +#endif + +/*===================================================*/ +/** + * @fn void rsi_delay_ms(uint32_t delay) + * @brief create delay in milli seconds + * @param[in] delay, timer delay in milli seconds + * @param[out] none + * @return none + * @description This HAL API should contain the code to create delay in milli seconds + */ +void rsi_delay_ms(uint32_t delay_ms) +{ +#ifndef RSI_WITH_OS + uint32_t start; +#endif + if (delay_ms == DELAY0) + return; + +#ifdef RSI_WITH_OS + vTaskDelay(delay_ms); +#else + start = rsi_hal_gettickcount(); + do + { + } while (rsi_hal_gettickcount() - start < delay_ms); +#endif +} + +/*===================================================*/ +/** + * @fn uint32_t rsi_hal_gettickcount() + * @brief provides a tick value in milliseconds + * @return tick value + * @description This HAL API should contain the code to read the timer tick count value in milliseconds + * + */ + +#ifndef RSI_HAL_USE_RTOS_SYSTICK +/* + SysTick handler implementation that also clears overflow flag. +*/ +void SysTick_Handler(void) +{ + /* Increment counter necessary in Delay()*/ + msTicks++; +#ifdef RSI_WITH_OS + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) + { + xPortSysTickHandler(); + } +#endif +} + +uint32_t rsi_hal_gettickcount(void) +{ + return msTicks; + +#ifdef LINUX_PLATFORM + // Define your API to get the tick count delay in milli seconds from systic ISR and return the resultant value + struct rsi_timeval tv1; + gettimeofday(&tv1, NULL); + return (tv1.tv_sec * CONVERT_SEC_TO_MSEC + tv1.tv_usec * CONVERT_USEC_TO_MSEC); +#endif +} + +#else +uint32_t rsi_hal_gettickcount(void) +{ + return xTaskGetTickCount(); +} +#endif /* RSI_HAL_USE_RTOS_SYSTICK */ +#endif /* _use_the_rsi_defined_functions */ diff --git a/examples/platform/silabs/SiWx917/rs911x/rs911x.gni b/examples/platform/silabs/SiWx917/rs911x/rs911x.gni new file mode 100644 index 00000000000000..f11981023e35f2 --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/rs911x.gni @@ -0,0 +1,101 @@ +import("//build_overrides/chip.gni") +import("//build_overrides/efr32_sdk.gni") +import("//build_overrides/pigweed.gni") + +examples_plat_dir = "${chip_root}/examples/platform/silabs/efr32" +wifi_sdk_dir = "${chip_root}/src/platform/silabs/EFR32/wifi" +wiseconnect_sdk_root = "${chip_root}/third_party/silabs/wiseconnect-wifi-bt-sdk" +rs911x_cflags = [] + +rs911x_src_plat = [ + "${examples_plat_dir}/rs911x/rsi_if.c", + "${examples_plat_dir}/rs911x/wfx_rsi_host.c", + "${wifi_sdk_dir}/wfx_notify.cpp", + "${examples_plat_dir}/rs911x/hal/rsi_hal_mcu_interrupt.c", + "${examples_plat_dir}/rs911x/hal/rsi_hal_mcu_ioports.c", + "${examples_plat_dir}/rs911x/hal/rsi_hal_mcu_timer.c", + "${examples_plat_dir}/rs911x/hal/efx_spi.c", +] +rs911x_plat_incs = [ + "${wifi_sdk_dir}", + "${wifi_sdk_dir}/hal", + "${chip_root}/src/platform/EFR32", +] + +# +# All the stuff from wiseconnect +# +rs911x_src_sapi = [ + "${wiseconnect_sdk_root}/sapi/wlan/rsi_wlan_apis.c", + "${wiseconnect_sdk_root}/sapi/common/rsi_apis_non_rom.c", + "${wiseconnect_sdk_root}/sapi/common/rsi_apis_rom.c", + "${wiseconnect_sdk_root}/sapi/common/rsi_common_apis.c", + "${wiseconnect_sdk_root}/sapi/common/rsi_device_init_apis.c", + "${wiseconnect_sdk_root}/sapi/driver/device_interface/spi/rsi_spi_frame_rd_wr.c", + "${wiseconnect_sdk_root}/sapi/driver/device_interface/spi/rsi_spi_functs.c", + "${wiseconnect_sdk_root}/sapi/driver/device_interface/spi/rsi_spi_iface_init.c", + "${wiseconnect_sdk_root}/sapi/driver/device_interface/spi/rsi_spi_mem_rd_wr.c", + "${wiseconnect_sdk_root}/sapi/driver/device_interface/spi/rsi_spi_reg_rd_wr.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_common.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_device_init.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_driver_event_handlers.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_driver.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_events_rom.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_events.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_iap.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_nwk_rom.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_nwk.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_pkt_mgmt_rom.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_pkt_mgmt.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_queue_rom.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_queue.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_scheduler_rom.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_scheduler.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_setregion_countryinfo.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_timer.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_utils_rom.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_utils.c", + "${wiseconnect_sdk_root}/sapi/driver/rsi_wlan.c", + "${wiseconnect_sdk_root}/sapi/rtos/freertos_wrapper/rsi_os_wrapper.c", +] + +foreach(src_file, rs911x_src_sapi) { + rs911x_cflags += [ "-Wno-empty-body" ] +} + +rs911x_inc_plat = [ + "${wifi_sdk_dir}", + "${examples_plat_dir}/rs911x", + "${examples_plat_dir}/rs911x/hal", + "${wiseconnect_sdk_root}/sapi/include", +] + +# Apparently - the rsi library needs this +rs911x_src_sock = [ + "${wiseconnect_sdk_root}/sapi/network/socket/rsi_socket.c", + "${wiseconnect_sdk_root}/sapi/network/socket/rsi_socket_rom.c", +] +rs911x_sock_inc = [ "${wifi_sdk_dir}/rsi-sockets" ] + +# +# If we use LWIP - not built-in sockets +# +rs911x_src_lwip = [ + "${wifi_sdk_dir}/ethernetif.cpp", + "${wifi_sdk_dir}/dhcp_client.cpp", + "${wifi_sdk_dir}/lwip_netif.cpp", +] +rs911x_defs = [ + "SL_HEAP_SIZE=32768", + "SL_WIFI=1", + "SL_WFX_USE_SPI", + "EFX32_RS911X=1", + "RS911X_WIFI", + "RSI_WLAN_ENABLE", + "RSI_SPI_INTERFACE", + "RSI_WITH_OS", +] +rs911x_sock_defs = [ + "RS911X_SOCKETS", + "RSI_IPV6_ENABLE", +] diff --git a/examples/platform/silabs/SiWx917/rs911x/rsi_if.c b/examples/platform/silabs/SiWx917/rs911x/rsi_if.c new file mode 100644 index 00000000000000..7d3be406fbce2f --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/rsi_if.c @@ -0,0 +1,854 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "em_bus.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" + +#include "sl_status.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" + +#include "wfx_host_events.h" + +#include "rsi_driver.h" +#include "rsi_wlan_non_rom.h" + +#include "rsi_common_apis.h" +#include "rsi_data_types.h" +#include "rsi_nwk.h" +#include "rsi_socket.h" +#include "rsi_utils.h" +#include "rsi_wlan.h" +#include "rsi_wlan_apis.h" +#include "rsi_wlan_config.h" +//#include "rsi_wlan_non_rom.h" +#include "rsi_bootup_config.h" +#include "rsi_error.h" + +#include "dhcp_client.h" +#include "wfx_host_events.h" +#include "wfx_rsi.h" + +/* Rsi driver Task will use as its stack */ +StackType_t driverRsiTaskStack[WFX_RSI_WLAN_TASK_SZ] = { 0 }; + +/* Structure that will hold the TCB of the wfxRsi Task being created. */ +StaticTask_t driverRsiTaskBuffer; + +/* Declare a variable to hold the data associated with the created event group. */ +StaticEventGroup_t rsiDriverEventGroup; + +bool hasNotifiedIPV6 = false; +#if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) +bool hasNotifiedIPV4 = false; +#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ +bool hasNotifiedWifiConnectivity = false; + +/* + * This file implements the interface to the RSI SAPIs + */ +static uint8_t wfx_rsi_drv_buf[WFX_RSI_BUF_SZ]; +wfx_wifi_scan_ext_t * temp_reset; +uint8_t security; + +/****************************************************************** + * @fn int32_t wfx_rsi_get_ap_info(wfx_wifi_scan_result_t *ap) + * @brief + * Getting the AP details + * @param[in] ap: access point + * @return + * status + *********************************************************************/ +int32_t wfx_rsi_get_ap_info(wfx_wifi_scan_result_t * ap) +{ + int32_t status; + uint8_t rssi; + ap->security = security; + ap->chan = wfx_rsi.ap_chan; + memcpy(&ap->bssid[0], &wfx_rsi.ap_mac.octet[0], BSSID_MAX_STR_LEN); + status = rsi_wlan_get(RSI_RSSI, &rssi, sizeof(rssi)); + if (status == RSI_SUCCESS) + { + ap->rssi = (-1) * rssi; + } + return status; +} + +/****************************************************************** + * @fn int32_t wfx_rsi_get_ap_ext(wfx_wifi_scan_ext_t *extra_info) + * @brief + * Getting the AP extra details + * @param[in] extra info: access point extra information + * @return + * status + *********************************************************************/ +int32_t wfx_rsi_get_ap_ext(wfx_wifi_scan_ext_t * extra_info) +{ + int32_t status; + uint8_t buff[RSI_RESPONSE_MAX_SIZE] = { 0 }; + status = rsi_wlan_get(RSI_WLAN_EXT_STATS, buff, sizeof(buff)); + if (status != RSI_SUCCESS) + { + WFX_RSI_LOG("\r\n Failed, Error Code : 0x%lX\r\n", status); + } + else + { + rsi_wlan_ext_stats_t * test = (rsi_wlan_ext_stats_t *) buff; + extra_info->beacon_lost_count = test->beacon_lost_count - temp_reset->beacon_lost_count; + extra_info->beacon_rx_count = test->beacon_rx_count - temp_reset->beacon_rx_count; + extra_info->mcast_rx_count = test->mcast_rx_count - temp_reset->mcast_rx_count; + extra_info->mcast_tx_count = test->mcast_tx_count - temp_reset->mcast_tx_count; + extra_info->ucast_rx_count = test->ucast_rx_count - temp_reset->ucast_rx_count; + extra_info->ucast_tx_count = test->ucast_tx_count - temp_reset->ucast_tx_count; + extra_info->overrun_count = test->overrun_count - temp_reset->overrun_count; + } + return status; +} + +/****************************************************************** + * @fn int32_t wfx_rsi_reset_count() + * @brief + * Getting the driver reset count + * @param[in] None + * @return + * status + *********************************************************************/ +int32_t wfx_rsi_reset_count() +{ + int32_t status; + uint8_t buff[RSI_RESPONSE_MAX_SIZE] = { 0 }; + status = rsi_wlan_get(RSI_WLAN_EXT_STATS, buff, sizeof(buff)); + if (status != RSI_SUCCESS) + { + WFX_RSI_LOG("\r\n Failed, Error Code : 0x%lX\r\n", status); + } + else + { + rsi_wlan_ext_stats_t * test = (rsi_wlan_ext_stats_t *) buff; + temp_reset->beacon_lost_count = test->beacon_lost_count; + temp_reset->beacon_rx_count = test->beacon_rx_count; + temp_reset->mcast_rx_count = test->mcast_rx_count; + temp_reset->mcast_tx_count = test->mcast_tx_count; + temp_reset->ucast_rx_count = test->ucast_rx_count; + temp_reset->ucast_tx_count = test->ucast_tx_count; + temp_reset->overrun_count = test->overrun_count; + } + return status; +} + +/****************************************************************** + * @fn wfx_rsi_disconnect() + * @brief + * Getting the driver disconnect status + * @param[in] None + * @return + * status + *********************************************************************/ +int32_t wfx_rsi_disconnect() +{ + int32_t status = rsi_wlan_disconnect(); + return status; +} + +/****************************************************************** + * @fn wfx_rsi_join_cb(uint16_t status, const uint8_t *buf, const uint16_t len) + * @brief + * called when driver join with cb + * @param[in] status: + * @param[in] buf: + * @param[in] len: + * @return + * None + *********************************************************************/ +static void wfx_rsi_join_cb(uint16_t status, const uint8_t * buf, const uint16_t len) +{ + WFX_RSI_LOG("%s: status: %02x", __func__, status); + wfx_rsi.dev_state &= ~WFX_RSI_ST_STA_CONNECTING; + temp_reset = (wfx_wifi_scan_ext_t *) malloc(sizeof(wfx_wifi_scan_ext_t)); + memset(temp_reset, 0, sizeof(wfx_wifi_scan_ext_t)); + if (status != RSI_SUCCESS) + { + /* + * We should enable retry.. (Need config variable for this) + */ + WFX_RSI_LOG("%s: failed. retry: %d", __func__, wfx_rsi.join_retries); +#if (WFX_RSI_CONFIG_MAX_JOIN != 0) + if (++wfx_rsi.join_retries < WFX_RSI_CONFIG_MAX_JOIN) +#endif + { + xEventGroupSetBits(wfx_rsi.events, WFX_EVT_STA_START_JOIN); + } + } + else + { + /* + * Join was complete - Do the DHCP + */ + WFX_RSI_LOG("%s: join completed.", __func__); +#ifdef RS911X_SOCKETS + xEventGroupSetBits(wfx_rsi.events, WFX_EVT_STA_DO_DHCP); +#else + xEventGroupSetBits(wfx_rsi.events, WFX_EVT_STA_CONN); +#endif + } +} + +/****************************************************************** + * @fn wfx_rsi_join_fail_cb(uint16_t status, uint8_t *buf, uint32_t len) + * @brief + * called when driver fail to join with cb + * @param[in] status: + * @param[in] buf: + * @param[in] len: + * @return + * None + *********************************************************************/ +static void wfx_rsi_join_fail_cb(uint16_t status, uint8_t * buf, uint32_t len) +{ + WFX_RSI_LOG("%s: error: failed status: %02x on try %d", __func__, status, wfx_rsi.join_retries); + wfx_rsi.join_retries += 1; + wfx_rsi.dev_state &= ~WFX_RSI_ST_STA_CONNECTING; + xEventGroupSetBits(wfx_rsi.events, WFX_EVT_STA_START_JOIN); +} +#ifdef RS911X_SOCKETS + +/****************************************************************** + * @fn wfx_rsi_ipchange_cb(uint16_t status, uint8_t *buf, uint32_t len) + * @brief + * DHCP should end up here + * @param[in] status: + * @param[in] buf: + * @param[in] len: + * @return + * None + *********************************************************************/ +static void wfx_rsi_ipchange_cb(uint16_t status, uint8_t * buf, uint32_t len) +{ + WFX_RSI_LOG("%s: status: %02x", __func__, status); + if (status != RSI_SUCCESS) + { + /* Restart DHCP? */ + xEventGroupSetBits(wfx_rsi.events, WFX_EVT_STA_DO_DHCP); + } + else + { + wfx_rsi.dev_state |= WFX_RSI_ST_STA_DHCP_DONE; + xEventGroupSetBits(wfx_rsi.events, WFX_EVT_STA_DHCP_DONE); + } +} + +#else +/************************************************************************************* + * @fn wfx_rsi_wlan_pkt_cb(uint16_t status, uint8_t *buf, uint32_t len) + * @brief + * Got RAW WLAN data pkt + * @param[in] status: + * @param[in] buf: + * @param[in] len: + * @return + * None + *****************************************************************************************/ +static void wfx_rsi_wlan_pkt_cb(uint16_t status, uint8_t * buf, uint32_t len) +{ + // WFX_RSI_LOG("%s: status=%d, len=%d", __func__, status, len); + if (status != RSI_SUCCESS) + { + return; + } + wfx_host_received_sta_frame_cb(buf, len); +} +#endif /* !Socket support */ + +/************************************************************************************* + * @fn static int32_t wfx_rsi_init(void) + * @brief + * driver initialization + * @param[in] None + * @return + * None + *****************************************************************************************/ +static int32_t wfx_rsi_init(void) +{ + int32_t status; + uint8_t buf[RSI_RESPONSE_HOLD_BUFF_SIZE]; + extern void rsi_hal_board_init(void); + + WFX_RSI_LOG("%s: starting(HEAP_SZ = %d)", __func__, SL_HEAP_SIZE); + //! Driver initialization + status = rsi_driver_init(wfx_rsi_drv_buf, WFX_RSI_BUF_SZ); + if ((status < RSI_DRIVER_STATUS) || (status > WFX_RSI_BUF_SZ)) + { + WFX_RSI_LOG("%s: error: RSI drv init failed with status: %02x", __func__, status); + return status; + } + + WFX_RSI_LOG("%s: rsi_device_init", __func__); + /* ! Redpine module intialisation */ + if ((status = rsi_device_init(LOAD_NWP_FW)) != RSI_SUCCESS) + { + WFX_RSI_LOG("%s: error: rsi_device_init failed with status: %02x", __func__, status); + return status; + } + WFX_RSI_LOG("%s: start wireless drv task", __func__); + /* + * Create the driver task + */ + wfx_rsi.drv_task = xTaskCreateStatic((TaskFunction_t) rsi_wireless_driver_task, "rsi_drv", WFX_RSI_WLAN_TASK_SZ, NULL, + WLAN_TASK_PRIORITY, driverRsiTaskStack, &driverRsiTaskBuffer); + if (NULL == wfx_rsi.drv_task) + { + WFX_RSI_LOG("%s: error: rsi_wireless_driver_task failed", __func__); + return RSI_ERROR_INVALID_PARAM; + } + + /* Initialize WiSeConnect or Module features. */ + WFX_RSI_LOG("%s: rsi_wireless_init", __func__); + if ((status = rsi_wireless_init(OPER_MODE_0, COEX_MODE_0)) != RSI_SUCCESS) + { + WFX_RSI_LOG("%s: error: rsi_wireless_init failed with status: %02x", __func__, status); + return status; + } + + WFX_RSI_LOG("%s: get FW version..", __func__); + /* + * Get the MAC and other info to let the user know about it. + */ + if (rsi_wlan_get(RSI_FW_VERSION, buf, sizeof(buf)) != RSI_SUCCESS) + { + WFX_RSI_LOG("%s: error: rsi_wlan_get(RSI_FW_VERSION) failed with status: %02x", __func__, status); + return status; + } + + buf[sizeof(buf) - 1] = 0; + WFX_RSI_LOG("%s: RSI firmware version: %s", __func__, buf); + //! Send feature frame + if ((status = rsi_send_feature_frame()) != RSI_SUCCESS) + { + WFX_RSI_LOG("%s: error: rsi_send_feature_frame failed with status: %02x", __func__, status); + return status; + } + + WFX_RSI_LOG("%s: sent rsi_send_feature_frame", __func__); + /* initializes wlan radio parameters and WLAN supplicant parameters. + */ + (void) rsi_wlan_radio_init(); /* Required so we can get MAC address */ + if ((status = rsi_wlan_get(RSI_MAC_ADDRESS, &wfx_rsi.sta_mac.octet[0], RESP_BUFF_SIZE)) != RSI_SUCCESS) + { + WFX_RSI_LOG("%s: error: rsi_wlan_get failed with status: %02x", __func__, status); + return status; + } + + WFX_RSI_LOG("%s: WLAN: MAC %02x:%02x:%02x %02x:%02x:%02x", __func__, wfx_rsi.sta_mac.octet[0], wfx_rsi.sta_mac.octet[1], + wfx_rsi.sta_mac.octet[2], wfx_rsi.sta_mac.octet[3], wfx_rsi.sta_mac.octet[4], wfx_rsi.sta_mac.octet[5]); + wfx_rsi.events = xEventGroupCreateStatic(&rsiDriverEventGroup); + /* + * Register callbacks - We are only interested in the connectivity CBs + */ + if ((status = rsi_wlan_register_callbacks(RSI_JOIN_FAIL_CB, wfx_rsi_join_fail_cb)) != RSI_SUCCESS) + { + WFX_RSI_LOG("%s: RSI callback register join failed with status: %02x", __func__, status); + return status; + } +#ifdef RS911X_SOCKETS + (void) rsi_wlan_register_callbacks(RSI_IP_CHANGE_NOTIFY_CB, wfx_rsi_ipchange_cb); +#else + if ((status = rsi_wlan_register_callbacks(RSI_WLAN_DATA_RECEIVE_NOTIFY_CB, wfx_rsi_wlan_pkt_cb)) != RSI_SUCCESS) + { + WFX_RSI_LOG("%s: RSI callback register data-notify failed with status: %02x", __func__, status); + return status; + } +#endif + wfx_rsi.dev_state |= WFX_RSI_ST_DEV_READY; + WFX_RSI_LOG("%s: RSI: OK", __func__); + return RSI_SUCCESS; +} + +/************************************************************************************* + * @fn void wfx_show_err(char *msg) + * @brief + * driver shows error message + * @param[in] msg + * @return + * None + *****************************************************************************************/ +void wfx_show_err(char * msg) +{ + WFX_RSI_LOG("%s: message: %d", __func__, msg); +} + +/*************************************************************************************** + * @fn static void wfx_rsi_save_ap_info() + * @brief + * Saving the details of the AP + * @param[in] None + * @return + * None + *******************************************************************************************/ +static void wfx_rsi_save_ap_info() +{ + int32_t status; + rsi_rsp_scan_t rsp; + + status = + rsi_wlan_scan_with_bitmap_options((int8_t *) &wfx_rsi.sec.ssid[0], AP_CHANNEL_NO_0, &rsp, sizeof(rsp), SCAN_BITMAP_OPTN_1); + if (status) + { + /* + * Scan is done - failed + */ + } + else + { + wfx_rsi.sec.security = rsp.scan_info->security_mode; + wfx_rsi.ap_chan = rsp.scan_info->rf_channel; + memcpy(&wfx_rsi.ap_mac.octet[0], &rsp.scan_info->bssid[0], BSSID_MAX_STR_LEN); + } + if ((wfx_rsi.sec.security == RSI_WPA) || (wfx_rsi.sec.security == RSI_WPA2)) + { + // saving the security before changing into mixed mode + security = wfx_rsi.sec.security; + wfx_rsi.sec.security = RSI_WPA_WPA2_MIXED; + } + if (wfx_rsi.sec.security == SME_WPA3) + { + // returning 3 for WPA3 when DGWIFI read security-type is called + security = WPA3_SECURITY; + wfx_rsi.sec.security = RSI_WPA3; + } + WFX_RSI_LOG("%s: WLAN: connecting to %s==%s, sec=%d, status=%02x", __func__, &wfx_rsi.sec.ssid[0], &wfx_rsi.sec.passkey[0], + wfx_rsi.sec.security, status); +} + +/******************************************************************************************** + * @fn static void wfx_rsi_do_join(void) + * @brief + * Start an async Join command + * @return + * None + **********************************************************************************************/ +static void wfx_rsi_do_join(void) +{ + int32_t status; + + if (wfx_rsi.dev_state & (WFX_RSI_ST_STA_CONNECTING | WFX_RSI_ST_STA_CONNECTED)) + { + WFX_RSI_LOG("%s: not joining - already in progress", __func__); + } + else + { + WFX_RSI_LOG("%s: WLAN: connecting to %s==%s, sec=%d", __func__, &wfx_rsi.sec.ssid[0], &wfx_rsi.sec.passkey[0], + wfx_rsi.sec.security); + /* + * Join the network + */ + /* TODO - make the WFX_SECURITY_xxx - same as RSI_xxx + * Right now it's done by hand - we need something better + */ + wfx_rsi.dev_state |= WFX_RSI_ST_STA_CONNECTING; + + /* Try to connect Wifi with given Credentials + * until there is a success or maximum number of tries allowed + */ + while (++wfx_rsi.join_retries < WFX_RSI_CONFIG_MAX_JOIN) + { + + /* Call rsi connect call with given ssid and password + * And check there is a success + */ + if ((status = rsi_wlan_connect_async((int8_t *) &wfx_rsi.sec.ssid[0], (rsi_security_mode_t) wfx_rsi.sec.security, + &wfx_rsi.sec.passkey[0], wfx_rsi_join_cb)) != RSI_SUCCESS) + { + + wfx_rsi.dev_state &= ~WFX_RSI_ST_STA_CONNECTING; + WFX_RSI_LOG("%s: rsi_wlan_connect_async failed with status: %02x on try %d", __func__, status, + wfx_rsi.join_retries); + vTaskDelay(4000); + /* TODO - Start a timer.. to retry */ + } + else + { + break; // exit while loop + } + } + if (wfx_rsi.join_retries == MAX_JOIN_RETRIES_COUNT) + { + WFX_RSI_LOG("Connect failed after %d tries", wfx_rsi.join_retries); + } + else + { + WFX_RSI_LOG("%s: starting JOIN to %s after %d tries\n", __func__, (char *) &wfx_rsi.sec.ssid[0], wfx_rsi.join_retries); + } + } +} + +/********************************************************************************* + * @fn void wfx_rsi_task(void *arg) + * @brief + * The main WLAN task - started by wfx_wifi_start () that interfaces with RSI. + * The rest of RSI stuff come in call-backs. + * The initialization has been already done. + * @param[in] arg: + * @return + * None + **********************************************************************************/ +/* ARGSUSED */ +void wfx_rsi_task(void * arg) +{ + EventBits_t flags; +#ifndef RS911X_SOCKETS + TickType_t last_dhcp_poll, now; + struct netif * sta_netif; +#endif + (void) arg; + uint32_t rsi_status = wfx_rsi_init(); + if (rsi_status != RSI_SUCCESS) + { + WFX_RSI_LOG("%s: error: wfx_rsi_init with status: %02x", __func__, rsi_status); + return; + } +#ifndef RS911X_SOCKETS + wfx_lwip_start(); + last_dhcp_poll = xTaskGetTickCount(); + sta_netif = wfx_get_netif(SL_WFX_STA_INTERFACE); +#endif + wfx_started_notify(); + + WFX_RSI_LOG("%s: starting event wait", __func__); + for (;;) + { + /* + * This is the main job of this task. + * Wait for commands from the ConnectivityManager + * Make state changes (based on call backs) + */ + flags = xEventGroupWaitBits(wfx_rsi.events, + WFX_EVT_STA_CONN | WFX_EVT_STA_DISCONN | WFX_EVT_STA_START_JOIN +#ifdef RS911X_SOCKETS + | WFX_EVT_STA_DO_DHCP | WFX_EVT_STA_DHCP_DONE +#endif /* RS911X_SOCKETS */ +#ifdef SL_WFX_CONFIG_SOFTAP + | WFX_EVT_AP_START | WFX_EVT_AP_STOP +#endif /* SL_WFX_CONFIG_SOFTAP */ +#ifdef SL_WFX_CONFIG_SCAN + | WFX_EVT_SCAN +#endif /* SL_WFX_CONFIG_SCAN */ + | 0, + pdTRUE, /* Clear the bits */ + pdFALSE, /* Wait for any bit */ + pdMS_TO_TICKS(250)); /* 250 mSec */ + + if (flags) + { + WFX_RSI_LOG("%s: wait event encountered: %x", __func__, flags); + } +#ifdef RS911X_SOCKETS + if (flags & WFX_EVT_STA_DO_DHCP) + { + /* + * Do DHCP - + */ + if ((status = rsi_config_ipaddress(RSI_IP_VERSION_4, RSI_DHCP | RSI_DHCP_UNICAST_OFFER, NULL, NULL, NULL, + &wfx_rsi.ip4_addr[0], IP_CONF_RSP_BUFF_LENGTH_4, STATION)) != RSI_SUCCESS) + { + /* We should try this again.. (perhaps sleep) */ + /* TODO - Figure out what to do here */ + } + } +#else /* !RS911X_SOCKET - using LWIP */ + /* + * Let's handle DHCP polling here + */ + if (wfx_rsi.dev_state & WFX_RSI_ST_STA_CONNECTED) + { + if ((now = xTaskGetTickCount()) > (last_dhcp_poll + pdMS_TO_TICKS(250))) + { +#if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) + uint8_t dhcp_state = dhcpclient_poll(sta_netif); + if (dhcp_state == DHCP_ADDRESS_ASSIGNED && !hasNotifiedIPV4) + { + wfx_dhcp_got_ipv4((uint32_t) sta_netif->ip_addr.u_addr.ip4.addr); + hasNotifiedIPV4 = true; + if (!hasNotifiedWifiConnectivity) + { + wfx_connected_notify(CONNECTION_STATUS_SUCCESS, &wfx_rsi.ap_mac); + hasNotifiedWifiConnectivity = true; + } + } + else if (dhcp_state == DHCP_OFF) + { + wfx_ip_changed_notify(IP_STATUS_FAIL); + hasNotifiedIPV4 = false; + } +#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ + /* Checks if the assigned IPv6 address is preferred by evaluating + * the first block of IPv6 address ( block 0) + */ + if ((ip6_addr_ispreferred(netif_ip6_addr_state(sta_netif, 0))) && !hasNotifiedIPV6) + { + wfx_ipv6_notify(GET_IPV6_SUCCESS); + hasNotifiedIPV6 = true; + if (!hasNotifiedWifiConnectivity) + { + wfx_connected_notify(CONNECTION_STATUS_SUCCESS, &wfx_rsi.ap_mac); + hasNotifiedWifiConnectivity = true; + } + } + last_dhcp_poll = now; + } + } +#endif /* RS911X_SOCKETS */ + if (flags & WFX_EVT_STA_START_JOIN) + { + // saving the AP related info + wfx_rsi_save_ap_info(); + // Joining to the network + wfx_rsi_do_join(); + } + if (flags & WFX_EVT_STA_CONN) + { + /* + * Initiate the Join command (assuming we have been provisioned) + */ + WFX_RSI_LOG("%s: starting LwIP STA", __func__); + wfx_rsi.dev_state |= WFX_RSI_ST_STA_CONNECTED; +#ifndef RS911X_SOCKETS + hasNotifiedWifiConnectivity = false; +#if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) + hasNotifiedIPV4 = false; +#endif // CHIP_DEVICE_CONFIG_ENABLE_IPV4 + hasNotifiedIPV6 = false; + wfx_lwip_set_sta_link_up(); +#endif /* !RS911X_SOCKETS */ + /* We need to get AP Mac - TODO */ + // Uncomment once the hook into MATTER is moved to IP connectivity instead + // of AP connectivity. wfx_connected_notify(0, &wfx_rsi.ap_mac); // This + // is independent of IP connectivity. + } + if (flags & WFX_EVT_STA_DISCONN) + { + wfx_rsi.dev_state &= + ~(WFX_RSI_ST_STA_READY | WFX_RSI_ST_STA_CONNECTING | WFX_RSI_ST_STA_CONNECTED | WFX_RSI_ST_STA_DHCP_DONE); + WFX_RSI_LOG("%s: disconnect notify", __func__); + /* TODO: Implement disconnect notify */ +#ifndef RS911X_SOCKETS + wfx_lwip_set_sta_link_down(); // Internally dhcpclient_poll(netif) -> + // wfx_ip_changed_notify(0) for IPV4 +#if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) + wfx_ip_changed_notify(IP_STATUS_FAIL); + hasNotifiedIPV4 = false; +#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ + wfx_ipv6_notify(GET_IPV6_FAIL); + hasNotifiedIPV6 = false; + hasNotifiedWifiConnectivity = false; +#endif /* !RS911X_SOCKETS */ + } +#ifdef SL_WFX_CONFIG_SCAN + if (flags & WFX_EVT_SCAN) + { + if (!(wfx_rsi.dev_state & WFX_RSI_ST_SCANSTARTED)) + { + WFX_RSI_LOG("%s: start SSID scan", __func__); + int x; + wfx_wifi_scan_result_t ap; + rsi_scan_info_t * scan; + int32_t status; + uint8_t bgscan_results[BG_SCAN_RES_SIZE] = { 0 }; + status = rsi_wlan_bgscan_profile(1, (rsi_rsp_scan_t *) bgscan_results, BG_SCAN_RES_SIZE); + + WFX_RSI_LOG("%s: status: %02x size = %d", __func__, status, BG_SCAN_RES_SIZE); + rsi_rsp_scan_t * rsp = (rsi_rsp_scan_t *) bgscan_results; + if (status) + { + /* + * Scan is done - failed + */ + } + else + for (x = 0; x < rsp->scan_count[0]; x++) + { + scan = &rsp->scan_info[x]; + strcpy(&ap.ssid[0], (char *) &scan->ssid[0]); + if (wfx_rsi.scan_ssid) + { + WFX_RSI_LOG("Inside scan_ssid"); + WFX_RSI_LOG("SCAN SSID: %s , ap scan: %s", wfx_rsi.scan_ssid, ap.ssid); + if (strcmp(wfx_rsi.scan_ssid, ap.ssid) == CMP_SUCCESS) + { + WFX_RSI_LOG("Inside ap details"); + ap.security = scan->security_mode; + ap.rssi = (-1) * scan->rssi_val; + memcpy(&ap.bssid[0], &scan->bssid[0], BSSID_MAX_STR_LEN); + (*wfx_rsi.scan_cb)(&ap); + } + } + else + { + WFX_RSI_LOG("Inside else"); + ap.security = scan->security_mode; + ap.rssi = (-1) * scan->rssi_val; + memcpy(&ap.bssid[0], &scan->bssid[0], BSSID_MAX_STR_LEN); + (*wfx_rsi.scan_cb)(&ap); + } + } + wfx_rsi.dev_state &= ~WFX_RSI_ST_SCANSTARTED; + /* Terminate with end of scan which is no ap sent back */ + (*wfx_rsi.scan_cb)((wfx_wifi_scan_result_t *) 0); + wfx_rsi.scan_cb = (void (*)(wfx_wifi_scan_result_t *)) 0; + + if (wfx_rsi.scan_ssid) + { + vPortFree(wfx_rsi.scan_ssid); + wfx_rsi.scan_ssid = (char *) 0; + } + } + } +#endif /* SL_WFX_CONFIG_SCAN */ +#ifdef SL_WFX_CONFIG_SOFTAP + /* TODO */ + if (flags & WFX_EVT_AP_START) + { + } + if (flags & WFX_EVT_AP_STOP) + { + } +#endif /* SL_WFX_CONFIG_SOFTAP */ + } +} + +#if CHIP_DEVICE_CONFIG_ENABLE_IPV4 +/******************************************************************************************** + * @fn void wfx_dhcp_got_ipv4(uint32_t ip) + * @brief + * Acquire the new ip address + * @param[in] ip: internet protocol + * @return + * None + **********************************************************************************************/ +void wfx_dhcp_got_ipv4(uint32_t ip) +{ + /* + * Acquire the new IP address + */ + wfx_rsi.ip4_addr[0] = (ip) &HEX_VALUE_FF; + wfx_rsi.ip4_addr[1] = (ip >> 8) & HEX_VALUE_FF; + wfx_rsi.ip4_addr[2] = (ip >> 16) & HEX_VALUE_FF; + wfx_rsi.ip4_addr[3] = (ip >> 24) & HEX_VALUE_FF; + WFX_RSI_LOG("%s: DHCP OK: IP=%d.%d.%d.%d", __func__, wfx_rsi.ip4_addr[0], wfx_rsi.ip4_addr[1], wfx_rsi.ip4_addr[2], + wfx_rsi.ip4_addr[3]); + /* Notify the Connectivity Manager - via the app */ + wfx_ip_changed_notify(IP_STATUS_SUCCESS); + wfx_rsi.dev_state |= WFX_RSI_ST_STA_READY; +} +#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ + +/* + * WARNING - Taken from RSI and broken up + * This is my own RSI stuff for not copying code and allocating an extra + * level of indirection - when using LWIP buffers + * see also: int32_t rsi_wlan_send_data_xx(uint8_t *buffer, uint32_t length) + */ +/******************************************************************************************** + * @fn void *wfx_rsi_alloc_pkt() + * @brief + * Allocate packet to send data + * @param[in] None + * @return + * None + **********************************************************************************************/ +void * wfx_rsi_alloc_pkt() +{ + rsi_pkt_t * pkt; + + // Allocate packet to send data + if ((pkt = rsi_pkt_alloc(&rsi_driver_cb->wlan_cb->wlan_tx_pool)) == NULL) + { + return (void *) 0; + } + + return (void *) pkt; +} + +/******************************************************************************************** + * @fn void wfx_rsi_pkt_add_data(void *p, uint8_t *buf, uint16_t len, uint16_t off) + * @brief + * add the data into packet + * @param[in] p: + * @param[in] buf: + * @param[in] len: + * @param[in] off: + * @return + * None + **********************************************************************************************/ +void wfx_rsi_pkt_add_data(void * p, uint8_t * buf, uint16_t len, uint16_t off) +{ + rsi_pkt_t * pkt; + + pkt = (rsi_pkt_t *) p; + memcpy(((char *) pkt->data) + off, buf, len); +} + +/******************************************************************************************** + * @fn int32_t wfx_rsi_send_data(void *p, uint16_t len) + * @brief + * Driver send a data + * @param[in] p: + * @param[in] len: + * @return + * None + **********************************************************************************************/ +int32_t wfx_rsi_send_data(void * p, uint16_t len) +{ + int32_t status; + register uint8_t * host_desc; + rsi_pkt_t * pkt; + + pkt = (rsi_pkt_t *) p; + host_desc = pkt->desc; + memset(host_desc, 0, RSI_HOST_DESC_LENGTH); + rsi_uint16_to_2bytes(host_desc, (len & 0xFFF)); + + // Fill packet type + host_desc[1] |= (RSI_WLAN_DATA_Q << 4); + host_desc[2] |= 0x01; + + rsi_enqueue_pkt(&rsi_driver_cb->wlan_tx_q, pkt); + +#ifndef RSI_SEND_SEM_BITMAP + rsi_driver_cb_non_rom->send_wait_bitmap |= BIT(0); +#endif + // Set TX packet pending event + rsi_set_event(RSI_TX_EVENT); + + if (rsi_wait_on_wlan_semaphore(&rsi_driver_cb_non_rom->send_data_sem, RSI_SEND_DATA_RESPONSE_WAIT_TIME) != RSI_ERROR_NONE) + { + return RSI_ERROR_RESPONSE_TIMEOUT; + } + status = rsi_wlan_get_status(); + + return status; +} + +struct wfx_rsi wfx_rsi; diff --git a/examples/platform/silabs/SiWx917/rs911x/rsi_wlan_config.h b/examples/platform/silabs/SiWx917/rs911x/rsi_wlan_config.h new file mode 100644 index 00000000000000..f2a47b5cb8d2b5 --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/rsi_wlan_config.h @@ -0,0 +1,606 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSI_CONFIG_H +#define RSI_CONFIG_H + +#include "rsi_wlan_defines.h" + +//! Enable feature +#define RSI_ENABLE 1 +//! Disable feature +#define RSI_DISABLE 0 + +//! To enable wlan opermode +#define RSI_OPERMODE_WLAN 0 + +//! To enable concurrent mode +#define CONCURRENT_MODE RSI_DISABLE + +//! opermode command parameters +/*=======================================================================*/ +//! To set wlan feature select bit map +#define RSI_FEATURE_BIT_MAP (FEAT_SECURITY_OPEN) + +//! TCP IP BYPASS feature check +#ifdef RS911X_SOCKETS +#define RSI_TCP_IP_BYPASS RSI_DISABLE + +#define RSI_TCP_IP_FEATURE_BIT_MAP \ + (TCP_IP_FEAT_DHCPV4_CLIENT | /*TCP_IP_FEAT_HTTP_CLIENT | */ \ + TCP_IP_FEAT_EXTENSION_VALID | /*TCP_IP_FEAT_SSL |*/ /*TCP_IP_FEAT_DNS_CLIENT |*/ \ + 0) +//! To set custom feature select bit map +#define RSI_CUSTOM_FEATURE_BIT_MAP FEAT_CUSTOM_FEAT_EXTENSION_VALID + +#else /* Don't use RSI_SOCKETS */ +#define RSI_TCP_IP_BYPASS RSI_ENABLE +#define RSI_TCP_IP_FEATURE_BIT_MAP (TCP_IP_FEAT_BYPASS /*| TCP_IP_FEAT_EXTENSION_VALID*/) +#endif + +//! To set Extended custom feature select bit map +#if WIFI_ENABLE_SECURITY_WPA3 +#ifdef RSI_M4_INTERFACE +#define RSI_EXT_CUSTOM_FEATURE_BIT_MAP (EXT_FEAT_256K_MODE | EXT_FEAT_IEEE_80211W) +#else +#define RSI_EXT_CUSTOM_FEATURE_BIT_MAP (EXT_FEAT_384K_MODE | EXT_FEAT_IEEE_80211W) +#endif +#else +#ifdef RSI_M4_INTERFACE +#define RSI_EXT_CUSTOM_FEATURE_BIT_MAP EXT_FEAT_256K_MODE +#else +#define RSI_EXT_CUSTOM_FEATURE_BIT_MAP EXT_FEAT_384K_MODE +#endif +#endif + +//! To set Extended TCPIP feature select bit map +#define RSI_EXT_TCPIP_FEATURE_BITMAP (/*EXT_FEAT_HTTP_OTAF_SUPPORT |*/ EXT_TCP_IP_SSL_16K_RECORD) +//! Extended custom feature is selected internally +//! CCP -- EXT_FEAT_256K_MODE +//! Wiseconnect -- EXT_FEAT_384K_MODE +/*=======================================================================*/ +//! Feature frame parameters +/*=======================================================================*/ +#define PLL_MODE 0 +#define RF_TYPE 1 //! 0 - External RF 1- Internal RF +#define WIRELESS_MODE 0 +#define ENABLE_PPP 0 +#define AFE_TYPE 1 +#define FEATURE_ENABLES 0 +/*=======================================================================*/ +//! Band command parameters +/*=======================================================================*/ + +//! RSI_BAND_2P4GHZ(2.4GHz) or RSI_BAND_5GHZ(5GHz) or RSI_DUAL_BAND +#define RSI_BAND RSI_BAND_2P4GHZ +/*=======================================================================*/ +//! set region command parameters +/*=======================================================================*/ + +//! RSI_ENABLE or RSI_DISABLE Set region support +#define RSI_SET_REGION_SUPPORT RSI_DISABLE //@ RSI_ENABLE or RSI_DISABLE set region + +//! If 1:region configurations taken from user ;0:region configurations taken from beacon +#define RSI_SET_REGION_FROM_USER_OR_BEACON 1 + +//! 0-Default Region domain ,1-US, 2-EUROPE, 3-JAPAN +#define RSI_REGION_CODE 1 + +//! 0- Without On Board Antenna , 1- With On Board Antenna +#define RSI_MODULE_TYPE 1 + +/*=======================================================================*/ +//! set region AP command parameters +/*=======================================================================*/ + +//! RSI_ENABLE or RSI_DISABLE Set region AP support +#define RSI_SET_REGION_AP_SUPPORT RSI_DISABLE + +//! If 1:region configurations taken from user ;0:region configurations taken from firmware +#define RSI_SET_REGION_AP_FROM_USER RSI_DISABLE + +//! "US" or "EU" or "JP" or other region codes +#define RSI_COUNTRY_CODE "US" +/*=======================================================================*/ + +//! Rejoin parameters +/*=======================================================================*/ + +//! RSI_ENABLE or RSI_DISABLE rejoin params +#define RSI_REJOIN_PARAMS_SUPPORT RSI_ENABLE + +//! Rejoin retry count. If 0 retries infinity times +#define RSI_REJOIN_MAX_RETRY 5 + +//! Periodicity of rejoin attempt +#define RSI_REJOIN_SCAN_INTERVAL 1 + +//! Beacon missed count +#define RSI_REJOIN_BEACON_MISSED_COUNT 40 + +//! RSI_ENABLE or RSI_DISABLE retry for first time join failure +#define RSI_REJOIN_FIRST_TIME_RETRY RSI_DISABLE + +/*=======================================================================*/ + +//! BG scan command parameters +/*=======================================================================*/ + +//! RSI_ENABLE or RSI_DISABLE BG Scan support +#define RSI_BG_SCAN_SUPPORT RSI_ENABLE + +//! RSI_ENABLE or RSI_DISABLE BG scan +#define RSI_BG_SCAN_ENABLE RSI_ENABLE + +//! RSI_ENABLE or RSI_DISABLE instant BG scan +#define RSI_INSTANT_BG RSI_ENABLE + +//! BG scan threshold value +#define RSI_BG_SCAN_THRESHOLD 63 + +//! RSSI tolerance Threshold +#define RSI_RSSI_TOLERANCE_THRESHOLD 4 + +//! BG scan periodicity +#define RSI_BG_SCAN_PERIODICITY 2 + +//! Active scan duration +#define RSI_ACTIVE_SCAN_DURATION 50 + +//! Passive scan duration +#define RSI_PASSIVE_SCAN_DURATION 50 + +//! Multi probe +#define RSI_MULTIPROBE RSI_ENABLE + +/*=======================================================================*/ + +//! RSI_ENABLE or RSI_DISABLE to set RTS threshold config +#define RSI_WLAN_CONFIG_ENABLE RSI_ENABLE + +#define CONFIG_RTSTHRESHOLD 1 + +#define RSI_RTS_THRESHOLD 2346 + +/*=======================================================================*/ + +//! Roaming parameters +/*=======================================================================*/ + +//! RSI_ENABLE or RSI_DISABLE Roaming support +#define RSI_ROAMING_SUPPORT RSI_DISABLE + +//! roaming threshold value +#define RSI_ROAMING_THRESHOLD 67 + +//! roaming hysterisis value +#define RSI_ROAMING_HYSTERISIS 4 + +/*=======================================================================*/ +//! High Throughput Capabilies related information +/*=======================================================================*/ + +//! RSI_ENABLE or RSI_DISABLE 11n mode in AP mode +#define RSI_MODE_11N_ENABLE RSI_DISABLE + +//! HT caps supported +#define RSI_HT_CAPS_NUM_RX_STBC (1 << 8) +#define RSI_HT_CAPS_SHORT_GI_20MHZ BIT(5) +#define RSI_HT_CAPS_GREENFIELD_EN BIT(4) +#define RSI_HT_CAPS_SUPPORT_CH_WIDTH BIT(1) + +//! HT caps bit map. +#define RSI_HT_CAPS_BIT_MAP \ + (RSI_HT_CAPS_NUM_RX_STBC | RSI_HT_CAPS_SHORT_GI_20MHZ | RSI_HT_CAPS_GREENFIELD_EN | RSI_HT_CAPS_SUPPORT_CH_WIDTH) + +/*=======================================================================*/ +//! Scan command parameters +/*=======================================================================*/ + +//! scan channel bit map in 2.4GHz band,valid if given channel to scan is 0 +#define RSI_SCAN_CHANNEL_BIT_MAP_2_4 0 + +//! scan channle bit map in 5GHz band ,valid if given channel to scan is 0 +#define RSI_SCAN_CHANNEL_BIT_MAP_5 0 + +//! scan_feature_bitmap ,valid only if specific channel to scan and ssid are given +#define RSI_SCAN_FEAT_BITMAP 0 + +/*=======================================================================*/ +//! Enterprise configuration command parameters +/*=======================================================================*/ + +//! Enterprise method ,should be one of among TLS, TTLS, FAST or PEAP +#define RSI_EAP_METHOD "TTLS" +//! This parameter is used to configure the module in Enterprise security mode +#define RSI_EAP_INNER_METHOD "\"auth=MSCHAPV2\"" +//! Private Key Password is required for encrypted private key, format is like "\"12345678\"" +#define RSI_PRIVATE_KEY_PASSWORD "" +/*=======================================================================*/ +//! AP configuration command parameters +/*=======================================================================*/ + +//! This Macro is used to enable AP keep alive functionality +#define RSI_AP_KEEP_ALIVE_ENABLE RSI_ENABLE + +//! This parameter is used to configure keep alive type +#define RSI_AP_KEEP_ALIVE_TYPE RSI_NULL_BASED_KEEP_ALIVE + +//! This parameter is used to configure keep alive period +#define RSI_AP_KEEP_ALIVE_PERIOD 100 + +//! This parameter is used to configure maximum stations supported +#define RSI_MAX_STATIONS_SUPPORT 4 +/*=======================================================================*/ +//! Join command parameters +/*=======================================================================*/ + +//! Tx power level +#define RSI_POWER_LEVEL RSI_POWER_LEVEL_HIGH + +//! RSI_JOIN_FEAT_STA_BG_ONLY_MODE_ENABLE or RSI_JOIN_FEAT_LISTEN_INTERVAL_VALID +#if WIFI_ENABLE_SECURITY_WPA3 +#define RSI_JOIN_FEAT_BIT_MAP RSI_JOIN_FEAT_MFP_CAPABLE_REQUIRED +#else +#define RSI_JOIN_FEAT_BIT_MAP 0 +#endif + +#define RSI_LISTEN_INTERVAL 0 + +//! Transmission data rate. Physical rate at which data has to be transmitted. +#define RSI_DATA_RATE RSI_DATA_RATE_AUTO + +/*=======================================================================*/ +//! Ipconf command parameters +/*=======================================================================*/ + +//! DHCP client host name +#define RSI_DHCP_HOST_NAME "efr_9116" + +//! Transmit test command parameters +/*=======================================================================*/ +//! TX TEST rate flags +#define RSI_TX_TEST_RATE_FLAGS 0 + +//! TX TEST per channel bandwidth +#define RSI_TX_TEST_PER_CH_BW 0 + +//! TX TEST aggregation enable or disable +#define RSI_TX_TEST_AGGR_ENABLE RSI_DISABLE + +//! TX TEST delay +#define RSI_TX_TEST_DELAY 0 + +/*======================================================================*/ +//! ssl parameters +/*=======================================================================*/ +//! ssl version +#define RSI_SSL_VERSION 0 + +//! ssl ciphers +#define RSI_SSL_CIPHERS SSL_ALL_CIPHERS + +//! Enable TCP over SSL with TLS version depends on remote side +#define PROTOCOL_DFLT_VERSION BIT(0) + +//! Enable TCP over SSL with TLS version 1.0 +#define PROTOCOL_TLS_1_0 (BIT(0) | BIT(13)) + +//! Enable TCP over SSL with TLS version 1.1 +#define PROTOCOL_TLS_1_1 (BIT(0) | BIT(14)) + +//! Enable TCP over SSL with TLS version 1.2 +#define PROTOCOL_TLS_1_2 (BIT(0) | BIT(15)) +/*=======================================================================*/ +//! Power save command parameters +/*=======================================================================*/ +//! set handshake type of power mode +#define RSI_HAND_SHAKE_TYPE MSG_BASED + +//! 0 - LP, 1- ULP mode with RAM retention and 2 - ULP with Non RAM retention +#define RSI_SELECT_LP_OR_ULP_MODE RSI_ULP_WITH_RAM_RET + +//! set DTIM aligment required +//! 0 - module wakes up at beacon which is just before or equal to listen_interval +//! 1 - module wakes up at DTIM beacon which is just before or equal to listen_interval +#define RSI_DTIM_ALIGNED_TYPE 0 + +//! Monitor interval for the FAST PSP mode +//! default is 50 ms, and this parameter is valid for FAST PSP only +#define RSI_MONITOR_INTERVAL 50 + +//! Number of DTIMs to skip during powersave +#define RSI_NUM_OF_DTIM_SKIP 0 + +//! WMM PS parameters +//! set wmm enable or disable +#define RSI_WMM_PS_ENABLE RSI_DISABLE + +//! set wmm enable or disable +//! 0- TX BASED 1 - PERIODIC +#define RSI_WMM_PS_TYPE 0 + +//! set wmm wake up interval +#define RSI_WMM_PS_WAKE_INTERVAL 20 + +//! set wmm UAPSD bitmap +#define RSI_WMM_PS_UAPSD_BITMAP 15 + +/*=======================================================================*/ +//! Socket configuration +/*=======================================================================*/ +//! RSI_ENABLE or RSI_DISABLE High performance socket +#define HIGH_PERFORMANCE_ENABLE RSI_ENABLE //@ RSI_ENABLE or RSI_DISABLE High performance socket +#define TOTAL_SOCKETS 10 //@ Total number of sockets. TCP TX + TCP RX + UDP TX + UDP RX +#define TOTAL_TCP_SOCKETS 4 //@ Total TCP sockets. TCP TX + TCP RX +#define TOTAL_UDP_SOCKETS 4 //@ Total UDP sockets. UDP TX + UDP RX +#define TCP_TX_ONLY_SOCKETS 0 //@ Total TCP TX only sockets. TCP TX +#define TCP_RX_ONLY_SOCKETS 0 //@ Total TCP RX only sockets. TCP RX +#define UDP_TX_ONLY_SOCKETS 0 //@ Total UDP TX only sockets. UDP TX +#define UDP_RX_ONLY_SOCKETS 0 //@ Total UDP RX only sockets. UDP RX +#define TCP_RX_HIGH_PERFORMANCE_SOCKETS 1 //@ Total TCP RX High Performance sockets +#define TCP_RX_WINDOW_SIZE_CAP 10 //@ TCP RX Window size +#define TCP_RX_WINDOW_DIV_FACTOR 10 //@ TCP RX Window division factor +/*=======================================================================*/ + +//! Socket Create parameters +/*=======================================================================*/ + +//! Initial timeout for Socket +#define RSI_SOCKET_KEEPALIVE_TIMEOUT 1200 + +//! VAP ID for Concurrent mode +#define RSI_VAP_ID 0 + +//! Timeout for join or scan +/*=======================================================================*/ + +//! RSI_ENABLE or RSI_DISABLE Timeout support +#define RSI_TIMEOUT_SUPPORT RSI_DISABLE + +//! roaming threshold value +#define RSI_TIMEOUT_BIT_MAP 1 + +//! roaming hysterisis value +#define RSI_TIMEOUT_VALUE 1500 + +//! Timeout for ping request +/*=======================================================================*/ + +//! Timeout for PING_REQUEST +#define RSI_PING_REQ_TIMEOUT_MS 1000 + +//! Provide HTTP/HTTPS response status code indication to application e.g 200, 404 etc +/*=======================================================================*/ +//! Enable or Diable feature +#define RSI_HTTP_STATUS_INDICATION_EN RSI_DISABLE +/*=======================================================================*/ + +//! Store Config Profile parameters +/*=======================================================================*/ + +//! Client profile +#define RSI_WLAN_PROFILE_CLIENT 0 +//! P2P profile +#define RSI_WLAN_PROFILE_P2P 1 +//! EAP profile +#define RSI_WLAN_PROFILE_EAP 2 +//! AP profile +#define RSI_WLAN_PROFILE_AP 6 +//! All profiles +#define RSI_WLAN_PROFILE_ALL 0xFF + +//! AP Config Profile Parameters +/*==============================================================================*/ + +//! Transmission data rate. Physical rate at which data has to be transmitted. +#define RSI_CONFIG_AP_DATA_RATE RSI_DATA_RATE_AUTO +//! To set wlan feature select bit map +#define RSI_CONFIG_AP_WLAN_FEAT_BIT_MAP (FEAT_SECURITY_PSK) +//! TCP/IP feature select bitmap for selecting TCP/IP features +#define RSI_CONFIG_AP_TCP_IP_FEAT_BIT_MAP (TCP_IP_FEAT_DHCPV4_SERVER) +//! To set custom feature select bit map +#define RSI_CONFIG_AP_CUSTOM_FEAT_BIT_MAP 0 +//! Tx power level +#define RSI_CONFIG_AP_TX_POWER RSI_POWER_LEVEL_HIGH +//! AP SSID +#define RSI_CONFIG_AP_SSID "SILABS_AP" +//! RSI_BAND_2P4GHZ(2.4GHz) or RSI_BAND_5GHZ(5GHz) or RSI_DUAL_BAND +#define RSI_CONFIG_AP_BAND RSI_BAND_2P4GHZ +//! To configure AP channle number +#define RSI_CONFIG_AP_CHANNEL 6 +//! To configure security type +#define RSI_CONFIG_AP_SECURITY_TYPE RSI_WPA +//! To configure encryption type +#define RSI_CONFIG_AP_ENCRYPTION_TYPE 1 +//! To configure PSK +#define RSI_CONFIG_AP_PSK "1234567890" +//! To configure beacon interval +#define RSI_CONFIG_AP_BEACON_INTERVAL 100 +//! To configure DTIM period +#define RSI_CONFIG_AP_DTIM 2 +//! This parameter is used to configure keep alive type +#define RSI_CONFIG_AP_KEEP_ALIVE_TYPE 0 //! RSI_NULL_BASED_KEEP_ALIVE + +#define RSI_CONFIG_AP_KEEP_ALIVE_COUNTER 0 //! 100 +//! This parameter is used to configure keep alive period +#define RSI_CONFIG_AP_KEEP_ALIVE_PERIOD 100 +//! This parameter is used to configure maximum stations supported +#define RSI_CONFIG_AP_MAX_STATIONS_COUNT 4 +//! P2P Network parameters +//! TCP_STACK_USED BIT(0) - IPv4, BIT(1) -IPv6, (BIT(0) | BIT(1)) - Both IPv4 and IPv6 +#define RSI_CONFIG_AP_TCP_STACK_USED BIT(0) +//! IP address of the module +//! E.g: 0x0A0AA8C0 == 192.168.10.10 +#define RSI_CONFIG_AP_IP_ADDRESS 0x0A0AA8C0 +//! IP address of netmask +//! E.g: 0x00FFFFFF == 255.255.255.0 +#define RSI_CONFIG_AP_SN_MASK_ADDRESS 0x00FFFFFF +//! IP address of Gateway +//! E.g: 0x0A0AA8C0 == 192.168.10.10 +#define RSI_CONFIG_AP_GATEWAY_ADDRESS 0x0A0AA8C0 + +//! Client Profile Parameters +/* ===================================================================================== */ + +//! To configure data rate +#define RSI_CONFIG_CLIENT_DATA_RATE RSI_DATA_RATE_AUTO +//! To configure wlan feature bitmap +#define RSI_CONFIG_CLIENT_WLAN_FEAT_BIT_MAP 0 +//! To configure tcp/ip feature bitmap +#define RSI_CONFIG_CLIENT_TCP_IP_FEAT_BIT_MAP BIT(2) +//! To configure custom feature bit map +#define RSI_CONFIG_CLIENT_CUSTOM_FEAT_BIT_MAP 0 +//! To configure TX power +#define RSI_CONFIG_CLIENT_TX_POWER RSI_POWER_LEVEL_HIGH +//! To configure listen interval +#define RSI_CONFIG_CLIENT_LISTEN_INTERVAL 0 +//! To configure SSID +#define RSI_CONFIG_CLIENT_SSID "Matter_9116" +//! RSI_BAND_2P4GHZ(2.4GHz) or RSI_BAND_5GHZ(5GHz) or RSI_DUAL_BAND +#define RSI_CONFIG_CLIENT_BAND RSI_BAND_2P4GHZ +//! To configure channel number +#define RSI_CONFIG_CLIENT_CHANNEL 0 +//! To configure security type +#define RSI_CONFIG_CLIENT_SECURITY_TYPE 0 // RSI_WPA +//! To configure encryption type +#define RSI_CONFIG_CLIENT_ENCRYPTION_TYPE 0 +//! To configure PSK +#define RSI_CONFIG_CLIENT_PSK "1234567890" +//! To configure PMK +#define RSI_CONFIG_CLIENT_PMK "" +//! Client Network parameters +//! TCP_STACK_USED BIT(0) - IPv4, BIT(1) -IPv6, (BIT(0) | BIT(1)) - Both IPv4 and IPv6 +#define RSI_CONFIG_CLIENT_TCP_STACK_USED BIT(0) +//! DHCP mode 1- Enable 0- Disable +//! If DHCP mode is disabled given IP statically +#define RSI_CONFIG_CLIENT_DHCP_MODE RSI_DHCP +//! IP address of the module +//! E.g: 0x0A0AA8C0 == 192.168.10.10 +#define RSI_CONFIG_CLIENT_IP_ADDRESS 0x0A0AA8C0 +//! IP address of netmask +//! E.g: 0x00FFFFFF == 255.255.255.0 +#define RSI_CONFIG_CLIENT_SN_MASK_ADDRESS 0x00FFFFFF +//! IP address of Gateway +//! E.g: 0x010AA8C0 == 192.168.10.1 +#define RSI_CONFIG_CLIENT_GATEWAY_ADDRESS 0x010AA8C0 +//! scan channel bit map in 2.4GHz band,valid if given channel to scan is 0 +#define RSI_CONFIG_CLIENT_SCAN_FEAT_BITMAP 0 +//! Scan channel magic code +#define RSI_CONFIG_CLIENT_MAGIC_CODE 0x4321 +//! scan channel bit map in 2.4GHz band,valid if given channel to scan is 0 +#define RSI_CONFIG_CLIENT_SCAN_CHAN_BITMAP_2_4_GHZ 0 +//! scan channle bit map in 5GHz band ,valid if given channel to scan is 0 +#define RSI_CONFIG_CLIENT_SCAN_CHAN_BITMAP_5_0_GHZ 0 + +//! EAP Client Profile Parameters +/* =========================================================================== */ + +//! To configure data rate +#define RSI_CONFIG_EAP_DATA_RATE RSI_DATA_RATE_AUTO +//! To configure wlan feature bitmap +#define RSI_CONFIG_EAP_WLAN_FEAT_BIT_MAP 0 +//! To configure tcp/ip feature bitmap +#define RSI_CONFIG_EAP_TCP_IP_FEAT_BIT_MAP BIT(2) +//! To configure custom feature bit map +#define RSI_CONFIG_EAP_CUSTOM_FEAT_BIT_MAP 0 +//! To configure EAP TX power +#define RSI_CONFIG_EAP_TX_POWER RSI_POWER_LEVEL_HIGH +//! To Configure scan channel feature bitmap +#define RSI_CONFIG_EAP_SCAN_FEAT_BITMAP 0 +//! scan channel bit map in 2.4GHz band,valid if given channel to scan is 0 +#define RSI_CONFIG_EAP_CHAN_MAGIC_CODE 0 // 0x4321 +//! scan channel bit map in 2.4GHz band,valid if given channel to scan is 0 +#define RSI_CONFIG_EAP_SCAN_CHAN_BITMAP_2_4_GHZ 0 +//! scan channle bit map in 5GHz band ,valid if given channel to scan is 0 +#define RSI_CONFIG_EAP_SCAN_CHAN_BITMAP_5_0_GHZ 0 +//! To configure SSID +#define RSI_CONFIG_EAP_SSID "SILABS_AP" +//! RSI_BAND_2P4GHZ(2.4GHz) or RSI_BAND_5GHZ(5GHz) or RSI_DUAL_BAND +#define RSI_CONFIG_EAP_BAND RSI_BAND_2P4GHZ +//! To set security type +#define RSI_CONFIG_EAP_SECURITY_TYPE RSI_WPA2_EAP +//! To set encryption type +#define RSI_CONFIG_EAP_ENCRYPTION_TYPE 0 +//! To set channel number +#define RSI_CONFIG_EAP_CHANNEL 0 +//! Enterprise method ,should be one of among TLS, TTLS, FAST or PEAP +#define RSI_CONFIG_EAP_METHOD "TLS" +//! This parameter is used to configure the module in Enterprise security mode +#define RSI_CONFIG_EAP_INNER_METHOD "\"auth=MSCHAPV2\"" +//! To configure EAP user identity +#define RSI_CONFIG_EAP_USER_IDENTITY "\"user1\"" +//! TO configure EAP password +#define RSI_CONFIG_EAP_PASSWORD "\"test123\"" +//! EAP Network parameters +//! TCP_STACK_USED BIT(0) - IPv4, BIT(1) -IPv6, (BIT(0) | BIT(1)) - Both IPv4 and IPv6 +#define RSI_CONFIG_EAP_TCP_STACK_USED BIT(0) +//! DHCP mode 1- Enable 0- Disable +//! If DHCP mode is disabled given IP statically +#define RSI_CONFIG_EAP_DHCP_MODE RSI_DHCP +//! IP address of the module +//! E.g: 0x0A0AA8C0 == 192.168.10.10 +#define RSI_CONFIG_EAP_IP_ADDRESS 0x0A0AA8C0 +//! IP address of netmask +//! E.g: 0x00FFFFFF == 255.255.255.0 +#define RSI_CONFIG_EAP_SN_MASK_ADDRESS 0x00FFFFFF +//! IP address of Gateway +//! E.g: 0x010AA8C0 == 192.168.10.1 +#define RSI_CONFIG_EAP_GATEWAY_ADDRESS 0x010AA8C0 + +//! P2P Profile parameters +/* ================================================================================= */ + +//! To configure data rate +#define RSI_CONFIG_P2P_DATA_RATE RSI_DATA_RATE_AUTO +//! To configure wlan feature bitmap +#define RSI_CONFIG_P2P_WLAN_FEAT_BIT_MAP 0 +//! To configure P2P tcp/ip feature bitmap +#define RSI_CONFIG_P2P_TCP_IP_FEAT_BIT_MAP BIT(2) +//! To configure P2P custom feature bitmap +#define RSI_CONFIG_P2P_CUSTOM_FEAT_BIT_MAP 0 +//! TO configure P2P tx power level +#define RSI_CONFIG_P2P_TX_POWER RSI_POWER_LEVEL_HIGH +//! Set P2P go intent +#define RSI_CONFIG_P2P_GO_INTNET 16 //! Support only Autonomous GO mode +//! Set device name +#define RSI_CONFIG_P2P_DEVICE_NAME "WSC1.1" +//! Set device operating channel +#define RSI_CONFIG_P2P_OPERATING_CHANNEL 11 +//! Set SSID postfix +#define RSI_CONFIG_P2P_SSID_POSTFIX "WSC_1_0_0" +//! Set P2P join SSID +#define RSI_CONFIG_P2P_JOIN_SSID "SILABS_AP" +//! Set psk key +#define RSI_CONFIG_P2P_PSK_KEY "12345678" +//! P2P Network parameters +//! TCP_STACK_USED BIT(0) - IPv4, BIT(1) -IPv6, (BIT(0) | BIT(1)) - Both IPv4 and IPv6 +#define RSI_CONFIG_P2P_TCP_STACK_USED BIT(0) +//! DHCP mode 1- Enable 0- Disable +//! If DHCP mode is disabled given IP statically +#define RSI_CONFIG_P2P_DHCP_MODE 1 +//! IP address of the module +//! E.g: 0x0A0AA8C0 == 192.168.10.10 +#define RSI_CONFIG_P2P_IP_ADDRESS 0x0A0AA8C0 +//! IP address of netmask +//! E.g: 0x00FFFFFF == 255.255.255.0 +#define RSI_CONFIG_P2P_SN_MASK_ADDRESS 0x00FFFFFF +//! IP address of Gateway +//! E.g: 0x010AA8C0 == 192.168.10.1 +#define RSI_CONFIG_P2P_GATEWAY_ADDRESS 0x010AA8C0 + +#endif diff --git a/examples/platform/silabs/SiWx917/rs911x/wfx_rsi.h b/examples/platform/silabs/SiWx917/rs911x/wfx_rsi.h new file mode 100644 index 00000000000000..380fc8f29e1693 --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/wfx_rsi.h @@ -0,0 +1,98 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _WFX_RSI_H_ +#define _WFX_RSI_H_ +/* + * Interface to RSI Sapis + */ + +#define WFX_RSI_WLAN_TASK_SZ (1024 + 512 + 256) /* Unknown how big this should be */ +#define WFX_RSI_TASK_SZ (1024 + 1024) /* Stack for the WFX/RSI task */ +#define WFX_RSI_BUF_SZ (1024 * 10) /* May need tweak */ +#define WFX_RSI_CONFIG_MAX_JOIN 5 /* Max join retries */ +#define WFX_RSI_NUM_TIMERS 2 /* Number of RSI timers to alloc */ + +/* + * Various events fielded by the wfx_rsi task + * Make sure that we only use 8 bits (otherwise freeRTOS - may need some changes) + */ +#define WFX_EVT_STA_CONN 0x01 +#define WFX_EVT_STA_DISCONN 0x02 +#define WFX_EVT_AP_START 0x04 +#define WFX_EVT_AP_STOP 0x08 +#define WFX_EVT_SCAN 0x10 /* This is used as scan result and start */ +#define WFX_EVT_STA_START_JOIN 0x20 +#define WFX_EVT_STA_DO_DHCP 0x40 +#define WFX_EVT_STA_DHCP_DONE 0x80 + +#define WFX_RSI_ST_DEV_READY 0x01 +#define WFX_RSI_ST_AP_READY 0x02 +#define WFX_RSI_ST_STA_PROVISIONED 0x04 +#define WFX_RSI_ST_STA_CONNECTING 0x08 +#define WFX_RSI_ST_STA_CONNECTED 0x10 +#define WFX_RSI_ST_STA_DHCP_DONE 0x40 /* Requested to do DHCP after conn */ +#define WFX_RSI_ST_STA_MODE 0x80 /* Enable Station Mode */ +#define WFX_RSI_ST_AP_MODE 0x100 /* Enable AP Mode */ +#define WFX_RSI_ST_STA_READY (WFX_RSI_ST_STA_CONNECTED | WFX_RSI_ST_STA_DHCP_DONE) +#define WFX_RSI_ST_STARTED 0x200 /* RSI task started */ +#define WFX_RSI_ST_SCANSTARTED 0x400 /* Scan Started */ + +struct wfx_rsi +{ + EventGroupHandle_t events; + TaskHandle_t drv_task; + TaskHandle_t wlan_task; + uint16_t dev_state; + uint16_t ap_chan; /* The chan our STA is using */ + wfx_wifi_provision_t sec; +#ifdef SL_WFX_CONFIG_SCAN + void (*scan_cb)(wfx_wifi_scan_result_t *); + char * scan_ssid; /* Which one are we scanning for */ +#endif +#ifdef SL_WFX_CONFIG_SOFTAP + sl_wfx_mac_address_t softap_mac; +#endif + sl_wfx_mac_address_t sta_mac; + sl_wfx_mac_address_t ap_mac; /* To which our STA is connected */ + sl_wfx_mac_address_t ap_bssid; /* To which our STA is connected */ + uint16_t join_retries; + uint8_t ip4_addr[4]; /* Not sure if this is enough */ +}; +#define RSI_SCAN_RESP_SZ 54 + +extern struct wfx_rsi wfx_rsi; +#ifdef __cplusplus +extern "C" { +#endif +void wfx_rsidev_init(void); +void wfx_rsi_task(void * arg); +void efr32Log(const char * aFormat, ...); +#if CHIP_DEVICE_CONFIG_ENABLE_IPV4 +void wfx_ip_changed_notify(int got_ip); +#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ +int32_t wfx_rsi_get_ap_info(wfx_wifi_scan_result_t * ap); +int32_t wfx_rsi_get_ap_ext(wfx_wifi_scan_ext_t * extra_info); +int32_t wfx_rsi_reset_count(); +int32_t wfx_rsi_disconnect(); +#define WFX_RSI_LOG(...) efr32Log(__VA_ARGS__); + +#ifdef __cplusplus +} +#endif + +#endif /* _WFX_RSI_H_ */ diff --git a/examples/platform/silabs/SiWx917/rs911x/wfx_rsi_host.c b/examples/platform/silabs/SiWx917/rs911x/wfx_rsi_host.c new file mode 100644 index 00000000000000..a55e0aeb5cab2e --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/wfx_rsi_host.c @@ -0,0 +1,440 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "em_bus.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" +#include "sl_status.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" + +#include "wfx_host_events.h" +#include "wfx_rsi.h" + +/* wfxRsi Task will use as its stack */ +StackType_t wfxRsiTaskStack[WFX_RSI_TASK_SZ] = { 0 }; + +/* Structure that will hold the TCB of the wfxRsi Task being created. */ +StaticTask_t wfxRsiTaskBuffer; + +/********************************************************************* + * @fn sl_status_t wfx_wifi_start(void) + * @brief + * Called from ConnectivityManagerImpl.cpp - to enable the device + * Create the RSI task and let it deal with life. + * @param[in] None + * @return Returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + ***********************************************************************/ +sl_status_t wfx_wifi_start(void) +{ + if (wfx_rsi.dev_state & WFX_RSI_ST_STARTED) + { + WFX_RSI_LOG("%s: already started.", __func__); + return SL_STATUS_OK; + } + wfx_rsi.dev_state |= WFX_RSI_ST_STARTED; + WFX_RSI_LOG("%s: starting..", __func__); + /* + * Create the Wifi driver task + */ + wfx_rsi.wlan_task = xTaskCreateStatic(wfx_rsi_task, "wfx_rsi", WFX_RSI_TASK_SZ, NULL, WLAN_DRIVER_TASK_PRIORITY, + wfxRsiTaskStack, &wfxRsiTaskBuffer); + + if (NULL == wfx_rsi.wlan_task) + { + WFX_RSI_LOG("%s: error: failed to create task.", __func__); + return SL_STATUS_FAIL; + } + return SL_STATUS_OK; +} + +/********************************************************************* + * @fn void wfx_enable_sta_mode(void) + * @brief + * driver enable the STA mode + * @param[in] None + * @return None + ***********************************************************************/ +void wfx_enable_sta_mode(void) +{ + wfx_rsi.dev_state |= WFX_RSI_ST_STA_MODE; +} + +/********************************************************************* + * @fn bool wfx_is_sta_mode_enabled(void) + * @brief + * driver enabled the STA mode + * @param[in] None + * @return mode + ***********************************************************************/ +bool wfx_is_sta_mode_enabled(void) +{ + bool mode; + mode = !!(wfx_rsi.dev_state & WFX_RSI_ST_STA_MODE); + // WFX_RSI_LOG("%s: %d", __func__, (mode ? "yes" : "no")); + return mode; +} + +/********************************************************************* + * @fn sl_wfx_state_t wfx_get_wifi_state(void) + * @brief + * get the wifi state + * @param[in] None + * @return return SL_WFX_NOT_INIT if successful, + * SL_WFX_started otherwise + ***********************************************************************/ +sl_wfx_state_t wfx_get_wifi_state(void) +{ + if (wfx_rsi.dev_state & WFX_RSI_ST_STA_DHCP_DONE) + { + return SL_WFX_STA_INTERFACE_CONNECTED; + } + if (wfx_rsi.dev_state & WFX_RSI_ST_DEV_READY) + { + return SL_WFX_STARTED; + } + return SL_WFX_NOT_INIT; +} + +/********************************************************************* + * @fn sl_wfx_state_t wfx_get_wifi_state(void) + * @brief + * get the wifi mac address + * @param[in] Interface: + * @param[in] addr : address + * @return + * None + ***********************************************************************/ +void wfx_get_wifi_mac_addr(sl_wfx_interface_t interface, sl_wfx_mac_address_t * addr) +{ + sl_wfx_mac_address_t * mac; + +#ifdef SL_WFX_CONFIG_SOFTAP + mac = (interface == SL_WFX_SOFTAP_INTERFACE) ? &wfx_rsi.softap_mac : &wfx_rsi.sta_mac; +#else + mac = &wfx_rsi.sta_mac; +#endif + *addr = *mac; + WFX_RSI_LOG("%s: %02x:%02x:%02x:%02x:%02x:%02x", __func__, mac->octet[0], mac->octet[1], mac->octet[2], mac->octet[3], + mac->octet[4], mac->octet[5]); +} + +/********************************************************************* + * @fn void wfx_set_wifi_provision(wfx_wifi_provision_t *cfg) + * @brief + * Driver set the wifi provision + * @param[in] cfg: wifi configuration + * @return + * None + ***********************************************************************/ +void wfx_set_wifi_provision(wfx_wifi_provision_t * cfg) +{ + WFX_RSI_LOG("%s: SSID: %s", __func__, &wfx_rsi.sec.ssid[0]); + + wfx_rsi.sec = *cfg; + wfx_rsi.dev_state |= WFX_RSI_ST_STA_PROVISIONED; +} + +/********************************************************************* + * @fn bool wfx_get_wifi_provision(wfx_wifi_provision_t *wifiConfig) + * @brief + * Driver get the wifi provision + * @param[in] wifiConfig: wifi configuration + * @return return false if successful, + * true otherwise + ***********************************************************************/ +bool wfx_get_wifi_provision(wfx_wifi_provision_t * wifiConfig) +{ + if (wifiConfig != NULL) + { + if (wfx_rsi.dev_state & WFX_RSI_ST_STA_PROVISIONED) + { + *wifiConfig = wfx_rsi.sec; + return true; + } + } + return false; +} + +/********************************************************************* + * @fn bool wfx_is_sta_provisioned(void) + * @brief + * Driver is STA provisioned + * @param[in] None + * @return None + ***********************************************************************/ +bool wfx_is_sta_provisioned(void) +{ + bool status = (wfx_rsi.dev_state & WFX_RSI_ST_STA_PROVISIONED) ? true : false; + WFX_RSI_LOG("%s: status: SSID -> %s: %s", __func__, &wfx_rsi.sec.ssid[0], (status ? "provisioned" : "not provisioned")); + return status; +} + +/********************************************************************* + * @fn void wfx_clear_wifi_provision(void) + * @brief + * Driver is clear the wifi provision + * @param[in] None + * @return None + ***********************************************************************/ +void wfx_clear_wifi_provision(void) +{ + memset(&wfx_rsi.sec, 0, sizeof(wfx_rsi.sec)); + wfx_rsi.dev_state &= ~WFX_RSI_ST_STA_PROVISIONED; + WFX_RSI_LOG("%s: completed.", __func__); +} + +/************************************************************************* + * @fn sl_status_t wfx_connect_to_ap(void) + * @brief + * Start a JOIN command to the AP - Done by the wfx_rsi task + * @param[in] None + * @return returns SL_STATUS_OK if successful, + * SL_STATUS_INVALID_CONFIGURATION otherwise + ****************************************************************************/ +sl_status_t wfx_connect_to_ap(void) +{ + if (wfx_rsi.dev_state & WFX_RSI_ST_STA_PROVISIONED) + { + WFX_RSI_LOG("%s: connecting to access point -> SSID: %s, PSK:%s", __func__, &wfx_rsi.sec.ssid[0], &wfx_rsi.sec.passkey[0]); + xEventGroupSetBits(wfx_rsi.events, WFX_EVT_STA_START_JOIN); + } + else + { + WFX_RSI_LOG("%s: error: access point not provisioned", __func__); + return SL_STATUS_INVALID_CONFIGURATION; + } + return SL_STATUS_OK; +} + +/********************************************************************* + * @fn void wfx_setup_ip6_link_local(sl_wfx_interface_t whichif) + * @brief + * Implement the ipv6 setup + * @param[in] whichif: + * @return None + ***********************************************************************/ +void wfx_setup_ip6_link_local(sl_wfx_interface_t whichif) +{ + /* + * TODO: Implement IPV6 setup, currently in wfx_rsi_task() + * This is hooked with MATTER code. + */ + WFX_RSI_LOG("%s: warning: not implemented.", __func__); +} + +/********************************************************************* + * @fn bool wfx_is_sta_connected(void) + * @brief + * called fuction when driver is connected to STA + * @param[in] None + * @return returns ture if successful, + * false otherwise + ***********************************************************************/ +bool wfx_is_sta_connected(void) +{ + bool status; + status = (wfx_rsi.dev_state & WFX_RSI_ST_STA_CONNECTED) ? true : false; + WFX_RSI_LOG("%s: status: %s", __func__, (status ? "connected" : "not connected")); + return status; +} + +/********************************************************************* + * @fn wifi_mode_t wfx_get_wifi_mode() + * @brief + * get the wifi mode + * @param[in] None + * @return return WIFI_MODE_NULL if successful, + * WIFI_MODE_STA otherwise + ***********************************************************************/ +wifi_mode_t wfx_get_wifi_mode() +{ + if (wfx_rsi.dev_state & WFX_RSI_ST_DEV_READY) + return WIFI_MODE_STA; + return WIFI_MODE_NULL; +} + +/********************************************************************* + * @fn sl_status_t wfx_sta_discon(void) + * @brief + * called fuction when STA disconnected + * @param[in] None + * @return return SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + ***********************************************************************/ +sl_status_t wfx_sta_discon(void) +{ + WFX_RSI_LOG("%s: started.", __func__); + int32_t status; + status = wfx_rsi_disconnect(); + wfx_rsi.dev_state &= ~WFX_RSI_ST_STA_CONNECTED; + WFX_RSI_LOG("%s: completed.", __func__); + return status; +} +#if CHIP_DEVICE_CONFIG_ENABLE_IPV4 +/********************************************************************* + * @fn bool wfx_have_ipv4_addr(sl_wfx_interface_t which_if) + * @brief + * called fuction when driver have ipv4 address + * @param[in] which_if: + * @return returns ture if successful, + * false otherwise + ***********************************************************************/ +bool wfx_have_ipv4_addr(sl_wfx_interface_t which_if) +{ + bool status = false; + if (which_if == SL_WFX_STA_INTERFACE) + { + status = (wfx_rsi.dev_state & WFX_RSI_ST_STA_DHCP_DONE) ? true : false; + } + else + { + status = false; /* TODO */ + } + WFX_RSI_LOG("%s: status: %d", __func__, status); + return status; +} +#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ + +/********************************************************************* + * @fn bool wfx_have_ipv6_addr(sl_wfx_interface_t which_if) + * @brief + * called fuction when driver have ipv6 address + * @param[in] which_if: + * @return returns ture if successful, + * false otherwise + ***********************************************************************/ +bool wfx_have_ipv6_addr(sl_wfx_interface_t which_if) +{ + bool status = false; + if (which_if == SL_WFX_STA_INTERFACE) + { + status = (wfx_rsi.dev_state & WFX_RSI_ST_STA_CONNECTED) ? true : false; + } + else + { + status = false; /* TODO */ + } + WFX_RSI_LOG("%s: status: %d", __func__, status); + return status; +} + +/********************************************************************* + * @fn bool wfx_hw_ready(void) + * @brief + * called fuction when driver ready + * @param[in] None + * @return returns ture if successful, + * false otherwise + ***********************************************************************/ +bool wfx_hw_ready(void) +{ + return (wfx_rsi.dev_state & WFX_RSI_ST_DEV_READY) ? true : false; +} + +/********************************************************************* + * @fn int32_t wfx_get_ap_info(wfx_wifi_scan_result_t *ap) + * @brief + * get the access point information + * @param[in] ap: access point + * @return + * access point information + ***********************************************************************/ +int32_t wfx_get_ap_info(wfx_wifi_scan_result_t * ap) +{ + return wfx_rsi_get_ap_info(ap); +} + +/********************************************************************* + * @fn int32_t wfx_get_ap_ext(wfx_wifi_scan_ext_t *extra_info) + * @brief + * get the access point extra information + * @param[in] extra_info:access point extra information + * @return + * access point extra information + ***********************************************************************/ +int32_t wfx_get_ap_ext(wfx_wifi_scan_ext_t * extra_info) +{ + return wfx_rsi_get_ap_ext(extra_info); +} + +/*************************************************************************** + * @fn int32_t wfx_reset_counts(){ + * @brief + * get the driver reset count + * @param[in] None + * @return + * reset count + *****************************************************************************/ +int32_t wfx_reset_counts() +{ + return wfx_rsi_reset_count(); +} + +#ifdef SL_WFX_CONFIG_SCAN +/******************************************************************************* + * @fn bool wfx_start_scan(char *ssid, void (*callback)(wfx_wifi_scan_result_t *)) + * @brief + * called fuction when driver start scaning + * @param[in] ssid: + * @return returns ture if successful, + * false otherwise + *******************************************************************************/ +bool wfx_start_scan(char * ssid, void (*callback)(wfx_wifi_scan_result_t *)) +{ + int sz; + + if (wfx_rsi.scan_cb) + return false; /* Already in progress */ + if (ssid) + { + sz = strlen(ssid); + if ((wfx_rsi.scan_ssid = (char *) pvPortMalloc(sz + 1)) == (char *) 0) + { + return false; + } + strcpy(wfx_rsi.scan_ssid, ssid); + } + wfx_rsi.scan_cb = callback; + xEventGroupSetBits(wfx_rsi.events, WFX_EVT_SCAN); + + return true; +} + +/*************************************************************************** + * @fn void wfx_cancel_scan(void) + * @brief + * called function when driver cancel scaning + * @param[in] None + * @return + * None + *****************************************************************************/ +void wfx_cancel_scan(void) +{ + /* Not possible */ + WFX_RSI_LOG("%s: cannot cancel scan", __func__); +} +#endif /* SL_WFX_CONFIG_SCAN */ diff --git a/examples/platform/silabs/SiWx917/rs911x/wfx_rsidev.c b/examples/platform/silabs/SiWx917/rs911x/wfx_rsidev.c new file mode 100644 index 00000000000000..8d8a3c1803382b --- /dev/null +++ b/examples/platform/silabs/SiWx917/rs911x/wfx_rsidev.c @@ -0,0 +1,272 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef _WFX_NOT_USED_USING_HAL_INSTEAD_ +#include +#include +#include + +#include "em_bus.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" +#include "gpiointerrupt.h" + +/* Need Lwip stuff before rsi is included */ +#include "wfx_host_events.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "rsi_common_apis.h" +#include "rsi_data_types.h" +#include "rsi_error.h" +#include "rsi_nwk.h" +#include "rsi_socket.h" +#include "rsi_utils.h" +#include "rsi_wlan.h" +#include "rsi_wlan_apis.h" +#include "rsi_wlan_config.h" +#include "task.h" + +#include "wfx_host_pinout.h" +#include "wfx_rsi.h" + +/* The following stuff comes from hal/rsi_hal_mcu_interrupt.c */ +static void (*rsi_intr_cb)(void); +/********************************************************************* + * @fn void rsi_hal_intr_config(void (*rsi_interrupt_handler)(void)) + * @brief + * get the hal intr configuration + * @param[in] rsi_interrupt_handler: + * @return + * None + ***********************************************************************/ +void rsi_hal_intr_config(void (*rsi_interrupt_handler)(void)) +{ + rsi_intr_cb = rsi_interrupt_handler; +} + +/*********************************************************************** + * @fn static void wfx_spi_wakeup_irq_callback(uint8_t irqNumber) + * @brief + * end of stuff from hal/rsi_hal_mcu_interrupt.c + * @param[in] irqNumber: + * @return None + * **********************************************************************/ +static void wfx_spi_wakeup_irq_callback(uint8_t irqNumber) +{ + BaseType_t bus_task_woken; + uint32_t interrupt_mask; + + if (irqNumber != SL_WFX_HOST_PINOUT_SPI_IRQ) + return; + // Get and clear all pending GPIO interrupts + interrupt_mask = GPIO_IntGet(); + GPIO_IntClear(interrupt_mask); + if (rsi_intr_cb) + (*rsi_intr_cb)(); +} + +/*********************************************************************** + * @fn static void wfx_host_gpio_init(void) + * @brief + * function called when host gpio intialization + * @param[in] None + * @return None + * **********************************************************************/ +static void wfx_host_gpio_init(void) +{ + // Enable GPIO clock. + CMU_ClockEnable(cmuClock_GPIO, true); + + // Configure WF200 reset pin. + GPIO_PinModeSet(SL_WFX_HOST_PINOUT_RESET_PORT, SL_WFX_HOST_PINOUT_RESET_PIN, gpioModePushPull, PINOUT_CLEAR); + // Configure WF200 WUP pin. + GPIO_PinModeSet(SL_WFX_HOST_PINOUT_WUP_PORT, SL_WFX_HOST_PINOUT_WUP_PIN, gpioModePushPull, PINOUT_CLEAR); + + // GPIO used as IRQ. + GPIO_PinModeSet(SL_WFX_HOST_PINOUT_SPI_WIRQ_PORT, SL_WFX_HOST_PINOUT_SPI_WIRQ_PIN, gpioModeInputPull, PINOUT_CLEAR); + CMU_OscillatorEnable(cmuOsc_LFXO, true, true); + + // Set up interrupt based callback function - trigger on both edges. + GPIOINT_Init(); + GPIO_ExtIntConfig(SL_WFX_HOST_PINOUT_SPI_WIRQ_PORT, SL_WFX_HOST_PINOUT_SPI_WIRQ_PIN, SL_WFX_HOST_PINOUT_SPI_IRQ, true, false, + true); + GPIOINT_CallbackRegister(SL_WFX_HOST_PINOUT_SPI_IRQ, wfx_spi_wakeup_irq_callback); + + // Change GPIO interrupt priority (FreeRTOS asserts unless this is done here!) + NVIC_SetPriority(GPIO_EVEN_IRQn, WFX_GPIO_NVIC_PRIORITY); + NVIC_SetPriority(GPIO_ODD_IRQn, WFX_GPIO_NVIC_PRIORITY); +} + +#define USART SL_WFX_HOST_PINOUT_SPI_PERIPHERAL + +/*********************************************************************** + * @fn static int sl_wfx_host_spi_set_config(void *usart) + * @brief + * set the configuration of spi + * @param[in] usart: + * @return returns 0 if successful, + * -1 otherwise + * **********************************************************************/ +static int sl_wfx_host_spi_set_config(void * usart) +{ + int ret = -1; + + if (0) + { +#if defined(USART0) + } + else if (usart == USART0) + { + usart_clock = cmuClock_USART0; + usart_tx_signal = dmadrvPeripheralSignal_USART0_TXBL; + usart_rx_signal = dmadrvPeripheralSignal_USART0_RXDATAV; + ret = 0; +#endif +#if defined(USART1) + } + else if (usart == USART1) + { + usart_clock = cmuClock_USART1; + usart_tx_signal = dmadrvPeripheralSignal_USART1_TXBL; + usart_rx_signal = dmadrvPeripheralSignal_USART1_RXDATAV; + ret = 0; +#endif +#if defined(USART2) + } + else if (usart == USART2) + { + usart_clock = cmuClock_USART2; + usart_tx_signal = dmadrvPeripheralSignal_USART2_TXBL; + usart_rx_signal = dmadrvPeripheralSignal_USART2_RXDATAV; + ret = 0; +#endif +#if defined(USART3) + } + else if (usart == USART3) + { + usart_clock = cmuClock_USART3; + usart_tx_signal = dmadrvPeripheralSignal_USART3_TXBL; + usart_rx_signal = dmadrvPeripheralSignal_USART3_RXDATAV; + ret = 0; +#endif +#if defined(USART4) + } + else if (usart == USART4) + { + usart_clock = cmuClock_USART4; + usart_tx_signal = dmadrvPeripheralSignal_USART4_TXBL; + usart_rx_signal = dmadrvPeripheralSignal_USART4_RXDATAV; + ret = 0; +#endif +#if defined(USART5) + } + else if (usart == USART5) + { + usart_clock = cmuClock_USART5; + usart_tx_signal = dmadrvPeripheralSignal_USART5_TXBL; + usart_rx_signal = dmadrvPeripheralSignal_USART5_RXDATAV; + ret = 0; +#endif +#if defined(USARTRF0) + } + else if (usart == USARTRF0) + { + usart_clock = cmuClock_USARTRF0; + usart_tx_signal = dmadrvPeripheralSignal_USARTRF0_TXBL; + usart_rx_signal = dmadrvPeripheralSignal_USARTRF0_RXDATAV; + ret = 0; +#endif +#if defined(USARTRF1) + } + else if (usart == USARTRF1) + { + usart_clock = cmuClock_USARTRF1; + usart_tx_signal = dmadrvPeripheralSignal_USARTRF1_TXBL; + usart_rx_signal = dmadrvPeripheralSignal_USARTRF1_RXDATAV; + ret = 0; +#endif + } + + return ret; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_init_bus(void) + * @brief + * Initialize SPI peripheral + * @param[in] None + * @return returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_init_bus(void) +{ + int res; + + // Initialize and enable the USART + USART_InitSync_TypeDef usartInit = USART_INITSYNC_DEFAULT; + + res = sl_wfx_host_spi_set_config(USART); + if (res != SPI_CONFIG_SUCCESS) + { + return SL_STATUS_FAIL; + } + + spi_enabled = true; + dummy_tx_data = 0; + usartInit.baudrate = 36000000u; + usartInit.msbf = true; + CMU_ClockEnable(cmuClock_HFPER, true); + CMU_ClockEnable(cmuClock_GPIO, true); + CMU_ClockEnable(usart_clock, true); + USART_InitSync(USART, &usartInit); + USART->CTRL |= (1u << _USART_CTRL_SMSDELAY_SHIFT); + USART->ROUTELOC0 = + (USART->ROUTELOC0 & ~(_USART_ROUTELOC0_TXLOC_MASK | _USART_ROUTELOC0_RXLOC_MASK | _USART_ROUTELOC0_CLKLOC_MASK)) | + (SL_WFX_HOST_PINOUT_SPI_TX_LOC << _USART_ROUTELOC0_TXLOC_SHIFT) | + (SL_WFX_HOST_PINOUT_SPI_RX_LOC << _USART_ROUTELOC0_RXLOC_SHIFT) | + (SL_WFX_HOST_PINOUT_SPI_CLK_LOC << _USART_ROUTELOC0_CLKLOC_SHIFT); + + USART->ROUTEPEN = USART_ROUTEPEN_TXPEN | USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_CLKPEN; + GPIO_DriveStrengthSet(SL_WFX_HOST_PINOUT_SPI_CLK_PORT, gpioDriveStrengthStrongAlternateStrong); + GPIO_PinModeSet(SL_WFX_HOST_PINOUT_SPI_TX_PORT, SL_WFX_HOST_PINOUT_SPI_TX_PIN, gpioModePushPull, PINOUT_CLEAR); + GPIO_PinModeSet(SL_WFX_HOST_PINOUT_SPI_RX_PORT, SL_WFX_HOST_PINOUT_SPI_RX_PIN, gpioModeInput, PINOUT_CLEAR); + GPIO_PinModeSet(SL_WFX_HOST_PINOUT_SPI_CLK_PORT, SL_WFX_HOST_PINOUT_SPI_CLK_PIN, gpioModePushPull, PINOUT_CLEAR); + + DMADRV_Init(); + DMADRV_AllocateChannel(&tx_dma_channel, NULL); + DMADRV_AllocateChannel(&rx_dma_channel, NULL); + GPIO_PinModeSet(SL_WFX_HOST_PINOUT_SPI_CS_PORT, SL_WFX_HOST_PINOUT_SPI_CS_PIN, gpioModePushPull, PINOUT_SET); + USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX; + + return SL_STATUS_OK; +} + +/*********************************************************************** + * @fn void wfx_rsidev_init(void) + * @brief + * function called when driver rsidev intialization + * @param[in] None + * @return None + * **********************************************************************/ +void wfx_rsidev_init(void) +{ + wfx_host_gpio_init(); +} +#endif /* _NOT_USED */ diff --git a/examples/platform/silabs/SiWx917/uart.cpp b/examples/platform/silabs/SiWx917/uart.cpp new file mode 100644 index 00000000000000..76dbca22ce52d5 --- /dev/null +++ b/examples/platform/silabs/SiWx917/uart.cpp @@ -0,0 +1,343 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "AppConfig.h" +#include "matter_shell.h" + +#ifdef __cplusplus +extern "C" { +#endif +#include "assert.h" +#include "em_core.h" +#include "em_usart.h" +#include "sl_board_control.h" +#include "sl_uartdrv_instances.h" +#if (defined(EFR32MG24) || defined(MGM24)) +#include "sl_uartdrv_eusart_vcom_config.h" +#else +#include "sl_uartdrv_usart_vcom_config.h" +#endif // EFR32MG24 +#include "uart.h" +#include "uartdrv.h" +#include +#include + +#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) +#include "sl_power_manager.h" +#endif + +#if !defined(MIN) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#endif + +#if (defined(EFR32MG24) || defined(MGM24)) +#define HELPER1(x) EUSART##x##_RX_IRQn +#else +#define HELPER1(x) USART##x##_RX_IRQn +#endif + +#define HELPER2(x) HELPER1(x) + +#if (defined(EFR32MG24) || defined(MGM24)) +#define HELPER3(x) EUSART##x##_RX_IRQHandler +#else +#define HELPER3(x) USART##x##_RX_IRQHandler +#endif + +#define HELPER4(x) HELPER3(x) + +// On MG24 boards VCOM runs on the EUSART device, MG12 uses the UART device +#if (defined(EFR32MG24) || defined(MGM24)) +#define USART_IRQ HELPER2(SL_UARTDRV_EUSART_VCOM_PERIPHERAL_NO) +#define USART_IRQHandler HELPER4(SL_UARTDRV_EUSART_VCOM_PERIPHERAL_NO) +#define vcom_handle sl_uartdrv_eusart_vcom_handle +#else +#define USART_IRQ HELPER2(SL_UARTDRV_USART_VCOM_PERIPHERAL_NO) +#define USART_IRQHandler HELPER4(SL_UARTDRV_USART_VCOM_PERIPHERAL_NO) +#define vcom_handle sl_uartdrv_usart_vcom_handle +#endif // EFR32MG24 + +typedef struct +{ + // The data buffer + uint8_t * pBuffer; + // The offset of the first item written to the list. + volatile uint16_t Head; + // The offset of the next item to be written to the list. + volatile uint16_t Tail; + // Maxium size of data that can be hold in buffer before overwriting + uint16_t MaxSize; +} Fifo_t; + +#define UART_CONSOLE_ERR -1 // Negative value in case of UART Console action failed. Triggers a failure for PW_RPC +#define MAX_BUFFER_SIZE 256 +#define MAX_DMA_BUFFER_SIZE (MAX_BUFFER_SIZE / 2) +// In order to reduce the probability of data loss during the dmaFull callback handler we use +// two duplicate receive buffers so we can always have one "active" receive queue. +static uint8_t sRxDmaBuffer[MAX_DMA_BUFFER_SIZE]; +static uint8_t sRxDmaBuffer2[MAX_DMA_BUFFER_SIZE]; +static uint16_t lastCount; // Nb of bytes already processed from the active dmaBuffer + +// Rx buffer for the receive Fifo +static uint8_t sRxFifoBuffer[MAX_BUFFER_SIZE]; +static Fifo_t sReceiveFifo; + +static void UART_rx_callback(UARTDRV_Handle_t handle, Ecode_t transferStatus, uint8_t * data, UARTDRV_Count_t transferCount); + +static bool InitFifo(Fifo_t * fifo, uint8_t * pDataBuffer, uint16_t bufferSize) +{ + if (fifo == NULL || pDataBuffer == NULL) + { + return false; + } + + fifo->pBuffer = pDataBuffer; + fifo->MaxSize = bufferSize; + fifo->Tail = fifo->Head = 0; + + return true; +} + +/* + * @brief Get the amount of unprocessed bytes in the fifo buffer + * @param Ptr to the fifo + * @return Nb of "unread" bytes available in the fifo + */ +static uint16_t AvailableDataCount(Fifo_t * fifo) +{ + uint16_t size = 0; + + // if equal there is no data return 0 directly + if (fifo->Tail != fifo->Head) + { + // determine if a wrap around occurred to get the right data size available. + size = (fifo->Tail < fifo->Head) ? (fifo->MaxSize - fifo->Head + fifo->Tail) : (fifo->Tail - fifo->Head); + } + + return size; +} + +/* + * @brief Get the available space in the fifo buffer to insert new data + * @param Ptr to the fifo + * @return Nb of free bytes left in te buffer + */ +static uint16_t RemainingSpace(Fifo_t * fifo) +{ + return fifo->MaxSize - AvailableDataCount(fifo); +} + +/* + * @brief Write data in the fifo as a circular buffer + * @param Ptr to the fifo, ptr of the data to write, nb of bytes to write + */ +static void WriteToFifo(Fifo_t * fifo, uint8_t * pDataToWrite, uint16_t SizeToWrite) +{ + assert(fifo); + assert(pDataToWrite); + assert(SizeToWrite <= fifo->MaxSize); + + // Overwrite is not allowed + if (RemainingSpace(fifo) >= SizeToWrite) + { + uint16_t nBytesBeforWrap = (fifo->MaxSize - fifo->Tail); + if (SizeToWrite > nBytesBeforWrap) + { + // The number of bytes to write is bigger than the remaining bytes + // in the buffer, we have to wrap around + memcpy(fifo->pBuffer + fifo->Tail, pDataToWrite, nBytesBeforWrap); + memcpy(fifo->pBuffer, pDataToWrite + nBytesBeforWrap, SizeToWrite - nBytesBeforWrap); + } + else + { + memcpy(fifo->pBuffer + fifo->Tail, pDataToWrite, SizeToWrite); + } + + fifo->Tail = (fifo->Tail + SizeToWrite) % fifo->MaxSize; // increment tail with wraparound + } +} + +/* + * @brief Write data in the fifo as a circular buffer + * @param Ptr to the fifo, ptr to contain the data to process, nb of bytes to pull from the fifo + * @return Nb of bytes that were retrieved. + */ +static uint8_t RetrieveFromFifo(Fifo_t * fifo, uint8_t * pData, uint16_t SizeToRead) +{ + assert(fifo); + assert(pData); + assert(SizeToRead <= fifo->MaxSize); + + uint16_t ReadSize = MIN(SizeToRead, AvailableDataCount(fifo)); + uint16_t nBytesBeforWrap = (fifo->MaxSize - fifo->Head); + + if (ReadSize > nBytesBeforWrap) + { + memcpy(pData, fifo->pBuffer + fifo->Head, nBytesBeforWrap); + memcpy(pData + nBytesBeforWrap, fifo->pBuffer, ReadSize - nBytesBeforWrap); + } + else + { + memcpy(pData, (fifo->pBuffer + fifo->Head), ReadSize); + } + + fifo->Head = (fifo->Head + ReadSize) % fifo->MaxSize; // increment tail with wraparound + + return ReadSize; +} + +/* + * @brief Init the the UART for serial communication, Start DMA reception + * and init Fifo to handle the received data from this uart + * + * @Note This UART is used for pigweed rpc + */ +void uartConsoleInit(void) +{ + sl_board_enable_vcom(); + // Init a fifo for the data received on the uart + InitFifo(&sReceiveFifo, sRxFifoBuffer, MAX_BUFFER_SIZE); + + // Activate 2 dma queues to always have one active + + UARTDRV_Receive(vcom_handle, sRxDmaBuffer, MAX_DMA_BUFFER_SIZE, UART_rx_callback); + UARTDRV_Receive(vcom_handle, sRxDmaBuffer2, MAX_DMA_BUFFER_SIZE, UART_rx_callback); + + // Enable USART0/EUSART0 interrupt to wake OT task when data arrives + NVIC_ClearPendingIRQ(USART_IRQ); + NVIC_EnableIRQ(USART_IRQ); + +#if (defined(EFR32MG24) || defined(MGM24)) + // Clear previous RX interrupts + EUSART_IntClear(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL); + + // Enable RX interrupts + EUSART_IntEnable(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL); + + // Enable EUSART + EUSART_Enable(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, eusartEnable); +#else + USART_IntEnable(SL_UARTDRV_USART_VCOM_PERIPHERAL, USART_IF_RXDATAV); +#endif // EFR32MG24 +} + +void USART_IRQHandler(void) +{ +#ifdef ENABLE_CHIP_SHELL + chip::NotifyShellProcessFromISR(); +#endif +#if defined(SL_WIFI) + /* TODO */ +#elif !defined(PW_RPC_ENABLED) + otSysEventSignalPending(); +#endif + +#if (defined(EFR32MG24) || defined(MGM24)) + EUSART_IntClear(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL); +#endif +} + +/* + * @brief Callback triggered when a UARTDRV DMA buffer is full + */ +static void UART_rx_callback(UARTDRV_Handle_t handle, Ecode_t transferStatus, uint8_t * data, UARTDRV_Count_t transferCount) +{ + (void) transferStatus; + + uint8_t writeSize = (transferCount - lastCount); + if (RemainingSpace(&sReceiveFifo) >= writeSize) + { + WriteToFifo(&sReceiveFifo, data + lastCount, writeSize); + lastCount = 0; + } + + UARTDRV_Receive(vcom_handle, data, transferCount, UART_rx_callback); + +#ifdef ENABLE_CHIP_SHELL + chip::NotifyShellProcessFromISR(); +#endif +#if defined(SL_WIFI) + /* TODO */ +#elif !defined(PW_RPC_ENABLED) + otSysEventSignalPending(); +#endif +} + +/* + * @brief Read the data available from the console Uart + * @param Buffer that contains the data to write, number bytes to write. + * @return Amount of bytes written or ERROR (-1) + */ +int16_t uartConsoleWrite(const char * Buf, uint16_t BufLength) +{ + if (Buf == NULL || BufLength < 1) + { + return UART_CONSOLE_ERR; + } + +#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) + sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1); +#endif + + // Use of ForceTransmit here. Transmit with DMA was causing errors with PW_RPC + // TODO Use DMA and find/fix what causes the issue with PW + if (UARTDRV_ForceTransmit(vcom_handle, (uint8_t *) Buf, BufLength) == ECODE_EMDRV_UARTDRV_OK) + { +#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) + sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1); +#endif + return BufLength; + } + +#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) + sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1); +#endif + + return UART_CONSOLE_ERR; +} + +/* + * @brief Read the data available from the console Uart + * @param Buffer for the data to be read, number bytes to read. + * @return Amount of bytes that was read from the rx fifo or ERROR (-1) + */ +int16_t uartConsoleRead(char * Buf, uint16_t NbBytesToRead) +{ + uint8_t * data; + UARTDRV_Count_t count, remaining; + + if (Buf == NULL || NbBytesToRead < 1) + { + return UART_CONSOLE_ERR; + } + + if (NbBytesToRead > AvailableDataCount(&sReceiveFifo)) + { + // Not enough data available in the fifo for the read size request + // If there is data available in dma buffer, get it now. + CORE_ATOMIC_SECTION(UARTDRV_GetReceiveStatus(vcom_handle, &data, &count, &remaining); if (count > lastCount) { + WriteToFifo(&sReceiveFifo, data + lastCount, count - lastCount); + lastCount = count; + }) + } + + return (int16_t) RetrieveFromFifo(&sReceiveFifo, (uint8_t *) Buf, NbBytesToRead); +} + +#ifdef __cplusplus +} +#endif diff --git a/examples/platform/silabs/SiWx917/uart.h b/examples/platform/silabs/SiWx917/uart.h new file mode 100644 index 00000000000000..f708030223b2f7 --- /dev/null +++ b/examples/platform/silabs/SiWx917/uart.h @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void uartConsoleInit(void); +int16_t uartConsoleWrite(const char * Buf, uint16_t BufLength); +int16_t uartConsoleRead(char * Buf, uint16_t NbBytesToRead); + +// Implemented by in openthread code +#ifndef PW_RPC_ENABLED +extern void otPlatUartReceived(const uint8_t * aBuf, uint16_t aBufLength); +extern void otPlatUartSendDone(void); +extern void otSysEventSignalPending(void); +#endif + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/examples/platform/silabs/SiWx917/wf200/efr_spi.c b/examples/platform/silabs/SiWx917/wf200/efr_spi.c new file mode 100644 index 00000000000000..fb35093797679d --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/efr_spi.c @@ -0,0 +1,426 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sl_wfx_configuration_defaults.h" + +#include "sl_wfx.h" +#include "sl_wfx_board.h" +#include "sl_wfx_host_api.h" + +#include "dmadrv.h" +#include "em_bus.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" +#include "spidrv.h" + +#include +#include +#include + +#include "FreeRTOS.h" +#include "semphr.h" +#ifdef SLEEP_ENABLED +#include "sl_power_manager.h" +#endif +#include "AppConfig.h" + +#include "gpiointerrupt.h" + +#include "sl_spidrv_exp_config.h" +#include "sl_wfx_board.h" +#include "sl_wfx_host.h" +#include "sl_wfx_task.h" +#include "wfx_host_events.h" + +extern SPIDRV_Handle_t sl_spidrv_exp_handle; + +#define USART SL_WFX_HOST_PINOUT_SPI_PERIPHERAL + +StaticSemaphore_t xEfrSpiSemaBuffer; +static SemaphoreHandle_t spi_sem; + +static unsigned int tx_dma_channel; +static unsigned int rx_dma_channel; + +static uint32_t dummy_rx_data; +static uint32_t dummy_tx_data; +static bool spi_enabled = false; + +#if defined(EFR32MG12) +uint8_t wirq_irq_nb = SL_WFX_HOST_PINOUT_SPI_IRQ; +#elif defined(EFR32MG24) +uint8_t wirq_irq_nb = SL_WFX_HOST_PINOUT_SPI_WIRQ_PIN; // SL_WFX_HOST_PINOUT_SPI_WIRQ_PIN; +#endif + +#define PIN_OUT_SET 1 +#define PIN_OUT_CLEAR 0 + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_init_bus(void) + * @brief + * Initialize SPI peripheral + * @param[in] None + * @return returns SL_STATUS_OK + *****************************************************************************/ +sl_status_t sl_wfx_host_init_bus(void) +{ + spi_enabled = true; + + /* Assign allocated DMA channel */ + tx_dma_channel = sl_spidrv_exp_handle->txDMACh; + rx_dma_channel = sl_spidrv_exp_handle->rxDMACh; + + /* + * Route EUSART1 MOSI, MISO, and SCLK to the specified pins. CS is + * not controlled by EUSART so there is no write to the corresponding + * EUSARTROUTE register to do this. + */ + MY_USART->CTRL |= (1u << _USART_CTRL_SMSDELAY_SHIFT); + +#if defined(EFR32MG12) + MY_USART->ROUTEPEN = USART_ROUTEPEN_TXPEN | USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_CLKPEN; +#endif + +#if defined(EFR32MG24) + GPIO->USARTROUTE[0].ROUTEEN = GPIO_USART_ROUTEEN_RXPEN | // MISO + GPIO_USART_ROUTEEN_TXPEN | // MOSI + GPIO_USART_ROUTEEN_CLKPEN; +#endif + + spi_sem = xSemaphoreCreateBinaryStatic(&xEfrSpiSemaBuffer); + xSemaphoreGive(spi_sem); + + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_deinit_bus(void) + * @brief + * De-initialize SPI peripheral and DMAs + * @param[in] None + * @return returns SL_STATUS_OK + *****************************************************************************/ +sl_status_t sl_wfx_host_deinit_bus(void) +{ + vSemaphoreDelete(spi_sem); + // Stop DMAs. + DMADRV_StopTransfer(rx_dma_channel); + DMADRV_StopTransfer(tx_dma_channel); + DMADRV_FreeChannel(tx_dma_channel); + DMADRV_FreeChannel(rx_dma_channel); + DMADRV_DeInit(); + USART_Reset(MY_USART); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_spi_cs_assert() + * @brief + * Assert chip select. + * @param[in] None + * @return returns SL_STATUS_OK + *****************************************************************************/ +sl_status_t sl_wfx_host_spi_cs_assert() +{ + GPIO_PinOutClear(SL_SPIDRV_EXP_CS_PORT, SL_SPIDRV_EXP_CS_PIN); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_spi_cs_deassert() + * @brief + * De-Assert chip select. + * @param[in] None + * @return returns SL_STATUS_OK + *****************************************************************************/ +sl_status_t sl_wfx_host_spi_cs_deassert() +{ + GPIO_PinOutSet(SL_SPIDRV_EXP_CS_PORT, SL_SPIDRV_EXP_CS_PIN); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn static bool rx_dma_complete(unsigned int channel, unsigned int sequenceNo, void *userParam) + * @brief + * function called when the DMA complete + * @param[in] channel: + * @param[in] sequenceNo: sequence number + * @param[in] userParam: user parameter + * @return returns true if suucessful, + * false otherwise + *****************************************************************************/ +static bool rx_dma_complete(unsigned int channel, unsigned int sequenceNo, void * userParam) +{ + (void) channel; + (void) sequenceNo; + (void) userParam; + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xSemaphoreGiveFromISR(spi_sem, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + + return true; +} + +/**************************************************************************** + * @fn void receiveDMA(uint8_t *buffer, uint16_t buffer_length) + * @brief + * start receive DMA + * @param[in] buffer: + * @param[in] buffer_length: + * @return None + *****************************************************************************/ +void receiveDMA(uint8_t * buffer, uint16_t buffer_length) +{ + // Start receive DMA. + DMADRV_PeripheralMemory(rx_dma_channel, MY_USART_RX_SIGNAL, (void *) buffer, (void *) &(MY_USART->RXDATA), true, buffer_length, + dmadrvDataSize1, rx_dma_complete, NULL); + + // Start transmit DMA. + DMADRV_MemoryPeripheral(tx_dma_channel, MY_USART_TX_SIGNAL, (void *) &(MY_USART->TXDATA), (void *) &(dummy_tx_data), false, + buffer_length, dmadrvDataSize1, NULL, NULL); +} + +/**************************************************************************** + * @fn void transmitDMA(uint8_t *buffer, uint16_t buffer_length) + * @brief + * start transmit DMA + * @param[in] buffer: + * @param[in] buffer_length: + * @return None + *****************************************************************************/ +void transmitDMA(uint8_t * buffer, uint16_t buffer_length) +{ + // Receive DMA runs only to initiate callback + // Start receive DMA. + DMADRV_PeripheralMemory(rx_dma_channel, MY_USART_RX_SIGNAL, &dummy_rx_data, (void *) &(MY_USART->RXDATA), false, buffer_length, + dmadrvDataSize1, rx_dma_complete, NULL); + // Start transmit DMA. + DMADRV_MemoryPeripheral(tx_dma_channel, MY_USART_TX_SIGNAL, (void *) &(MY_USART->TXDATA), (void *) buffer, true, buffer_length, + dmadrvDataSize1, NULL, NULL); +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_spi_transfer_no_cs_assert(sl_wfx_host_bus_transfer_type_t type, + uint8_t *header, + uint16_t header_length, + uint8_t *buffer, + uint16_t buffer_length) + * @brief + * WFX SPI transfer implementation + * @param[in] type: + * @param[in] header: + * @param[in] header_length: + * @param[in] buffer: + * @param[in] buffer_length: + * @return returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_spi_transfer_no_cs_assert(sl_wfx_host_bus_transfer_type_t type, uint8_t * header, uint16_t header_length, + uint8_t * buffer, uint16_t buffer_length) +{ + sl_status_t result = SL_STATUS_FAIL; + const bool is_read = (type == SL_WFX_BUS_READ); + + while (!(MY_USART->STATUS & USART_STATUS_TXBL)) + { + } + MY_USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX; + + /* header length should be greater than 0 */ + if (header_length > 0) + { + for (uint8_t * buffer_ptr = header; header_length > 0; --header_length, ++buffer_ptr) + { + MY_USART->TXDATA = (uint32_t)(*buffer_ptr); + + while (!(MY_USART->STATUS & USART_STATUS_TXC)) + { + } + } + while (!(MY_USART->STATUS & USART_STATUS_TXBL)) + { + } + } + + /* buffer length should be greater than 0 */ + if (buffer_length > 0) + { + MY_USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX; + if (xSemaphoreTake(spi_sem, portMAX_DELAY) == pdTRUE) + { + if (is_read) + { + receiveDMA(buffer, buffer_length); + result = SL_STATUS_OK; + } + else + { + transmitDMA(buffer, buffer_length); + result = SL_STATUS_OK; + } + + if (xSemaphoreTake(spi_sem, portMAX_DELAY) == pdTRUE) + { + xSemaphoreGive(spi_sem); + } + } + else + { + result = SL_STATUS_TIMEOUT; + } + } + + return result; +} + +/**************************************************************************** + * @fn void sl_wfx_host_start_platform_interrupt(void) + * @brief + * Enable WFX interrupt + * @param[in] none + * @return None + *****************************************************************************/ +void sl_wfx_host_start_platform_interrupt(void) +{ + // Enable (and clear) the bus interrupt + GPIO_ExtIntConfig(SL_WFX_HOST_PINOUT_SPI_WIRQ_PORT, SL_WFX_HOST_PINOUT_SPI_WIRQ_PIN, wirq_irq_nb, true, false, true); +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_disable_platform_interrupt(void) + * @brief + * Disable WFX interrupt + * @param[in] None + * @return returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_disable_platform_interrupt(void) +{ + GPIO_IntDisable(1 << wirq_irq_nb); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_enable_platform_interrupt(void) + * @brief + * enable the platform interrupt + * @param[in] None + * @return returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_enable_platform_interrupt(void) +{ + GPIO_IntEnable(1 << wirq_irq_nb); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_enable_spi(void) + * @brief + * enable spi + * @param[in] None + * @return returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_enable_spi(void) +{ + if (spi_enabled == false) + { +#ifdef SLEEP_ENABLED + // Prevent the host to use lower EM than EM1 + sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1); +#endif + spi_enabled = true; + } + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_disable_spi(void) + * @brief + * disable spi + * @param[in] None + * @return returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_disable_spi(void) +{ + if (spi_enabled == true) + { + spi_enabled = false; +#ifdef SLEEP_ENABLED + // Allow the host to use the lowest allowed EM + sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1); +#endif + } + return SL_STATUS_OK; +} + +/* + * IRQ for SPI callback + * Clear the Interrupt and wake up the task that + * handles the actions of the interrupt (typically - wfx_bus_task ()) + */ +static void sl_wfx_spi_wakeup_irq_callback(uint8_t irqNumber) +{ + BaseType_t bus_task_woken; + uint32_t interrupt_mask; + + if (irqNumber != wirq_irq_nb) + return; + // Get and clear all pending GPIO interrupts + interrupt_mask = GPIO_IntGet(); + GPIO_IntClear(interrupt_mask); + bus_task_woken = pdFALSE; + xSemaphoreGiveFromISR(wfx_wakeup_sem, &bus_task_woken); + vTaskNotifyGiveFromISR(wfx_bus_task_handle, &bus_task_woken); + portYIELD_FROM_ISR(bus_task_woken); +} + +/**************************************************************************** + * Init some actions pins to the WF-200 expansion board + *****************************************************************************/ +void sl_wfx_host_gpio_init(void) +{ + SILABS_LOG("WIFI: GPIO Init:IRQ=%d", wirq_irq_nb); + // Enable GPIO clock. + CMU_ClockEnable(cmuClock_GPIO, true); + + // Configure WF200 reset pin. + GPIO_PinModeSet(SL_WFX_HOST_PINOUT_RESET_PORT, SL_WFX_HOST_PINOUT_RESET_PIN, gpioModePushPull, 0); + // Configure WF200 WUP pin. + GPIO_PinModeSet(SL_WFX_HOST_PINOUT_WUP_PORT, SL_WFX_HOST_PINOUT_WUP_PIN, gpioModePushPull, 0); + + // GPIO used as IRQ. + GPIO_PinModeSet(SL_WFX_HOST_PINOUT_SPI_WIRQ_PORT, SL_WFX_HOST_PINOUT_SPI_WIRQ_PIN, gpioModeInputPull, 0); + CMU_OscillatorEnable(cmuOsc_LFXO, true, true); + + // Set up interrupt based callback function - trigger on both edges. + GPIOINT_Init(); + GPIO_ExtIntConfig(SL_WFX_HOST_PINOUT_SPI_WIRQ_PORT, SL_WFX_HOST_PINOUT_SPI_WIRQ_PIN, wirq_irq_nb, true, false, + false); /* Don't enable it */ + + GPIOINT_CallbackRegister(wirq_irq_nb, sl_wfx_spi_wakeup_irq_callback); + + // Change GPIO interrupt priority (FreeRTOS asserts unless this is done here!) + NVIC_ClearPendingIRQ(1 << wirq_irq_nb); + NVIC_SetPriority(GPIO_EVEN_IRQn, 5); + NVIC_SetPriority(GPIO_ODD_IRQn, 5); +} diff --git a/examples/platform/silabs/SiWx917/wf200/host_if.cpp b/examples/platform/silabs/SiWx917/wf200/host_if.cpp new file mode 100644 index 00000000000000..26bd7886654700 --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/host_if.cpp @@ -0,0 +1,1270 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Includes */ + +#include +#include +#include + +#include "em_bus.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" +#include "gpiointerrupt.h" + +#include "wifi_config.h" + +#include "AppConfig.h" +#include "sl_wfx_board.h" +#include "sl_wfx_host.h" +#include "sl_wfx_task.h" +#include "wfx_host_events.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" + +#include "dhcp_client.h" +#include "ethernetif.h" +#include + +using namespace ::chip; +using namespace ::chip::DeviceLayer; + +/* wfxRsi Task will use as its stack */ +StackType_t wfxEventTaskStack[1024] = { 0 }; + +/* Structure that will hold the TCB of the wfxRsi Task being created. */ +StaticTask_t wfxEventTaskBuffer; + +/* Declare a variable to hold the data associated with the created event group. */ +StaticEventGroup_t wfxEventGroup; + +EventGroupHandle_t sl_wfx_event_group; +TaskHandle_t wfx_events_task_handle; +static sl_wfx_mac_address_t ap_mac; +static uint32_t sta_ip; +static wfx_wifi_scan_result_t ap_info; + +// Set Scan Parameters +#define ACTIVE_CHANNEL_TIME 110 +#define PASSIVE_CHANNEL_TIME 0 +#define NUM_PROBE_REQUEST 2 + +// wfx_fmac_driver context +sl_wfx_context_t wifiContext; +static uint8_t wifi_extra; + +/***************************************************************************** + * macros + ******************************************************************************/ +#define WE_ST_STARTED 1 +#define WE_ST_STA_CONN 2 +#define WE_ST_HW_STARTED 4 + +#ifdef SL_WFX_CONFIG_SOFTAP +// Connection parameters +char softap_ssid[32] = SOFTAP_SSID_DEFAULT; +char softap_passkey[64] = SOFTAP_PASSKEY_DEFAULT; +sl_wfx_security_mode_t softap_security = SOFTAP_SECURITY_DEFAULT; +uint8_t softap_channel = SOFTAP_CHANNEL_DEFAULT; +#endif + +/* station network interface structures */ +struct netif * sta_netif; +wfx_wifi_provision_t wifi_provision; +sl_wfx_get_counters_cnf_t * counters; +sl_wfx_get_counters_cnf_t * Tempcounters; +#define PUT_COUNTER(name) SILABS_LOG("%-24s %lu\r\n", #name, (unsigned long) counters->body.count_##name); + +bool hasNotifiedIPV6 = false; +bool hasNotifiedIPV4 = false; +bool hasNotifiedWifiConnectivity = false; +static uint8_t retryJoin = 0; +bool retryInProgress = false; + +#ifdef SL_WFX_CONFIG_SCAN +static struct scan_result_holder +{ + struct scan_result_holder * next; + wfx_wifi_scan_result scan; +} * scan_save; +static uint8_t scan_count = 0; +static void (*scan_cb)(wfx_wifi_scan_result_t *); /* user-callback - when scan is done */ +static char * scan_ssid; /* Which one are we scanning for */ +static void sl_wfx_scan_result_callback(sl_wfx_scan_result_ind_body_t * scan_result); +static void sl_wfx_scan_complete_callback(uint32_t status); +#endif /* SL_WFX_CONFIG_SCAN */ + +static void wfx_events_task(void * p_arg); + +/* WF200 host callbacks */ +static void sl_wfx_connect_callback(sl_wfx_connect_ind_body_t connect_indication_body); +static void sl_wfx_disconnect_callback(uint8_t * mac, uint16_t reason); +static void sl_wfx_generic_status_callback(sl_wfx_generic_ind_t * frame); + +#ifdef SL_WFX_CONFIG_SOFTAP +static void sl_wfx_start_ap_callback(uint32_t status); +static void sl_wfx_stop_ap_callback(void); +static void sl_wfx_client_connected_callback(uint8_t * mac); +static void sl_wfx_ap_client_disconnected_callback(uint32_t status, uint8_t * mac); +static void sl_wfx_ap_client_rejected_callback(uint32_t status, uint8_t * mac); +#endif + +extern uint32_t gOverrunCount; + +/*************************************************************************** + * @brief + * Creates WFX events processing task. + ******************************************************************************/ +static void wfx_events_task_start() +{ + /* create an event group to track Wi-Fi events */ + sl_wfx_event_group = xEventGroupCreateStatic(&wfxEventGroup); + + wfx_events_task_handle = xTaskCreateStatic(wfx_events_task, "wfx_events", WLAN_TASK_STACK_SIZE, NULL, WLAN_TASK_PRIORITY, + wfxEventTaskStack, &wfxEventTaskBuffer); + if (NULL == wfx_events_task_handle) + { + SILABS_LOG("Failed to create WFX wfx_events"); + } +} + +/**************************************************************************** + * @brief + * Called when the driver needs to post an event + * @param[in] event_payload: + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_process_event(sl_wfx_generic_message_t * event_payload) +{ + switch (event_payload->header.id) + { + /******** INDICATION ********/ + case SL_WFX_STARTUP_IND_ID: { + SILABS_LOG("WFX Startup Completed\r\n"); + PlatformMgrImpl().HandleWFXSystemEvent(WIFI_EVENT, event_payload); + break; + } + case SL_WFX_CONNECT_IND_ID: { + sl_wfx_connect_ind_t * connect_indication = (sl_wfx_connect_ind_t *) event_payload; + sl_wfx_connect_callback(connect_indication->body); + break; + } + case SL_WFX_DISCONNECT_IND_ID: { + sl_wfx_disconnect_ind_t * disconnect_indication = (sl_wfx_disconnect_ind_t *) event_payload; + sl_wfx_disconnect_callback(disconnect_indication->body.mac, disconnect_indication->body.reason); + break; + } + case SL_WFX_RECEIVED_IND_ID: { + sl_wfx_received_ind_t * ethernet_frame = (sl_wfx_received_ind_t *) event_payload; + if (ethernet_frame->body.frame_type == ETH_FRAME) + { + sl_wfx_host_received_frame_callback(ethernet_frame); + } + break; + } +#ifdef SL_WFX_CONFIG_SCAN + case SL_WFX_SCAN_RESULT_IND_ID: { + sl_wfx_scan_result_ind_t * scan_result = (sl_wfx_scan_result_ind_t *) event_payload; + sl_wfx_scan_result_callback(&scan_result->body); + break; + } + case SL_WFX_SCAN_COMPLETE_IND_ID: { + sl_wfx_scan_complete_ind_t * scan_complete = (sl_wfx_scan_complete_ind_t *) event_payload; + sl_wfx_scan_complete_callback(scan_complete->body.status); + break; + } +#endif /* SL_WFX_CONFIG_SCAN */ +#ifdef SL_WFX_CONFIG_SOFTAP + case SL_WFX_START_AP_IND_ID: { + sl_wfx_start_ap_ind_t * start_ap_indication = (sl_wfx_start_ap_ind_t *) event_payload; + sl_wfx_start_ap_callback(start_ap_indication->body.status); + break; + } + case SL_WFX_STOP_AP_IND_ID: { + sl_wfx_stop_ap_callback(); + break; + } + case SL_WFX_AP_CLIENT_CONNECTED_IND_ID: { + sl_wfx_ap_client_connected_ind_t * client_connected_indication = (sl_wfx_ap_client_connected_ind_t *) event_payload; + sl_wfx_client_connected_callback(client_connected_indication->body.mac); + break; + } + case SL_WFX_AP_CLIENT_REJECTED_IND_ID: { + sl_wfx_ap_client_rejected_ind_t * ap_client_rejected_indication = (sl_wfx_ap_client_rejected_ind_t *) event_payload; + sl_wfx_ap_client_rejected_callback(ap_client_rejected_indication->body.reason, ap_client_rejected_indication->body.mac); + break; + } + case SL_WFX_AP_CLIENT_DISCONNECTED_IND_ID: { + sl_wfx_ap_client_disconnected_ind_t * ap_client_disconnected_indication = + (sl_wfx_ap_client_disconnected_ind_t *) event_payload; + sl_wfx_ap_client_disconnected_callback(ap_client_disconnected_indication->body.reason, + ap_client_disconnected_indication->body.mac); + break; + } +#endif /* SL_WFX_CONFIG_SOFTAP */ +#ifdef SL_WFX_USE_SECURE_LINK + case SL_WFX_SECURELINK_EXCHANGE_PUB_KEYS_IND_ID: { + if (host_context.waited_event_id != SL_WFX_SECURELINK_EXCHANGE_PUB_KEYS_IND_ID) + { + memcpy((void *) &sl_wfx_context->secure_link_exchange_ind, (void *) event_payload, event_payload->header.length); + } + break; + } +#endif + case SL_WFX_GENERIC_IND_ID: { + sl_wfx_generic_ind_t * generic_status = (sl_wfx_generic_ind_t *) event_payload; + sl_wfx_generic_status_callback(generic_status); + break; + } + case SL_WFX_EXCEPTION_IND_ID: { + sl_wfx_exception_ind_t * firmware_exception = (sl_wfx_exception_ind_t *) event_payload; + uint8_t * exception_tmp = (uint8_t *) firmware_exception; + SILABS_LOG("firmware exception\r\n"); + for (uint16_t i = 0; i < firmware_exception->header.length; i += 16) + { + SILABS_LOG("hif: %.8x:", i); + for (uint8_t j = 0; (j < 16) && ((i + j) < firmware_exception->header.length); j++) + { + SILABS_LOG(" %.2x", *exception_tmp); + exception_tmp++; + } + SILABS_LOG("\r\n"); + } + break; + } + case SL_WFX_ERROR_IND_ID: { + sl_wfx_error_ind_t * firmware_error = (sl_wfx_error_ind_t *) event_payload; + uint8_t * error_tmp = (uint8_t *) firmware_error; + SILABS_LOG("firmware error %lu\r\n", firmware_error->body.type); + for (uint16_t i = 0; i < firmware_error->header.length; i += 16) + { + SILABS_LOG("hif: %.8x:", i); + for (uint8_t j = 0; (j < 16) && ((i + j) < firmware_error->header.length); j++) + { + SILABS_LOG(" %.2x", *error_tmp); + error_tmp++; + } + SILABS_LOG("\r\n"); + } + break; + } + } + + return SL_STATUS_OK; +} + +#ifdef SL_WFX_CONFIG_SCAN +/**************************************************************************** + * @brief + * Callback for individual scan result + * @param[in] scan_result: Scan result of all SSID's + *****************************************************************************/ +static void sl_wfx_scan_result_callback(sl_wfx_scan_result_ind_body_t * scan_result) +{ + struct scan_result_holder * ap; + + SILABS_LOG("# %2d %2d %03d %02X:%02X:%02X:%02X:%02X:%02X %s", scan_count, scan_result->channel, + ((int16_t)(scan_result->rcpi - 220) / 2), scan_result->mac[0], scan_result->mac[1], scan_result->mac[2], + scan_result->mac[3], scan_result->mac[4], scan_result->mac[5], scan_result->ssid_def.ssid); + /*Report one AP information*/ + SILABS_LOG("\r\n"); + /* don't save if filter only wants specific ssid */ + if (scan_ssid != (char *) 0) + { + if (strcmp(scan_ssid, (char *) &scan_result->ssid_def.ssid[0]) != CMP_SUCCESS) + return; + } + if ((ap = (struct scan_result_holder *) pvPortMalloc(sizeof(*ap))) == (struct scan_result_holder *) 0) + { + SILABS_LOG("*ERR*Scan: No Mem"); + } + else + { + ap->next = scan_save; + scan_save = ap; + /* Not checking if scan_result->ssid_length is < 33 */ + memcpy(ap->scan.ssid, scan_result->ssid_def.ssid, scan_result->ssid_def.ssid_length); + ap->scan.ssid[scan_result->ssid_def.ssid_length] = 0; /* make sure about null terminate */ + /* We do it in this order WPA3 first */ + /* No EAP supported - Is this required */ + if (scan_result->security_mode.wpa3) + { + ap->scan.security = WFX_SEC_WPA3; + } + else if (scan_result->security_mode.wpa2) + { + ap->scan.security = WFX_SEC_WPA2; + } + else if (scan_result->security_mode.wpa) + { + ap->scan.security = WFX_SEC_WPA; + } + else if (scan_result->security_mode.wep) + { + ap->scan.security = WFX_SEC_WEP; + } + else + { + ap->scan.security = WFX_SEC_NONE; + } + ap->scan.chan = scan_result->channel; + ap->scan.rssi = scan_result->rcpi; + memcpy(&ap->scan.bssid[0], &scan_result->mac[0], BSSID_MAX_STR_LEN); + scan_count++; + } +} + +/**************************************************************************** + * @brief + * Callback for scan complete + * @param[in] status:Status of WLAN scan api + *****************************************************************************/ +/* ARGSUSED */ +static void sl_wfx_scan_complete_callback(uint32_t status) +{ + (void) (status); + /* Use scan_count value and reset it */ + xEventGroupSetBits(sl_wfx_event_group, SL_WFX_SCAN_COMPLETE); +} +#endif /* SL_WFX_CONFIG_SCAN */ + +/**************************************************************************** + * @brief + * Callback when station connects + * @param[in] mac: MAC address of device + * @param[in] status: Status of connect call + *****************************************************************************/ +static void sl_wfx_connect_callback(sl_wfx_connect_ind_body_t connect_indication_body) +{ + uint8_t * mac = connect_indication_body.mac; + uint32_t status = connect_indication_body.status; + switch (status) + { + case WFM_STATUS_SUCCESS: { + SILABS_LOG("STA-Connected\r\n"); + memcpy(&ap_mac.octet[0], mac, MAC_ADDRESS_FIRST_OCTET); + sl_wfx_context->state = + static_cast(static_cast(sl_wfx_context->state) | static_cast(SL_WFX_STA_INTERFACE_CONNECTED)); + xEventGroupSetBits(sl_wfx_event_group, SL_WFX_CONNECT); + break; + } + case WFM_STATUS_NO_MATCHING_AP: { + SILABS_LOG("WFX Connection failed, access point not found\r\n"); + break; + } + case WFM_STATUS_CONNECTION_ABORTED: { + SILABS_LOG("WFX Connection aborted\r\n"); + break; + } + case WFM_STATUS_CONNECTION_TIMEOUT: { + SILABS_LOG("WFX Connection timeout\r\n"); + break; + } + case WFM_STATUS_CONNECTION_REJECTED_BY_AP: { + SILABS_LOG("WFX Connection rejected by the access point\r\n"); + break; + } + case WFM_STATUS_CONNECTION_AUTH_FAILURE: { + SILABS_LOG("WFX Connection authentication failure\r\n"); + break; + } + default: { + SILABS_LOG("WF Connection attempt error\r\n"); + } + } + + if ((status != WFM_STATUS_SUCCESS) && retryJoin < MAX_JOIN_RETRIES_COUNT) + { + retryJoin += 1; + retryInProgress = false; + SILABS_LOG("WFX Retry to connect to network count: %d", retryJoin); + sl_wfx_context->state = + static_cast(static_cast(sl_wfx_context->state) & ~static_cast(SL_WFX_STARTED)); + xEventGroupSetBits(sl_wfx_event_group, SL_WFX_RETRY_CONNECT); + } +} + +/**************************************************************************** + * @brief + * Callback for station disconnect + * @param[in] mac: MAC address of device + * @param[in] reason: Reason code of disconnection + *****************************************************************************/ +static void sl_wfx_disconnect_callback(uint8_t * mac, uint16_t reason) +{ + (void) (mac); + SILABS_LOG("WFX Disconnected %d\r\n", reason); + sl_wfx_context->state = + static_cast(static_cast(sl_wfx_context->state) & ~static_cast(SL_WFX_STA_INTERFACE_CONNECTED)); + xEventGroupSetBits(sl_wfx_event_group, SL_WFX_DISCONNECT); +} + +#ifdef SL_WFX_CONFIG_SOFTAP +/**************************************************************************** + * @brief + * Callback for AP started + * @param[in] status: Status of wfx start ap api + *****************************************************************************/ +static void sl_wfx_start_ap_callback(uint32_t status) +{ + if (status == AP_START_SUCCESS) + { + SILABS_LOG("AP started\r\n"); + sl_wfx_context->state = + static_cast(static_cast(sl_wfx_context->state) | static_cast(SL_WFX_AP_INTERFACE_UP)); + xEventGroupSetBits(sl_wfx_event_group, SL_WFX_START_AP); + } + else + { + SILABS_LOG("AP start failed\r\n"); + strcpy(event_log, "AP start failed"); + } +} + +/**************************************************************************** + * @brief + * Callback for AP stopped + *****************************************************************************/ +static void sl_wfx_stop_ap_callback(void) +{ + // TODO + // dhcpserver_clear_stored_mac(); + SILABS_LOG("SoftAP stopped\r\n"); + sl_wfx_context->state = + static_cast(static_cast(sl_wfx_context->state) & ~static_cast(SL_WFX_AP_INTERFACE_UP)); + xEventGroupSetBits(sl_wfx_event_group, SL_WFX_STOP_AP); +} + +/**************************************************************************** + * @brief + * Callback for client connect to AP + * @param[in] mac: MAC address of device + *****************************************************************************/ +static void sl_wfx_client_connected_callback(uint8_t * mac) +{ + SILABS_LOG("Client connected, MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + // TODO + SILABS_LOG("Open a web browser and go to http://%d.%d.%d.%d\r\n", ap_ip_addr0, ap_ip_addr1, ap_ip_addr2, ap_ip_addr3); +} + +/**************************************************************************** + * @brief + * Callback for client rejected from AP + * @param[in] status: Status of ap rejected + * @param[in] mac: MAC address of device + *****************************************************************************/ +static void sl_wfx_ap_client_rejected_callback(uint32_t status, uint8_t * mac) +{ + SILABS_LOG("Client rejected, reason: %d, MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", (int) status, mac[0], mac[1], mac[2], mac[3], + mac[4], mac[5]); +} + +/**************************************************************************** + * @brief + * Callback for AP client disconnect + * @param[in] status: Status of ap dissconnect + * @param[in] mac: + *****************************************************************************/ +static void sl_wfx_ap_client_disconnected_callback(uint32_t status, uint8_t * mac) +{ + // TODO + SILABS_LOG("Client disconnected, reason: %d, MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", (int) status, mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5]); +} +#endif /* SL_WFX_CONFIG_SOFTAP */ + +/**************************************************************************** + * @brief + * Callback for generic status received + * @param[in] farme: + *****************************************************************************/ +static void sl_wfx_generic_status_callback(sl_wfx_generic_ind_t * frame) +{ + (void) (frame); + SILABS_LOG("WFX Generic status received\r\n"); +} + +/*************************************************************************** + * @brief + * WFX events processing task. + * @param[in] p_arg: + * ******************************************************************************/ +static void wfx_events_task(void * p_arg) +{ + TickType_t last_dhcp_poll, now; + EventBits_t flags; + (void) p_arg; + + sta_netif = wfx_get_netif(SL_WFX_STA_INTERFACE); + last_dhcp_poll = xTaskGetTickCount(); + while (true) + { + flags = xEventGroupWaitBits(sl_wfx_event_group, + SL_WFX_CONNECT | SL_WFX_DISCONNECT +#ifdef SL_WFX_CONFIG_SOFTAP + | SL_WFX_START_AP | SL_WFX_STOP_AP +#endif /* SL_WFX_CONFIG_SOFTAP */ +#ifdef SL_WFX_CONFIG_SCAN + | SL_WFX_SCAN_START | SL_WFX_SCAN_COMPLETE +#endif /* SL_WFX_CONFIG_SCAN */ + | BITS_TO_WAIT, + pdTRUE, pdFALSE, pdMS_TO_TICKS(250)); /* 250 msec delay converted to ticks */ + if (flags & SL_WFX_RETRY_CONNECT) + { + if (!retryInProgress) + { + SILABS_LOG("WFX sending the connect command"); + wfx_connect_to_ap(); + retryInProgress = true; + } + } + + if (wifi_extra & WE_ST_STA_CONN) + { + if ((now = xTaskGetTickCount()) > (last_dhcp_poll + pdMS_TO_TICKS(250))) + { +#if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) + uint8_t dhcp_state = dhcpclient_poll(&sta_netif); + + if ((dhcp_state == DHCP_ADDRESS_ASSIGNED) && !hasNotifiedIPV4) + { + wfx_dhcp_got_ipv4((uint32_t) sta_netif->ip_addr.u_addr.ip4.addr); + hasNotifiedIPV4 = true; + if (!hasNotifiedWifiConnectivity) + { + SILABS_LOG("WIFI: Has Notified Wifi Connectivity"); + wfx_connected_notify(CONNECTION_STATUS_SUCCESS, &ap_mac); + hasNotifiedWifiConnectivity = true; + } + } + else if (dhcp_state == DHCP_OFF) + { + wfx_ip_changed_notify(IP_STATUS_FAIL); + hasNotifiedIPV4 = false; + } +#endif // CHIP_DEVICE_CONFIG_ENABLE_IPV4 + if ((ip6_addr_ispreferred(netif_ip6_addr_state(sta_netif, 0))) && !hasNotifiedIPV6) + { + wfx_ipv6_notify(1); + hasNotifiedIPV6 = true; + if (!hasNotifiedWifiConnectivity) + { + wfx_connected_notify(CONNECTION_STATUS_SUCCESS, &ap_mac); + hasNotifiedWifiConnectivity = true; + } + } + last_dhcp_poll = now; + } + } + + if (flags & SL_WFX_CONNECT) + { +#if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) + wfx_ip_changed_notify(IP_STATUS_FAIL); + hasNotifiedIPV4 = false; +#endif // CHIP_DEVICE_CONFIG_ENABLE_IPV4 + wfx_ipv6_notify(GET_IPV6_FAIL); + hasNotifiedIPV6 = false; + hasNotifiedWifiConnectivity = false; + SILABS_LOG("WIFI: Connected to AP"); + wifi_extra |= WE_ST_STA_CONN; + wfx_lwip_set_sta_link_up(); +#ifdef SLEEP_ENABLED + if (!(wfx_get_wifi_state() & SL_WFX_AP_INTERFACE_UP)) + { + // Enable the power save + sl_wfx_set_power_mode(WFM_PM_MODE_PS, WFM_PM_POLL_UAPSD, BEACON_1); + sl_wfx_enable_device_power_save(); + } +#endif // SLEEP_ENABLED + } + + if (flags & SL_WFX_DISCONNECT) + { + +#if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) + wfx_ip_changed_notify(IP_STATUS_FAIL); + hasNotifiedIPV4 = false; +#endif // CHIP_DEVICE_CONFIG_ENABLE_IPV4 + wfx_ipv6_notify(GET_IPV6_FAIL); + hasNotifiedIPV6 = false; + hasNotifiedWifiConnectivity = false; + wifi_extra &= ~WE_ST_STA_CONN; + wfx_lwip_set_sta_link_down(); + } + +#ifdef SL_WFX_CONFIG_SCAN + if (flags & SL_WFX_SCAN_START) + { + /* + * Start the Scan + */ + sl_wfx_ssid_def_t ssid, *sp; + uint16_t num_ssid, slen; + if (scan_ssid) + { + memset(&ssid, 0, sizeof(ssid)); + slen = strlen(scan_ssid); + memcpy(&ssid.ssid[0], scan_ssid, slen); + ssid.ssid_length = slen; + num_ssid = 1; + sp = &ssid; + } + else + { + num_ssid = 0; + sp = (sl_wfx_ssid_def_t *) 0; + } + + SILABS_LOG("WIFI Scan Parameter set to Active channel time %d, Passive " + "Channel Time: %d, Number of prob: %d", + ACTIVE_CHANNEL_TIME, PASSIVE_CHANNEL_TIME, NUM_PROBE_REQUEST); + (void) sl_wfx_set_scan_parameters(ACTIVE_CHANNEL_TIME, PASSIVE_CHANNEL_TIME, NUM_PROBE_REQUEST); + (void) sl_wfx_send_scan_command(WFM_SCAN_MODE_ACTIVE, CHANNEL_LIST, /* Channel list */ + CHANNEL_COUNT, /* Scan all chans */ + sp, num_ssid, IE_DATA, /* IE we're looking for */ + IE_DATA_LENGTH, BSSID_SCAN); + } + if (flags & SL_WFX_SCAN_COMPLETE) + { + struct scan_result_holder *hp, *next; + + SILABS_LOG("WIFI: Return %d scan results", scan_count); + for (hp = scan_save; hp; hp = next) + { + next = hp->next; + (*scan_cb)(&hp->scan); + vPortFree(hp); + } + (*scan_cb)((wfx_wifi_scan_result *) 0); + scan_save = (struct scan_result_holder *) 0; + scan_count = 0; + if (scan_ssid) + { + vPortFree(scan_ssid); + scan_ssid = (char *) 0; + } + /* Terminate scan */ + scan_cb = 0; + } +#endif /* SL_WFX_CONFIG_SCAN */ + } +} + +/**************************************************************************** + * @brief + * Initialize the WF200 used by the two interfaces + *****************************************************************************/ +static sl_status_t wfx_init(void) +{ + /* Initialize the WF200 used by the two interfaces */ + wfx_events_task_start(); + sl_status_t status = sl_wfx_init(&wifiContext); + SILABS_LOG("FMAC Driver version %s", FMAC_DRIVER_VERSION_STRING); + switch (status) + { + case SL_STATUS_OK: + SILABS_LOG("WF200 FW ver:%d.%d.%d [MAC %02x:%02x:%02x-%02x:%02x:%02x]", wifiContext.firmware_major, + wifiContext.firmware_minor, wifiContext.firmware_build, wifiContext.mac_addr_0.octet[0], + wifiContext.mac_addr_0.octet[1], wifiContext.mac_addr_0.octet[2], wifiContext.mac_addr_0.octet[3], + wifiContext.mac_addr_0.octet[4], wifiContext.mac_addr_0.octet[5]); + SILABS_LOG("WF200 Init OK"); + + if (wifiContext.state == SL_WFX_STA_INTERFACE_CONNECTED) + { + sl_wfx_send_disconnect_command(); + } + + break; + case SL_STATUS_WIFI_INVALID_KEY: + SILABS_LOG("*ERR*WF200: F/W keyset invalid"); + break; + case SL_STATUS_WIFI_FIRMWARE_DOWNLOAD_TIMEOUT: + SILABS_LOG("*ERR*WF200: F/W download timo"); + break; + case SL_STATUS_TIMEOUT: + SILABS_LOG("*ERR*WF200: Poll for value timo"); + break; + case SL_STATUS_FAIL: + SILABS_LOG("*ERR*WF200: Error"); + break; + default: + SILABS_LOG("*ERR*WF200: Unknown"); + } + + return status; +} + +/***************************************************************************** + * @brief + * tcp ip, wfx and lwip stack and start dhcp client. + * @return + * sl_status_t Shows init succes or error. + ******************************************************************************/ +static void wfx_wifi_hw_start(void) +{ + sl_status_t status; + + if (wifi_extra & WE_ST_HW_STARTED) + return; + SILABS_LOG("STARTING WF200\n"); + wifi_extra |= WE_ST_HW_STARTED; + + sl_wfx_host_gpio_init(); + if ((status = wfx_init()) == SL_STATUS_OK) + { + /* Initialize the LwIP stack */ + SILABS_LOG("WF200:Start LWIP"); + wfx_lwip_start(); + wifiContext.state = SL_WFX_STARTED; /* Really this is a bit mask */ + SILABS_LOG("WF200:ready.."); + } + else + { + SILABS_LOG("*ERR*WF200:init failed"); + } +} + +/*********************************************************************** + * @brief + * Get AP info + * @param[in] ap: access point information + * @return returns -1 + **************************************************************************/ +int32_t wfx_get_ap_info(wfx_wifi_scan_result_t * ap) +{ + int32_t signal_strength; + SILABS_LOG("WIFI:SSID:: %s", &ap_info.ssid[0]); + memcpy(ap->ssid, ap_info.ssid, sizeof(ap_info.ssid)); + SILABS_LOG("WIFI:Mac addr:: %02x:%02x:%02x:%02x:%02x:%02x", ap_info.bssid[0], ap_info.bssid[1], ap_info.bssid[2], + ap_info.bssid[3], ap_info.bssid[4], ap_info.bssid[5]); + memcpy(ap->bssid, ap_info.bssid, sizeof(ap_info.bssid)); + ap->security = ap_info.security; + SILABS_LOG("WIFI:security:: %d", ap->security); + ap->chan = ap_info.chan; + SILABS_LOG("WIFI:Channel:: to %d", ap->chan); + + sl_status_t status = sl_wfx_get_signal_strength((uint32_t *) &signal_strength); + + if (status == SL_STATUS_OK) + { + SILABS_LOG("status SL_STATUS_OK & signal_strength:: %d", signal_strength); + ap->rssi = (signal_strength - 220) / 2; + } + return status; +} + +/************************************************************************ + * @brief + * Get AP extra info + * @param[in] extra_info: access point extra information + * @return returns -1 + **************************************************************************/ +int32_t wfx_get_ap_ext(wfx_wifi_scan_ext_t * extra_info) +{ + int32_t status; + status = get_all_counters(); + if (status != SL_STATUS_OK) + { + SILABS_LOG("Failed to get the couters"); + } + else + { + extra_info->beacon_lost_count = counters->body.count_miss_beacon; + extra_info->beacon_rx_count = counters->body.count_rx_beacon; + extra_info->mcast_rx_count = counters->body.count_rx_multicast_frames; + extra_info->mcast_tx_count = counters->body.count_tx_multicast_frames; + extra_info->ucast_rx_count = counters->body.count_rx_packets; + extra_info->ucast_tx_count = counters->body.count_tx_packets; + extra_info->overrun_count = gOverrunCount; + } + return status; +} + +sl_status_t get_all_counters(void) +{ + sl_status_t result; + uint8_t command_id = 0x05; + uint16_t mib_id = 0x2035; + sl_wfx_mib_req_t * request = NULL; + uint32_t request_length = SL_WFX_ROUND_UP_EVEN(sizeof(sl_wfx_header_mib_t) + sizeof(sl_wfx_mib_req_body_t)); + + result = + sl_wfx_allocate_command_buffer((sl_wfx_generic_message_t **) &request, command_id, SL_WFX_CONTROL_BUFFER, request_length); + + if (request == NULL) + { + } + + request->body.mib_id = mib_id; + request->header.interface = 0x2; + request->header.encrypted = 0x0; + + result = sl_wfx_send_request(command_id, (sl_wfx_generic_message_t *) request, request_length); + SL_WFX_ERROR_CHECK(result); + + result = sl_wfx_host_wait_for_confirmation(command_id, SL_WFX_DEFAULT_REQUEST_TIMEOUT_MS, (void **) &counters); + SL_WFX_ERROR_CHECK(result); + + SILABS_LOG("%-24s %12s \r\n", "", "Debug Counters Content"); + SILABS_LOG("%-24s %lu\r\n", "rcpi", (unsigned long) counters->body.rcpi); + PUT_COUNTER(plcp_errors); + PUT_COUNTER(fcs_errors); + PUT_COUNTER(tx_packets); + PUT_COUNTER(rx_packets); + PUT_COUNTER(rx_packet_errors); + PUT_COUNTER(rx_decryption_failures); + PUT_COUNTER(rx_mic_failures); + PUT_COUNTER(rx_no_key_failures); + PUT_COUNTER(tx_multicast_frames); + PUT_COUNTER(tx_frames_success); + PUT_COUNTER(tx_frame_failures); + PUT_COUNTER(tx_frames_retried); + PUT_COUNTER(tx_frames_multi_retried); + PUT_COUNTER(rx_frame_duplicates); + PUT_COUNTER(rts_success); + PUT_COUNTER(rts_failures); + PUT_COUNTER(ack_failures); + PUT_COUNTER(rx_multicast_frames); + PUT_COUNTER(rx_frames_success); + PUT_COUNTER(rx_cmacicv_errors); + PUT_COUNTER(rx_cmac_replays); + PUT_COUNTER(rx_mgmt_ccmp_replays); + PUT_COUNTER(rx_bipmic_errors); + PUT_COUNTER(rx_beacon); + PUT_COUNTER(miss_beacon); + +error_handler: + + if (result == SL_STATUS_TIMEOUT) + { + if (sl_wfx_context->used_buffers > 0) + { + sl_wfx_context->used_buffers--; + } + } + if (request != NULL) + { + sl_wfx_free_command_buffer((sl_wfx_generic_message_t *) request, command_id, SL_WFX_CONTROL_BUFFER); + } + + return result; +} + +/************************************************************************ + * @brief + * reset the count + * @return returns -1 + **************************************************************************/ +int32_t wfx_reset_counts() +{ + /* TODO */ + return -1; +} + +/************************************************************************* + * @brief + * I think that this is getting called before FreeRTOS threads are ready + * @return returns SL_STATUS_OK + **************************************************************************/ +sl_status_t wfx_wifi_start(void) +{ + if (wifi_extra & WE_ST_STARTED) + { + SILABS_LOG("WIFI: Already started"); + return SL_STATUS_OK; + } + wifi_extra |= WE_ST_STARTED; + wfx_soft_init(); + wfx_wifi_hw_start(); + + return SL_STATUS_OK; +} + +/**************************************************************************** + * @brief + * get the wifi state + * @return returns wificonetext state + *****************************************************************************/ +sl_wfx_state_t wfx_get_wifi_state(void) +{ + return wifiContext.state; +} + +/**************************************************************************** + * @brief + * getnetif using interface + * @param[in] interface: + * @return returns selectedNetif + *****************************************************************************/ +struct netif * wfx_GetNetif(sl_wfx_interface_t interface) +{ + struct netif * SelectedNetif = NULL; + if (interface == SL_WFX_STA_INTERFACE) + { + SelectedNetif = sta_netif; + } +#ifdef SL_WFX_CONFIG_SOFTAP + else if (interface == SL_WFX_SOFTAP_INTERFACE) + { + // no ap currently + } +#endif + return SelectedNetif; +} + +/**************************************************************************** + * @brief + * get the wifi mac address using interface + * @param[in] interface: + * @return returns wificontext.mac_addr_o if successful, + * wificontext.mac_addr_1 otherwise + *****************************************************************************/ +sl_wfx_mac_address_t wfx_get_wifi_mac_addr(sl_wfx_interface_t interface) +{ + // return Mac address used by WFX SL_WFX_STA_INTERFACE or SL_WFX_SOFTAP_INTERFACE, + return (interface == SL_WFX_STA_INTERFACE) ? wifiContext.mac_addr_0 : wifiContext.mac_addr_1; +} + +/**************************************************************************** + * @brief + * set the wifi provision + * @param[in] wifiConfig: configuration of wifi + *****************************************************************************/ +void wfx_set_wifi_provision(wfx_wifi_provision_t * wifiConfig) +{ + memcpy(wifi_provision.ssid, wifiConfig->ssid, sizeof(wifiConfig->ssid)); + memcpy(wifi_provision.passkey, wifiConfig->passkey, sizeof(wifiConfig->passkey)); + SILABS_LOG("WIFI: Provision SSID=%s", &wifi_provision.ssid[0]); + + /* Not very good - To be improved */ + switch (wifiConfig->security) + { + case WFX_SEC_WPA: + wifi_provision.security = static_cast(sl_wfx_security_mode_e::WFM_SECURITY_MODE_WPA2_WPA1_PSK); + break; + case WFX_SEC_WPA3: + wifi_provision.security = WFM_SECURITY_MODE_WPA3_SAE; + break; + case WFX_SEC_WPA2: + wifi_provision.security = static_cast(sl_wfx_security_mode_e::WFM_SECURITY_MODE_WPA2_WPA1_PSK); + break; + case WFX_SEC_WPA_WPA2_MIXED: + wifi_provision.security = static_cast(sl_wfx_security_mode_e::WFM_SECURITY_MODE_WPA2_WPA1_PSK); + break; + default: + wifi_provision.security = WFM_SECURITY_MODE_WPA2_PSK; + break; + } +} + +/**************************************************************************** + * @brief + * get the wifi provision + * @param[in] wifiConfig: configuration of wifi + * @return returns true if successful, + * false otherwise + *****************************************************************************/ +bool wfx_get_wifi_provision(wfx_wifi_provision_t * wifiConfig) +{ + if (wifiConfig == NULL) + { + return false; + } + memcpy(wifiConfig, &wifi_provision, sizeof(wfx_wifi_provision_t)); + + return true; +} + +/**************************************************************************** + * @brief + * clear the wifi provision + * @return returns true if successful, + * false otherwise + *****************************************************************************/ +void wfx_clear_wifi_provision(void) +{ + memset(&wifi_provision, 0, sizeof(wifi_provision)); +} + +/**************************************************************************** + * @brief + * driver STA provisioned + * @return returns true if successful, + * false otherwise + *****************************************************************************/ +bool wfx_is_sta_provisioned(void) +{ + return (wifi_provision.ssid[0]) ? true : false; +} + +/**************************************************************************** + * @fn sl_status_t wfx_connect_to_ap(void) + * @brief + * driver connect to ap + * @return returns SL_STATUS_NOT_AVAILABLE + *****************************************************************************/ +sl_status_t wfx_connect_to_ap(void) +{ + sl_status_t result; + + if (wifi_provision.ssid[0] == 0) + { + return SL_STATUS_NOT_AVAILABLE; + } + SILABS_LOG("WIFI:JOIN to %s", &wifi_provision.ssid[0]); + + SILABS_LOG("WIFI Scan Parameter set to Active channel time %d, Passive Channel " + "Time: %d, Number of prob: %d", + ACTIVE_CHANNEL_TIME, PASSIVE_CHANNEL_TIME, NUM_PROBE_REQUEST); + (void) sl_wfx_set_scan_parameters(ACTIVE_CHANNEL_TIME, PASSIVE_CHANNEL_TIME, NUM_PROBE_REQUEST); + result = + sl_wfx_send_join_command((uint8_t *) wifi_provision.ssid, strlen(wifi_provision.ssid), NULL, CHANNEL_0, + static_cast(wifi_provision.security), PREVENT_ROAMING, DISABLE_PMF_MODE, + (uint8_t *) wifi_provision.passkey, strlen(wifi_provision.passkey), NULL, IE_DATA_LENGTH); + + return result; +} + +/**************************************************************************** + * @brief + * get the wifi mac addresss + * @param[in] interface: + * @param[in] addr : address + *****************************************************************************/ +void wfx_get_wifi_mac_addr(sl_wfx_interface_t interface, sl_wfx_mac_address_t * addr) +{ + sl_wfx_mac_address_t * mac; + +#ifdef SL_WFX_CONFIG_SOFTAP + mac = (interface == SL_WFX_SOFTAP_INTERFACE) ? &wifiContext.mac_addr_1 : &wifiContext.mac_addr_0; +#else + mac = &wifiContext.mac_addr_0; +#endif + *addr = *mac; + SILABS_LOG("WLAN:Get WiFi Mac addr %02x:%02x:%02x:%02x:%02x:%02x", mac->octet[0], mac->octet[1], mac->octet[2], mac->octet[3], + mac->octet[4], mac->octet[5]); + memcpy(&ap_info.bssid[0], &mac->octet[0], 6); +} + +/**************************************************************************** + * @brief + * function called when driver have ipv4 address + * @param[in] which_if: + * @return returns false if successful, + * true otherwise + *****************************************************************************/ +bool wfx_have_ipv4_addr(sl_wfx_interface_t which_if) +{ + if (which_if == SL_WFX_STA_INTERFACE) + { + return (sta_ip == STA_IP_FAIL) ? false : true; + } + else + { + return false; /* TODO */ + } +} + +/**************************************************************************** + * @brief + * function called when driver have ipv6 address + * @param[in] which_if: + * @return returns false if successful, + * true otherwise + *****************************************************************************/ +bool wfx_have_ipv6_addr(sl_wfx_interface_t which_if) +{ + SILABS_LOG("%s: started.", __func__); + bool status = false; + if (which_if == SL_WFX_STA_INTERFACE) + { + status = wfx_is_sta_connected(); + } + else + { + status = false; /* TODO */ + } + SILABS_LOG("%s: status: %d", __func__, status); + return status; +} + +/**************************************************************************** + * @brief + * Disconnect station mode from connected AP + * @returns Returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t wfx_sta_discon(void) +{ + SILABS_LOG("STA-Disconnecting"); + int32_t status = sl_wfx_send_disconnect_command(); + wifi_extra &= ~WE_ST_STA_CONN; + xEventGroupSetBits(sl_wfx_event_group, SL_WFX_RETRY_CONNECT); + return status; +} + +/**************************************************************************** + * @brief + * enable the STA mode + * @return returns true + *****************************************************************************/ +bool wfx_is_sta_mode_enabled(void) +{ + return true; /* It always is */ +} + +/**************************************************************************** + * @brief + * fuction called when driver is STA connected + * @return returns true if successful, + * false otherwise + *****************************************************************************/ +bool wfx_is_sta_connected(void) +{ + bool val; + + val = (wifi_extra & WE_ST_STA_CONN) ? true : false; + + SILABS_LOG("WLAN: STA %s connected", (val ? "IS" : "NOT")); + + return val; +} + +/**************************************************************************** + * @brief + * It is automatically done when lwip link up + * @return returns true if successful, + * false otherwise + *****************************************************************************/ +void wfx_setup_ip6_link_local(sl_wfx_interface_t whichif) +{ + SILABS_LOG("Setup-IP6: TODO"); /* It is automatically done when lwip link up */ +} + +/**************************************************************************** + * @brief + * get the wifi mode + * @return returns WIFI_MODE_NULL if successful, + * WIFI_MODE_STA otherwise + *****************************************************************************/ +wifi_mode_t wfx_get_wifi_mode() +{ + if (wifiContext.state & SL_WFX_STARTED) + return WIFI_MODE_STA; + return WIFI_MODE_NULL; +} + +/***************************************************************************** + * @brief + * This is called from the context of AppTask + * For WF200 - Start WIFI here + * @return returns true if successful, + * false otherwise + ******************************************************************************/ +bool wfx_hw_ready(void) +{ + return (wifiContext.state & SL_WFX_STARTED) ? true : false; +} + +#if CHIP_DEVICE_CONFIG_ENABLE_IPV4 +/***************************************************************************** + * @brief + * function called when dhcp got ipv4 + * @param[in] ip : internet protocol + ******************************************************************************/ +void wfx_dhcp_got_ipv4(uint32_t ip) +{ + /* Acquire the new IP address + */ + sta_ip = ip; + wfx_ip_changed_notify(IP_STATUS_SUCCESS); +} +#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ + +/***************************************************************************** + * @brief + * function called from connectivityManager + ******************************************************************************/ +void wfx_enable_sta_mode(void) +{ + /* Nothing to do - default is that it is + place holder */ +} + +/**************************************************************************** + * @brief + * driver scan start + * @param[in] callback: Callback from the wifi scan results + * @return returns true if successful, + * false otherwise + *****************************************************************************/ +#ifdef SL_WFX_CONFIG_SCAN +bool wfx_start_scan(char * ssid, void (*callback)(wfx_wifi_scan_result_t *)) +{ + int sz; + + if (scan_cb) + return false; /* Already in progress */ + if (ssid) + { + sz = strlen(ssid); + if ((scan_ssid = (char *) pvPortMalloc(sz + 1)) == (char *) 0) + { + return false; + } + strcpy(scan_ssid, ssid); + } + scan_cb = callback; + xEventGroupSetBits(sl_wfx_event_group, SL_WFX_SCAN_START); + + return true; +} + +/**************************************************************************** + * @brief + * driver scan cancelation + *****************************************************************************/ +void wfx_cancel_scan(void) +{ + struct scan_result_holder *hp, *next; + /* Not possible */ + if (!scan_cb) + { + return; + } + sl_wfx_send_stop_scan_command(); + for (hp = scan_save; hp; hp = next) + { + next = hp->next; + vPortFree(hp); + } + scan_save = (struct scan_result_holder *) 0; + scan_count = 0; + if (scan_ssid) + { + vPortFree(scan_ssid); + scan_ssid = (char *) 0; + } + scan_cb = 0; +} +#endif /* SL_WFX_CONFIG_SCAN */ diff --git a/examples/platform/silabs/SiWx917/wf200/sl_wfx_board.h b/examples/platform/silabs/SiWx917/wf200/sl_wfx_board.h new file mode 100644 index 00000000000000..96ab9681745fdc --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/sl_wfx_board.h @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SL_WFX_BOARD_H_ +#define _SL_WFX_BOARD_H_ +/* + * Pull in the right board PINS + */ +#if defined(EFR32MG12_BRD4161A) || defined(BRD4161A) || defined(EFR32MG12_BRD4162A) || defined(BRD4162A) || \ + defined(EFR32MG12_BRD4163A) || defined(BRD4163A) || defined(EFR32MG12_BRD4164A) || defined(BRD4164A) || \ + defined(EFR32MG12_BRD4170A) || defined(BRD4170A) +#include "brd4161a.h" +#elif defined(EFR32MG24_BRD4186C) || defined(BRD4186C) || defined(EFR32MG24_BRD4186A) || defined(BRD4186A) +#include "brd4186c.h" +#elif defined(EFR32MG24_BRD4187C) || defined(BRD4187C) || defined(EFR32MG24_BRD4187A) || defined(BRD4187A) +#include "brd4187c.h" +#else +#error "Need SPI Pins" +#endif /* EFR32MG12_BRD4161A */ +#endif /* _SL_WFX_BOARD_H_ */ diff --git a/examples/platform/silabs/SiWx917/wf200/sl_wfx_configuration.h b/examples/platform/silabs/SiWx917/wf200/sl_wfx_configuration.h new file mode 100644 index 00000000000000..deb468d1a6af73 --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/sl_wfx_configuration.h @@ -0,0 +1,30 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// SL_WFX_DEFAULT_REQUEST_TIMEOUT_MS> Timeout period in milliseconds<250-10000> +// Default: 5000 +// Timeout period in milliseconds for requests. +#define SL_WFX_DEFAULT_REQUEST_TIMEOUT_MS (5000) + +// WFx Secure Link configuration + +// SL_WFX_SLK_CURVE25519> Use crypto curves +// Default: 1 +// If this option is enabled ECDH crypto is used, KDF otherwise. +#define SL_WFX_SLK_CURVE25519 (1) diff --git a/examples/platform/silabs/SiWx917/wf200/sl_wfx_crypto.c b/examples/platform/silabs/SiWx917/wf200/sl_wfx_crypto.c new file mode 100644 index 00000000000000..ddad3ec5b95dde --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/sl_wfx_crypto.c @@ -0,0 +1,409 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef SL_WFX_USE_SECURE_LINK + +/* Includes */ + +#include "sl_wfx.h" +#include + +#include "mbedtls/ccm.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/entropy.h" +#include "mbedtls/md.h" +#include "mbedtls/sha256.h" + +#include "FreeRTOS.h" +#include "queue.h" +#include "semphr.h" +#include "task.h" + +// Secure link MAC key location for WGM160P (in DI page in flash) +#ifdef EFM32GG11B820F2048GM64 // WGM160PX22KGA2 +#define SL_WFX_FCCC_BASE_ADDR ((void *) 0x0fe08000ul) +#define SL_WFX_FCCC_DI_OFFSET 0x1B0ul +#define SL_WFX_FCCC_DI_ADDR ((void *) (SL_WFX_FCCC_BASE_ADDR + SL_WFX_FCCC_DI_OFFSET)) +#define SL_WFX_SECURE_LINK_MAC_KEY_LOCATION ((void *) (SL_WFX_FCCC_BASE_ADDR + 0x3D0)) +#endif +/****************************************************** + * Macros + ******************************************************/ +#define MAC_KEY_FAIL_BYTE 0XFF +#define KEY_DIGEST_SIZE 92 +#define MEMCMP_FAIL 0 +#define MPI_SET 1 +#define SUCCESS_STATUS_WIFI_SECURE_LINK_EXCHANGE 0 +#define SHA224_0 0 +#define HMAC_SIZE 92 +#define MEMSET_LEN 1 +#define LABLE_LEN 24 +#define ADDRESS_LENGTH 0 +#define CCM_STATUS_SUCCESS 0 +/****************************************************** + * Constants + ******************************************************/ + +/* Semaphore to signal wfx driver available */ +extern TaskHandle_t wfx_securelink_task; +extern SemaphoreHandle_t wfx_securelink_rx_mutex; + +/****************************************************** + * Enumerations + ******************************************************/ + +/****************************************************** + * Type Definitions + ******************************************************/ + +/****************************************************** + * Structures + ******************************************************/ + +/****************************************************** + * Function Declarations + ******************************************************/ + +static inline void reverse_bytes(uint8_t * src, uint8_t length); + +/****************************************************** + * Variable Definitions + ******************************************************/ + +#if SL_WFX_SLK_CURVE25519 +static mbedtls_ecdh_context mbedtls_host_context; +static mbedtls_ctr_drbg_context host_drbg_context; +#endif +static mbedtls_entropy_context entropy; +uint8_t temp_key_location[SL_WFX_HOST_PUB_KEY_MAC_SIZE]; +#ifdef EFM32GG11B820F2048GM64 // WGM160PX22KGA2 +static const uint8_t * const secure_link_mac_key = (uint8_t *) SL_WFX_SECURE_LINK_MAC_KEY_LOCATION; +#else +static const uint8_t secure_link_mac_key[SL_WFX_SECURE_LINK_MAC_KEY_LENGTH] = { 0x2B, 0x49, 0xFD, 0x66, 0xCB, 0x74, 0x6D, 0x6B, + 0x4F, 0xDC, 0xC3, 0x79, 0x4E, 0xC5, 0x9A, 0x86, + 0xE5, 0x48, 0x2A, 0x41, 0x22, 0x87, 0x8B, 0x12, + 0x1A, 0x7C, 0x3E, 0xEF, 0xB7, 0x04, 0x9E, 0xB3 }; +#endif +/****************************************************** + * Function Definitions + ******************************************************/ +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_get_secure_link_mac_key(uint8_t *sl_mac_key) + * @brief + * Get secure link mac key + * @param[in] sl_mac_key: + * @return returns SL_STATUS_OK + *****************************************************************************/ +sl_status_t sl_wfx_host_get_secure_link_mac_key(uint8_t * sl_mac_key) +{ + sl_status_t result = SL_STATUS_WIFI_SECURE_LINK_MAC_KEY_ERROR; + + memcpy(sl_mac_key, secure_link_mac_key, SL_WFX_SECURE_LINK_MAC_KEY_LENGTH); + + for (uint8_t index = 0; index < SL_WFX_SECURE_LINK_MAC_KEY_LENGTH; ++index) + { + // Assuming 0xFF... when not written + if (sl_mac_key[index] != MAC_KEY_FAIL_BYTE) + { + result = SL_STATUS_OK; + break; + } + } + + return result; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_compute_pub_key(sl_wfx_securelink_exchange_pub_keys_req_body_t *request, + const uint8_t *sl_mac_key) + * @brief + * compute host public key + * @param[in] request : + * @param[in] sl_mac_key : + * @return returns SL_STATUS_OK + *****************************************************************************/ +sl_status_t sl_wfx_host_compute_pub_key(sl_wfx_securelink_exchange_pub_keys_req_body_t * request, const uint8_t * sl_mac_key) +{ + sl_status_t status = SL_STATUS_OK; + +#if SL_WFX_SLK_CURVE25519 + const char identifier[] = "ecdh"; + + mbedtls_ecdh_init(&mbedtls_host_context); + mbedtls_ctr_drbg_init(&host_drbg_context); + mbedtls_entropy_init(&entropy); + status = mbedtls_ctr_drbg_seed(&host_drbg_context, mbedtls_entropy_func, &entropy, (const unsigned char *) identifier, + sizeof(identifier)); + status += mbedtls_ecp_group_load(&mbedtls_host_context.grp, MBEDTLS_ECP_DP_CURVE25519); + status += mbedtls_ecdh_gen_public(&mbedtls_host_context.grp, &mbedtls_host_context.d, &mbedtls_host_context.Q, + mbedtls_ctr_drbg_random, &host_drbg_context); + status += mbedtls_mpi_write_binary(&mbedtls_host_context.Q.X, request->host_pub_key, SL_WFX_HOST_PUB_KEY_SIZE); +#else + mbedtls_entropy_init(&entropy); + status = mbedtls_entropy_func(&entropy, request->host_pub_key, SL_WFX_HOST_PUB_KEY_SIZE); +#endif + reverse_bytes(request->host_pub_key, SL_WFX_HOST_PUB_KEY_SIZE); + SL_WFX_ERROR_CHECK(status); + + // Generate SHA512 digest of public key + status = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), sl_mac_key, SL_WFX_HOST_PUB_KEY_SIZE, + request->host_pub_key, SL_WFX_HOST_PUB_KEY_SIZE, request->host_pub_key_mac); + SL_WFX_ERROR_CHECK(status); + +error_handler: + if (status != SL_STATUS_OK) + { + return SL_STATUS_WIFI_SECURE_LINK_EXCHANGE_FAILED; + } + return status; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_verify_pub_key(sl_wfx_securelink_exchange_pub_keys_ind_t *response_packet, + const uint8_t *sl_mac_key, + uint8_t *sl_host_pub_key) + * @brief + * verify host public key + * @param[in] response_packet: + * @param[in] sl_mac_key: + * @param[in] sl_host_pub_key: + * @return returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_verify_pub_key(sl_wfx_securelink_exchange_pub_keys_ind_t * response_packet, const uint8_t * sl_mac_key, + uint8_t * sl_host_pub_key) +{ + sl_status_t status = SL_STATUS_OK; + uint8_t shared_key_digest[KEY_DIGEST_SIZE]; + + if (xSemaphoreTake(wfx_securelink_rx_mutex, portMAX_DELAY) != pdTRUE) + { + return SL_STATUS_WIFI_SECURE_LINK_EXCHANGE_FAILED; + } + + // Compute the Hash and verify the public key/hashing + status = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), sl_mac_key, SL_WFX_NCP_PUB_KEY_SIZE, + response_packet->body.ncp_pub_key, SL_WFX_NCP_PUB_KEY_SIZE, temp_key_location); + SL_WFX_ERROR_CHECK(status); + + // Calculate session key if public key/SHA512 digest matches + if (memcmp(temp_key_location, response_packet->body.ncp_pub_key_mac, SL_WFX_HOST_PUB_KEY_MAC_SIZE) != MEMCMP_FAIL) + { + status = SL_STATUS_WIFI_SECURE_LINK_EXCHANGE_FAILED; + goto error_handler; + } + +#if SL_WFX_SLK_CURVE25519 + SL_WFX_UNUSED_PARAMETER(sl_host_pub_key); + + mbedtls_mpi_lset(&mbedtls_host_context.Qp.Z, MPI_SET); + + // Read Ineo public key + reverse_bytes(response_packet->body.ncp_pub_key, SL_WFX_NCP_PUB_KEY_SIZE); + mbedtls_mpi_read_binary(&mbedtls_host_context.Qp.X, response_packet->body.ncp_pub_key, SL_WFX_NCP_PUB_KEY_SIZE); + + // Calculate shared secret + if (mbedtls_ecdh_compute_shared(&mbedtls_host_context.grp, &mbedtls_host_context.z, &mbedtls_host_context.Qp, + &mbedtls_host_context.d, mbedtls_ctr_drbg_random, + &host_drbg_context) != SUCCESS_STATUS_WIFI_SECURE_LINK_EXCHANGE) + { + status = SL_STATUS_WIFI_SECURE_LINK_EXCHANGE_FAILED; + goto error_handler; + } + + // Generate session key + mbedtls_mpi_write_binary(&mbedtls_host_context.z, temp_key_location, SL_WFX_HOST_PUB_KEY_SIZE); + reverse_bytes(temp_key_location, SL_WFX_HOST_PUB_KEY_SIZE); + mbedtls_sha256(temp_key_location, SL_WFX_HOST_PUB_KEY_SIZE, shared_key_digest, SHA224_0); +#else + uint8_t hmac_input[HMAC_SIZE] = { 0 }; + char label[LABLE_LEN] = "SecureLink!KeyDerivation"; + + memset((uint16_t *) &hmac_input[0], (uint16_t) sl_wfx_htole16(1), MEMSET_LEN); + memcpy((uint8_t *) &hmac_input[2], (uint8_t *) label, LABLE_LEN); + memcpy((uint8_t *) &hmac_input[26], sl_host_pub_key, SL_WFX_NCP_PUB_KEY_SIZE); + memcpy((uint8_t *) &hmac_input[58], (uint8_t *) response_packet->body.ncp_pub_key, SL_WFX_NCP_PUB_KEY_SIZE); + memset((uint16_t *) &hmac_input[90], (uint16_t) sl_wfx_htole16(128), 1); + + // Generate SHA256 digest of hmac_input + status = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), sl_mac_key, SL_WFX_HOST_PUB_KEY_SIZE, + (uint8_t *) hmac_input, HMAC_SIZE, shared_key_digest); +#endif + + memcpy(sl_wfx_context->secure_link_session_key, shared_key_digest, + SL_WFX_SECURE_LINK_SESSION_KEY_LENGTH); // Use the lower 16 bytes of the sha256 + sl_wfx_context->secure_link_nonce.hp_packet_count = 0; + sl_wfx_context->secure_link_nonce.rx_packet_count = 0; + sl_wfx_context->secure_link_nonce.tx_packet_count = 0; + +error_handler: + if (xSemaphoreGive(wfx_securelink_rx_mutex) != pdTRUE) + { + printf("ERROR: sl_wfx_securelink_rx_mutex. unable to post.\n"); + } + return status; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_free_crypto_context(void) + * @brief + * Free host crypto context + * @param[in] None + * @return returns SL_STATUS_OK + *****************************************************************************/ +sl_status_t sl_wfx_host_free_crypto_context(void) +{ +#if SL_WFX_SLK_CURVE25519 + mbedtls_ecdh_free(&mbedtls_host_context); + mbedtls_ctr_drbg_free(&host_drbg_context); +#endif + mbedtls_entropy_free(&entropy); + + return SL_STATUS_OK; +} + +/******************************************************************************** + * @fn sl_status_t sl_wfx_host_decode_secure_link_data(uint8_t *buffer, uint32_t length, uint8_t *session_key) + * @brief + * Decode receive data + * Length excludes size of CCM tag and secure link header + * @param[in] buffer: + * @param[in] length: + * @param[in] session_key: + * @return returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + ********************************************************************************/ +sl_status_t sl_wfx_host_decode_secure_link_data(uint8_t * buffer, uint32_t length, uint8_t * session_key) +{ + mbedtls_ccm_context ccm_context; + sl_status_t status = SL_STATUS_SECURITY_DECRYPT_ERROR; + int crypto_status; + sl_wfx_nonce_t nonce = { 0, 0, 0 }; + + if (xSemaphoreTake(wfx_securelink_rx_mutex, portMAX_DELAY) != pdTRUE) + { + return SL_STATUS_FAIL; + } + + // Nonce for decryption should have TX and HP counters 0, only use RX counter + nonce.rx_packet_count = sl_wfx_context->secure_link_nonce.rx_packet_count; + + // Init context + mbedtls_ccm_init(&ccm_context); + + // Set the crypto key + crypto_status = mbedtls_ccm_setkey(&ccm_context, MBEDTLS_CIPHER_ID_AES, session_key, SL_WFX_SECURE_LINK_SESSION_KEY_BIT_COUNT); + SL_WFX_ERROR_CHECK(crypto_status); + + // Decrypt the data + if (!mbedtls_ccm_auth_decrypt(&ccm_context, length, (uint8_t *) &nonce, SL_WFX_SECURE_LINK_NONCE_SIZE_BYTES, NULL, + ADDRESS_LENGTH, (uint8_t *) buffer, (uint8_t *) buffer, (uint8_t *) buffer + length, + SL_WFX_SECURE_LINK_CCM_TAG_SIZE)) + { + status = SL_STATUS_OK; + } + +error_handler: + mbedtls_ccm_free(&ccm_context); + if (xSemaphoreGive(wfx_securelink_rx_mutex) != pdTRUE) + { + printf("ERROR: sl_wfx_securelink_rx_mutex. unable to post.\n"); + } + return status; +} + +/********************************************************************* + * @fn sl_status_t sl_wfx_host_encode_secure_link_data(sl_wfx_generic_message_t *buffer, + uint32_t data_length, + uint8_t *session_key, + uint8_t *nonce) + * @brief + * Encode transmit data + * Length excludes size of CCM tag and secure link header + * @param[in] buffer: + * @param[in] data_length: + * @param[in] session_key: + * @param[in] nonce: + * @return returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise +*************************************************************************/ +sl_status_t sl_wfx_host_encode_secure_link_data(sl_wfx_generic_message_t * buffer, uint32_t data_length, uint8_t * session_key, + uint8_t * nonce) +{ + mbedtls_ccm_context ccm_context; + sl_status_t status = SL_STATUS_FAIL; + + mbedtls_ccm_init(&ccm_context); + if (mbedtls_ccm_setkey(&ccm_context, MBEDTLS_CIPHER_ID_AES, session_key, SL_WFX_SECURE_LINK_SESSION_KEY_BIT_COUNT) == + CCM_STATUS_SUCCESS) + { + mbedtls_ccm_encrypt_and_tag(&ccm_context, data_length, nonce, SL_WFX_SECURE_LINK_NONCE_SIZE_BYTES, NULL, ADDRESS_LENGTH, + (uint8_t *) &buffer->header.id, (uint8_t *) &buffer->header.id, + (uint8_t *) &buffer->header.id + data_length, SL_WFX_SECURE_LINK_CCM_TAG_SIZE); + status = SL_STATUS_OK; + } + + mbedtls_ccm_free(&ccm_context); + + return status; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_schedule_secure_link_renegotiation(void) + * @brief + * Called when the driver needs to schedule secure link renegotiation + * @param[in] None + * @returns Returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_schedule_secure_link_renegotiation(void) +{ + // call sl_wfx_secure_link_renegotiate_session_key() as soon as it makes sense for the host to do so + xTaskNotifyGive(wfx_securelink_task); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn static inline void reverse_bytes(uint8_t *src, uint8_t length) + * @brief + * reverse the bytes + * @param[in] src: source + * @param[in] length: + * @returns None + *****************************************************************************/ +static inline void reverse_bytes(uint8_t * src, uint8_t length) +{ + uint8_t * lo = src; + uint8_t * hi = src + length - 1; + uint8_t swap; + + while (lo < hi) + { + swap = *lo; + *lo++ = *hi; + *hi-- = swap; + } +} + +/******************************************************************************************************** + ******************************************************************************************************** + * DEPENDENCIES & AVAIL CHECK(S) + ******************************************************************************************************** + *******************************************************************************************************/ + +#endif // SL_WFX_USE_SECURE_LINK diff --git a/examples/platform/silabs/SiWx917/wf200/sl_wfx_host.h b/examples/platform/silabs/SiWx917/wf200/sl_wfx_host.h new file mode 100644 index 00000000000000..dc9bcd28524623 --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/sl_wfx_host.h @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "FreeRTOS.h" +#include "queue.h" +#include "semphr.h" +#include "sl_wfx.h" +#include "task.h" + +#ifdef __cplusplus +extern "C" { +#endif +uint8_t sl_wfx_host_get_waited_event(void); +sl_status_t wfx_soft_init(void); + +#ifdef SLEEP_ENABLED +sl_status_t sl_wfx_host_switch_to_wirq(void); +#endif +#ifdef __cplusplus +} +#endif + +#define SL_WFX_MAX_STATIONS 8 +#define SL_WFX_MAX_SCAN_RESULTS 50 + +typedef struct __attribute__((__packed__)) scan_result_list_s +{ + sl_wfx_ssid_def_t ssid_def; + uint8_t mac[SL_WFX_MAC_ADDR_SIZE]; + uint16_t channel; + sl_wfx_security_mode_bitmask_t security_mode; + uint16_t rcpi; +} scan_result_list_t; + +void sl_wfx_host_start_platform_interrupt(void); +extern SemaphoreHandle_t wfx_wakeup_sem; diff --git a/examples/platform/silabs/SiWx917/wf200/sl_wfx_securelink_task.c b/examples/platform/silabs/SiWx917/wf200/sl_wfx_securelink_task.c new file mode 100644 index 00000000000000..28ffdda2c3852f --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/sl_wfx_securelink_task.c @@ -0,0 +1,85 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef SL_WFX_USE_SECURE_LINK +#include "secure_link/sl_wfx_secure_link.h" + +#include "FreeRTOS.h" +#include "queue.h" +#include "semphr.h" +#include "task.h" +#include +#include +#include + +// Securelink Task Configurations +#define WFX_SECURELINK_TASK_PRIO 1u +#define WFX_SECURELINK_TASK_STK_SIZE 512u + +TaskHandle_t secureLinkTaskHandle; +SemaphoreHandle_t s_xSLSemaphore; +StackType_t secureLinkStack[WFX_SECURELINK_TASK_STK_SIZE]; +StaticTask_t secureLinkTaskStruct; + +StaticSemaphore_t xSlMutexBuffer; + +/********************************************************************* + * @fn static void prvSecureLinkTask(void *p_arg) + * @brief + * The task that implements the Secure Link renegotiation with WFX. + * @param[in] p_arg: + * @return None + *************************************************************************/ +static void prvSecureLinkTask(void * p_arg) +{ + sl_status_t result; + (void) p_arg; + + /* Create a mutex used for making Secure Link renegotiations atomic */ + s_xSLSemaphore = xSemaphoreCreateMutexStatic(&xSlMutexBuffer); + + for (;;) + { + /* Wait for a key renegotiation request */ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + result = sl_wfx_secure_link_renegotiate_session_key(); + if (result != SL_STATUS_OK) + { + printf("session key negotiation error %lu\n", result); + } + } +} + +/**************************************************************************** + * @fn void wfx_securelink_task_start(void) + * @brief + * Creates WFX securelink key renegotiation task. + * @param[in] None + * @return None + ******************************************************************************/ +void wfx_securelink_task_start(void) +{ + secureLinkTaskHandle = xTaskCreateStatic(prvSecureLinkTask, "secureLinkTask", WFX_SECURELINK_TASK_STK_SIZE, NULL, + WFX_SECURELINK_TASK_PRIO, secureLinkStack, &secureLinkTaskStruct); + if (secureLinkTaskHandle == NULL) + { + printf("Failed to create WFX secureLinkTask"); + } +} + +#endif diff --git a/examples/platform/silabs/SiWx917/wf200/sl_wfx_task.c b/examples/platform/silabs/SiWx917/wf200/sl_wfx_task.c new file mode 100644 index 00000000000000..8a00e454ade504 --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/sl_wfx_task.c @@ -0,0 +1,128 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "em_gpio.h" + +#include "sl_wfx.h" +#include "sl_wfx_board.h" +#include "sl_wfx_host.h" +#include "sl_wfx_task.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" + +#include "AppConfig.h" + +#define CHECK_VAL 0 +#define WFX_BUS_TASK_PRIORITY 2 +#define BUS_TASK_STACK_SIZE 1024 +static StackType_t busStack[BUS_TASK_STACK_SIZE]; +StaticTask_t busTaskStruct; +TaskHandle_t wfx_bus_task_handle; + +wfx_frame_q_item wfx_bus_tx_frame; +SemaphoreHandle_t wfxtask_tx_complete; +SemaphoreHandle_t wfxtask_mutex; + +// Flag to indicate receive frames is currently running. +static bool wfx_bus_rx_in_process = false; + +/*************************************************************************** + * @fn bool wfx_bus_is_receive_processing(void) + * @brief + * Check receive frame status + * @param[in] None + * @return returns wfx_bus_rx_in_process + ******************************************************************************/ +bool wfx_bus_is_receive_processing(void) +{ + return wfx_bus_rx_in_process; +} + +/***************************************************************************** + * @fn static sl_status_t receive_frames() + * @brief + * Receives frames from the WFX. + * @param[in] None + * @return returns result + ******************************************************************************/ +static sl_status_t receive_frames() +{ + sl_status_t result; + uint16_t control_register = 0; + wfx_bus_rx_in_process = true; + do + { + result = sl_wfx_receive_frame(&control_register); + SL_WFX_ERROR_CHECK(result); + } while ((control_register & SL_WFX_CONT_NEXT_LEN_MASK) != CHECK_VAL); + +error_handler: + wfx_bus_rx_in_process = false; + return result; +} + +/******************************************************************************** + * @fn static void wfx_bus_task(void *p_arg) + * @brief + * WFX bus communication task. + * receives frames from the Bus interface + * @param[in] p_arg: + * @return None + */ +static void wfx_bus_task(void * p_arg) +{ + SILABS_LOG("SPI: Bus Task started"); + sl_wfx_host_start_platform_interrupt(); + for (;;) + { + /*Wait for an interrupt from WFX*/ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + /*Disable the interrupt while treating frames received to avoid + *the case where the interrupt is set but there is no frame left to treat.*/ + sl_wfx_host_disable_platform_interrupt(); + + /*Receive the frame(s) pending in WFX*/ + receive_frames(); + + /*Re-enable the interrupt*/ + sl_wfx_host_enable_platform_interrupt(); + } +} + +/*************************************************************************** + * @fn void wfx_bus_start() + * @brief + * Creates WFX bus communication task. + * @param[in] None + * @return None + ******************************************************************************/ +void wfx_bus_start() +{ + wfx_bus_task_handle = + xTaskCreateStatic(wfx_bus_task, "wfxbus", BUS_TASK_STACK_SIZE, NULL, WFX_BUS_TASK_PRIORITY, busStack, &busTaskStruct); + if (wfx_bus_task_handle == NULL) + { + SILABS_LOG("*ERR*WFX BusTask"); + } +} diff --git a/examples/platform/silabs/SiWx917/wf200/sl_wfx_task.h b/examples/platform/silabs/SiWx917/wf200/sl_wfx_task.h new file mode 100644 index 00000000000000..6838b9bac14eb4 --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/sl_wfx_task.h @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "FreeRTOS.h" +#include "sl_wfx_constants.h" +#include "task.h" + +typedef struct +{ + sl_wfx_send_frame_req_t * frame; + uint32_t data_length; + sl_wfx_interface_t interface; + uint8_t priority; +} wfx_frame_q_item; + +extern wfx_frame_q_item wfxtask_tx_frame; +extern TaskHandle_t wfx_bus_task_handle; + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************** + * @fn void wfx_bus_start(void) + * @brief + * Start wfx bus communication task. + *****************************************************************************/ +void wfx_bus_start(void); + +/**************************************************************************** + * @fn bool wfx_bus_is_receive_processing(void) + * @brief + * Returns status of wfx receive frames. + *****************************************************************************/ +bool wfx_bus_is_receive_processing(void); + +#ifdef __cplusplus +} +#endif diff --git a/examples/platform/silabs/SiWx917/wf200/wf200.gni b/examples/platform/silabs/SiWx917/wf200/wf200.gni new file mode 100644 index 00000000000000..358384a81121bf --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/wf200.gni @@ -0,0 +1,30 @@ +import("//build_overrides/chip.gni") +import("//build_overrides/efr32_sdk.gni") +import("//build_overrides/pigweed.gni") + +examples_plat_dir = "${chip_root}/examples/platform/silabs/efr32" +wifi_sdk_dir = "${chip_root}/src/platform/silabs/EFR32/wifi" + +wf200_defs = [ + "SL_HEAP_SIZE=24576", + "WF200_WIFI=1", + "SL_WIFI=1", + "SL_WFX_USE_SPI", + "SL_WFX_DEBUG_MASK=0x0003", +] +softap_defs = "SL_WFX_CONFIG_SOFTAP" +wifi_scan_defs = "SL_WFX_CONFIG_SCAN" +wf200_plat_incs = [ + "${wifi_sdk_dir}/", + "${examples_plat_dir}/wf200", +] +wf200_plat_src = [ + "${wifi_sdk_dir}/dhcp_client.cpp", + "${wifi_sdk_dir}/ethernetif.cpp", + "${wifi_sdk_dir}/lwip_netif.cpp", + "${wifi_sdk_dir}/wfx_notify.cpp", + "${examples_plat_dir}/wf200/sl_wfx_task.c", + "${examples_plat_dir}/wf200/wf200_init.c", + "${examples_plat_dir}/wf200/efr_spi.c", + "${examples_plat_dir}/wf200/host_if.cpp", +] diff --git a/examples/platform/silabs/SiWx917/wf200/wf200_init.c b/examples/platform/silabs/SiWx917/wf200/wf200_init.c new file mode 100644 index 00000000000000..12973d3c8ffb67 --- /dev/null +++ b/examples/platform/silabs/SiWx917/wf200/wf200_init.c @@ -0,0 +1,543 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Includes */ + +#include "em_gpio.h" + +#include "sl_wfx.h" +#include "sl_wfx_board.h" + +// File specific to each platform, it must be created for custom boards +#include "sl_wfx_pds.h" + +#include +#include +#include +#include + +/* Firmware include */ +#include "sl_wfx_wf200_C0.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" + +#include "AppConfig.h" +#include "sl_wfx_host.h" +#include "sl_wfx_task.h" +#include "wfx_host_events.h" + +#include "sl_spidrv_instances.h" +#include "spidrv.h" + +#define SL_WFX_EVENT_MAX_SIZE 512 +#define SL_WFX_EVENT_LIST_SIZE 1 + +StaticSemaphore_t xWfxWakeupSemaBuffer; +uint8_t sWfxEventQueueBuffer[SL_WFX_EVENT_LIST_SIZE * sizeof(uint8_t)]; +StaticQueue_t sWfxEventQueueStruct; +QueueHandle_t wfx_event_Q = NULL; +SemaphoreHandle_t wfx_wakeup_sem = NULL; +SemaphoreHandle_t wfx_mutex = NULL; + +StaticSemaphore_t xWfxMutexBuffer; + +struct +{ + uint32_t wf200_firmware_download_progress; + int wf200_initialized; + uint8_t waited_event_id; + uint8_t posted_event_id; +} host_context; + +#ifdef SL_WFX_USE_SDIO +#ifdef SLEEP_ENABLED +sl_status_t sl_wfx_host_enable_sdio(void); +sl_status_t sl_wfx_host_disable_sdio(void); +#endif +#endif + +#ifdef SL_WFX_USE_SPI +#ifdef SLEEP_ENABLED +sl_status_t sl_wfx_host_enable_spi(void); +sl_status_t sl_wfx_host_disable_spi(void); +#endif +#endif + +/**************************************************************************** + * @fn sl_status_t wfx_soft_init(void) + * @brief + * WFX FMAC driver host interface initialization + * @param[in] None + * @returns Returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t wfx_soft_init(void) +{ + SILABS_LOG("WF200:Soft Init"); + if ((wfx_event_Q = xQueueCreateStatic(SL_WFX_EVENT_LIST_SIZE, sizeof(uint8_t), sWfxEventQueueBuffer, &sWfxEventQueueStruct)) == + NULL) + { + return SL_STATUS_FAIL; + } + + if ((wfx_wakeup_sem = xSemaphoreCreateBinaryStatic(&xWfxWakeupSemaBuffer)) == NULL) + { + return SL_STATUS_FAIL; + } + + if ((wfx_mutex = xSemaphoreCreateMutexStatic(&xWfxMutexBuffer)) == NULL) + { + return SL_STATUS_FAIL; + } + + return SL_STATUS_OK; +} +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_init(void) + * @brief + * Notify driver init function + * @param[in] None + * @returns Returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_init(void) +{ + SILABS_LOG("WFX: Host Init"); + host_context.wf200_firmware_download_progress = 0; + host_context.wf200_initialized = 0; + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_get_firmware_data(const uint8_t **data, uint32_t data_size) + * @brief + * Get firmware data + * @param[in] data: + * @param[in] data_size: + * @returns Returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_get_firmware_data(const uint8_t ** data, uint32_t data_size) +{ + *data = &sl_wfx_firmware[host_context.wf200_firmware_download_progress]; + host_context.wf200_firmware_download_progress += data_size; + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_get_firmware_size(uint32_t *firmware_size) + * @brief + * Get firmware size + * @param[in] firmware_size: + * @returns Returns SL_STATUS_OK if successful, + * SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_get_firmware_size(uint32_t * firmware_size) +{ + *firmware_size = sizeof(sl_wfx_firmware); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_get_pds_data(const char **pds_data, uint16_t index) + * @brief + * Get PDS data + * @param[in] pds_data: + * @param[in] index: + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_get_pds_data(const char ** pds_data, uint16_t index) +{ + *pds_data = sl_wfx_pds[index]; + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_get_pds_size(uint16_t *pds_size) + * @brief + * Get PDS size + * @param[in] pds_size: + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_get_pds_size(uint16_t * pds_size) +{ + *pds_size = SL_WFX_ARRAY_COUNT(sl_wfx_pds); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_deinit(void) + * @brief + * Deinit host interface + * @param[in] None + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_deinit(void) +{ + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_allocate_buffer(void **buffer, sl_wfx_buffer_type_t type, uint32_t buffer_size) + * @brief + * Allocate buffer (Should allocate either Ethernet - from LWIP or Control) - TODO + * @param[in] buffer: + * @param[in] type: + * @param[in] buffer_size: + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_allocate_buffer(void ** buffer, sl_wfx_buffer_type_t type, uint32_t buffer_size) +{ + if ((*buffer = pvPortMalloc(buffer_size)) == (void *) 0) + { + return SL_STATUS_FAIL; + } + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_free_buffer(void *buffer, sl_wfx_buffer_type_t type) + * @brief + * Free host buffer (CHECK LWIP buffer) + * @param[in] buffer: + * @param[in] type: + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_free_buffer(void * buffer, sl_wfx_buffer_type_t type) +{ + vPortFree(buffer); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_hold_in_reset(void) + * @brief + * Set reset pin low + * @param[in] None + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_hold_in_reset(void) +{ + GPIO_PinOutClear(SL_WFX_HOST_PINOUT_RESET_PORT, SL_WFX_HOST_PINOUT_RESET_PIN); + host_context.wf200_initialized = 0; + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_set_wake_up_pin(uint8_t state) + * @brief + * Set wakeup pin status + * @param[in] state: + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_set_wake_up_pin(uint8_t state) +{ + CORE_DECLARE_IRQ_STATE; + + CORE_ENTER_ATOMIC(); + if (state > PINOUT_CLEAR_STATUS) + { +#ifdef SLEEP_ENABLED +#ifdef SL_WFX_USE_SDIO + sl_wfx_host_enable_sdio(); +#endif +#ifdef SL_WFX_USE_SPI + sl_wfx_host_enable_spi(); +#endif +#endif + GPIO_PinOutSet(SL_WFX_HOST_PINOUT_WUP_PORT, SL_WFX_HOST_PINOUT_WUP_PIN); + } + else + { + GPIO_PinOutClear(SL_WFX_HOST_PINOUT_WUP_PORT, SL_WFX_HOST_PINOUT_WUP_PIN); +#ifdef SLEEP_ENABLED +#ifdef SL_WFX_USE_SDIO + sl_wfx_host_disable_sdio(); +#endif +#ifdef SL_WFX_USE_SPI + sl_wfx_host_disable_spi(); +#endif +#endif + } + CORE_EXIT_ATOMIC(); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_reset_chip(void) + * @brief + * reset the host chip + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_reset_chip(void) +{ + // Pull it low for at least 1 ms to issue a reset sequence + GPIO_PinOutClear(SL_WFX_HOST_PINOUT_RESET_PORT, SL_WFX_HOST_PINOUT_RESET_PIN); + + // Delay for 10ms + vTaskDelay(pdMS_TO_TICKS(10)); + + // Hold pin high to get chip out of reset + GPIO_PinOutSet(SL_WFX_HOST_PINOUT_RESET_PORT, SL_WFX_HOST_PINOUT_RESET_PIN); + + // Delay for 3ms + vTaskDelay(pdMS_TO_TICKS(3)); + + host_context.wf200_initialized = 0; + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_wait_for_wake_up(void) + * @brief + * wait for the host wake up + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_wait_for_wake_up(void) +{ + xSemaphoreTake(wfx_wakeup_sem, TICKS_TO_WAIT_0); + xSemaphoreTake(wfx_wakeup_sem, TICKS_TO_WAIT_3 / portTICK_PERIOD_MS); + + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_wait(uint32_t wait_time) + * @brief + * wait for the host + * @param[in] wait_time: + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ + +sl_status_t sl_wfx_host_wait(uint32_t wait_time) +{ + uint32_t ticks = pdMS_TO_TICKS(wait_time); + vTaskDelay(ticks ? ticks : 10); + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_setup_waited_event(uint8_t event_id) + * @brief + * Called when the driver needs to setup the waited event + * @param[in] event_id: + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_FAIL otherwise + *****************************************************************************/ + +sl_status_t sl_wfx_host_setup_waited_event(uint8_t event_id) +{ + host_context.waited_event_id = event_id; + host_context.posted_event_id = 0; + + return SL_STATUS_OK; +} + +/**************************************************************************** + * @fn uint8_t sl_wfx_host_get_waited_event(void) + * @brief + * Called when the driver get waited event + * @returns returns host_context.waited_event_id + *****************************************************************************/ + +uint8_t sl_wfx_host_get_waited_event(void) +{ + return host_context.waited_event_id; +} + +/****************************************************************************** + * @fn sl_status_t sl_wfx_host_wait_for_confirmation(uint8_t confirmation_id, uint32_t timeout, void **event_payload_out) + * @brief + * wait for the host confirmation + * @param[in] confirmation_id: + * @param[in] timeout: + * @param[in] event_payload_out: + * @returns Returns SL_STATUS_OK if successful, + * Timeout, SL_STATUS_TIMEOUT otherwise + *****************************************************************************/ + +sl_status_t sl_wfx_host_wait_for_confirmation(uint8_t confirmation_id, uint32_t timeout, void ** event_payload_out) +{ + uint8_t posted_event_id; + for (uint32_t i = 0; i < timeout; i++) + { + /* Wait for an event posted by the function sl_wfx_host_post_event() */ + if (xQueueReceive(wfx_event_Q, &posted_event_id, TICKS_TO_WAIT_1) == pdTRUE) + { + /* Once a message is received, check if it is the expected ID */ + if (confirmation_id == posted_event_id) + { + /* Pass the confirmation reply and return*/ + if (event_payload_out != NULL) + { + *event_payload_out = sl_wfx_context->event_payload_buffer; + } + return SL_STATUS_OK; + } + } + } + /* The wait for the confirmation timed out, return */ + return SL_STATUS_TIMEOUT; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_lock(void) + * @brief + * Called when the driver needs to lock its access + * @returns Returns SL_STATUS_OK if successful, + *SL_STATUS_TIMEOUT otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_lock(void) +{ + + sl_status_t status = SL_STATUS_OK; + + if (xSemaphoreTake(wfx_mutex, TICKS_TO_WAIT_500) != pdTRUE) + { + SILABS_LOG("*ERR*Wi-Fi driver mutex timo"); + status = SL_STATUS_TIMEOUT; + } + + return status; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_unlock(void) + * @brief + * Called when the driver needs to unlock its access + * @returns Returns SL_STATUS_OK + *****************************************************************************/ +sl_status_t sl_wfx_host_unlock(void) +{ + xSemaphoreGive(wfx_mutex); + + return SL_STATUS_OK; +} + +/****************************************************************************** + * @fn sl_status_t sl_wfx_host_post_event(sl_wfx_generic_message_t *event_payload) + * @brief + * Called when the driver needs to post an event + * @param[in] event_payload: + * @returns Returns status + *****************************************************************************/ +sl_status_t sl_wfx_host_post_event(sl_wfx_generic_message_t * event_payload) +{ + sl_status_t status; + + /* Forward the message to the application */ + status = sl_wfx_host_process_event(event_payload); + + if (host_context.waited_event_id == event_payload->header.id) + { + if (event_payload->header.length < SL_WFX_EVENT_MAX_SIZE) + { + /* Post the event in the queue */ + memcpy(sl_wfx_context->event_payload_buffer, (void *) event_payload, event_payload->header.length); + host_context.posted_event_id = event_payload->header.id; + xQueueOverwrite(wfx_event_Q, (void *) &event_payload->header.id); + } + } + + return status; +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_transmit_frame(void *frame, uint32_t frame_len) + * @brief + * Called when the driver needs to transmit a frame + * @param[in] frame: + * @param[in] frame_len: + * @returns returns sl_wfx_data_write(frame, frame_len) + *****************************************************************************/ +sl_status_t sl_wfx_host_transmit_frame(void * frame, uint32_t frame_len) +{ + return sl_wfx_data_write(frame, frame_len); +} + +/**************************************************************************** + * @fn sl_status_t sl_wfx_host_sleep_grant(sl_wfx_host_bus_transfer_type_t type, + sl_wfx_register_address_t address, + uint32_t length) + * @brief + * Called when the driver is considering putting the + * WFx in sleep mode + * @param[in] type: + * @param[in] address: + * @param[in] length: + * @returns SL_WIFI_SLEEP_GRANTED to let the WFx go to + *sleep, SL_WIFI_SLEEP_NOT_GRANTED otherwise + *****************************************************************************/ +sl_status_t sl_wfx_host_sleep_grant(sl_wfx_host_bus_transfer_type_t type, sl_wfx_register_address_t address, uint32_t length) +{ + (void) (type); + (void) (address); + (void) (length); + + return SL_STATUS_WIFI_SLEEP_GRANTED; +} + +#if SL_WFX_DEBUG_MASK +/**************************************************************************** + * @fn void sl_wfx_host_log(const char *str, ...) + * @brief + * Host debug output + * @param[in] str: string + * @return None + *****************************************************************************/ +void sl_wfx_host_log(const char * str, ...) +{ + va_list args; + va_start(args, str); + vprintf(str, args); + va_end(args); +} +#endif +#ifndef PW_RPC_ENABLED +/* Place holder - This is just to handle UART interrupts + * The "otThread tasks handles it. WiFi does not need it yet + * I don't care for it. I should really have the thread + * shut it off + */ +#if !CHIP_ENABLE_OPENTHREAD +/**************************************************************************** + * @fn void otSysEventSignalPending(void) + * @brief + * system event signal pending + * @param[in] None + * @return None + *****************************************************************************/ +void otSysEventSignalPending(void) +{ + // BaseType_t yieldRequired = ThreadStackMgrImpl().SignalThreadActivityPendingFromISR(); + SILABS_LOG("*ERR*UART intr - NOT Handled"); + portYIELD_FROM_ISR(pdFALSE); +} +#endif /* !CHIP_ENABLE_OPENTHREAD */ +#endif /* PW_RPC_ENABLED */ diff --git a/src/platform/silabs/SiWx917/BLEManagerImpl.cpp b/src/platform/silabs/SiWx917/BLEManagerImpl.cpp new file mode 100644 index 00000000000000..a76f26c6df6b20 --- /dev/null +++ b/src/platform/silabs/SiWx917/BLEManagerImpl.cpp @@ -0,0 +1,1093 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2019 Nest Labs, Inc. + * + * 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 Silicon Labs EFR32 platforms. + */ + +/* this file behaves like a config.h, comes first */ +#include +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +#include "sl_component_catalog.h" + +#include + +#include "FreeRTOS.h" +#include "rail.h" +extern "C" { +#include "sl_bluetooth.h" +} +#include "sl_bt_api.h" +#include "sl_bt_stack_config.h" +#include "sl_bt_stack_init.h" +#include "timers.h" +#include +#include +#include +#include +#include +#include + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING +#include +#endif + +using namespace ::chip; +using namespace ::chip::Ble; + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +namespace { + +#define CHIP_ADV_DATA_TYPE_FLAGS 0x01 +#define CHIP_ADV_DATA_TYPE_UUID 0x03 +#define CHIP_ADV_DATA_TYPE_NAME 0x09 +#define CHIP_ADV_DATA_TYPE_SERVICE_DATA 0x16 + +#define CHIP_ADV_DATA_FLAGS 0x06 + +#define CHIP_ADV_DATA 0 +#define CHIP_ADV_SCAN_RESPONSE_DATA 1 +#define CHIP_ADV_SHORT_UUID_LEN 2 + +#define MAX_RESPONSE_DATA_LEN 31 +#define MAX_ADV_DATA_LEN 31 + +// Timer Frequency used. +#define TIMER_CLK_FREQ ((uint32_t) 32768) +// Convert msec to timer ticks. +#define TIMER_MS_2_TIMERTICK(ms) ((TIMER_CLK_FREQ * ms) / 1000) +#define TIMER_S_2_TIMERTICK(s) (TIMER_CLK_FREQ * s) + +#define BLE_MAX_BUFFER_SIZE (3076) +#define BLE_MAX_ADVERTISERS (1) +#define BLE_CONFIG_MAX_PERIODIC_ADVERTISING_SYNC (0) +#define BLE_CONFIG_MAX_SOFTWARE_TIMERS (4) +#define BLE_CONFIG_MIN_TX_POWER (-30) +#define BLE_CONFIG_MAX_TX_POWER (80) +#define BLE_CONFIG_RF_PATH_GAIN_TX (0) +#define BLE_CONFIG_RF_PATH_GAIN_RX (0) + +// Default Connection parameters +#define BLE_CONFIG_MIN_INTERVAL (16) // Time = Value x 1.25 ms = 30ms +#define BLE_CONFIG_MAX_INTERVAL (80) // Time = Value x 1.25 ms = 100ms +#define BLE_CONFIG_LATENCY (0) +#define BLE_CONFIG_TIMEOUT (100) // Time = Value x 10 ms = 1s +#define BLE_CONFIG_MIN_CE_LENGTH (0) // Leave to min value +#define BLE_CONFIG_MAX_CE_LENGTH (0xFFFF) // Leave to max value + +TimerHandle_t sbleAdvTimeoutTimer; // FreeRTOS sw timer. + +const uint8_t UUID_CHIPoBLEService[] = { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0xF6, 0xFF, 0x00, 0x00 }; +const uint8_t ShortUUID_CHIPoBLEService[] = { 0xF6, 0xFF }; +const ChipBleUUID ChipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, + 0x9D, 0x11 } }; +const ChipBleUUID ChipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, + 0x9D, 0x12 } }; + +} // namespace + +BLEManagerImpl BLEManagerImpl::sInstance; + +CHIP_ERROR BLEManagerImpl::_Init() +{ + CHIP_ERROR err; + + // Initialize the CHIP BleLayer. + err = BleLayer::Init(this, this, &DeviceLayer::SystemLayer()); + SuccessOrExit(err); + + memset(mBleConnections, 0, sizeof(mBleConnections)); + memset(mIndConfId, kUnusedIndex, sizeof(mIndConfId)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; + + // Create FreeRTOS sw timer for BLE timeouts and interval change. + sbleAdvTimeoutTimer = xTimerCreate("BleAdvTimer", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = ble obj context + BleAdvTimeoutHandler // timer callback handler + ); + + mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART); + mFlags.Set(Flags::kFastAdvertisingEnabled, true); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + +exit: + return err; +} + +uint16_t BLEManagerImpl::_NumConnections(void) +{ + uint16_t numCons = 0; + for (uint16_t i = 0; i < kMaxConnections; i++) + { + if (mBleConnections[i].allocated) + { + numCons++; + } + } + + return numCons; +} + +CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (mFlags.Has(Flags::kAdvertisingEnabled) != val) + { + mFlags.Set(Flags::kAdvertisingEnabled, val); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode) +{ + switch (mode) + { + case BLEAdvertisingMode::kFastAdvertising: + mFlags.Set(Flags::kFastAdvertisingEnabled, true); + break; + case BLEAdvertisingMode::kSlowAdvertising: + mFlags.Set(Flags::kFastAdvertisingEnabled, false); + break; + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + mFlags.Set(Flags::kRestartAdvertising); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + return CHIP_NO_ERROR; +} + +CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize) +{ + if (strlen(mDeviceName) >= bufSize) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + strcpy(buf, mDeviceName); + return CHIP_NO_ERROR; +} + +CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName) +{ + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_NotSupported) + { + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; + } + if (deviceName != NULL && deviceName[0] != 0) + { + if (strlen(deviceName) >= kMaxDeviceNameLength) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + strcpy(mDeviceName, deviceName); + mFlags.Set(Flags::kDeviceNameSet); + mFlags.Set(Flags::kRestartAdvertising); + ChipLogProgress(DeviceLayer, "Setting device name to : \"%s\"", mDeviceName); + } + else + { + mDeviceName[0] = 0; + } + PlatformMgr().ScheduleWork(DriveBLEState, 0); + return CHIP_NO_ERROR; +} + +void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) +{ + switch (event->Type) + { + case DeviceEventType::kCHIPoBLESubscribe: { + ChipDeviceEvent connEstEvent; + + ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLESubscribe"); + HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX); + connEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished; + PlatformMgr().PostEventOrDie(&connEstEvent); + } + break; + + case DeviceEventType::kCHIPoBLEUnsubscribe: { + ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEUnsubscribe"); + HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX); + } + break; + + case DeviceEventType::kCHIPoBLEWriteReceived: { + ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEWriteReceived"); + HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX, + PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data)); + } + break; + + case DeviceEventType::kCHIPoBLEConnectionError: { + ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEConnectionError"); + HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason); + } + break; + + case DeviceEventType::kCHIPoBLEIndicateConfirm: { + ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEIndicateConfirm"); + HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX); + } + break; + + default: + ChipLogProgress(DeviceLayer, "_OnPlatformEvent default: event->Type = %d", event->Type); + break; + } +} + +bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogProgress(DeviceLayer, "BLEManagerImpl::SubscribeCharacteristic() not supported"); + return false; +} + +bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogProgress(DeviceLayer, "BLEManagerImpl::UnsubscribeCharacteristic() not supported"); + return false; +} + +bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + sl_status_t ret; + + ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId); + + ret = sl_bt_connection_close(conId); + err = MapBLEError(ret); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "sl_bt_connection_close() failed: %s", ErrorStr(err)); + } + + return (err == CHIP_NO_ERROR); +} + +uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const +{ + CHIPoBLEConState * conState = const_cast(this)->GetConnectionState(conId); + return (conState != NULL) ? conState->mtu : 0; +} + +bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle data) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + CHIPoBLEConState * conState = GetConnectionState(conId); + sl_status_t ret; + uint16_t cId = (UUIDsMatch(&ChipUUID_CHIPoBLEChar_RX, charId) ? gattdb_CHIPoBLEChar_Rx : gattdb_CHIPoBLEChar_Tx); + uint8_t timerHandle = GetTimerHandle(conId, true); + + VerifyOrExit(((conState != NULL) && (conState->subscribed != 0)), err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(timerHandle != kMaxConnections, err = CHIP_ERROR_NO_MEMORY); + + // start timer for light indication confirmation. Long delay for spake2 indication + sl_bt_system_set_lazy_soft_timer(TIMER_S_2_TIMERTICK(6), 0, timerHandle, true); + + ret = sl_bt_gatt_server_send_indication(conId, cId, (data->DataLength()), data->Start()); + err = MapBLEError(ret); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "BLEManagerImpl::SendIndication() failed: %s", ErrorStr(err)); + return false; + } + + return true; +} + +bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogProgress(DeviceLayer, "BLEManagerImpl::SendWriteRequest() not supported"); + return false; +} + +bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogProgress(DeviceLayer, "BLEManagerImpl::SendReadRequest() not supported"); + return false; +} + +bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, + const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogProgress(DeviceLayer, "BLEManagerImpl::SendReadResponse() not supported"); + return false; +} + +void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) +{ + // Nothing to do +} + +CHIP_ERROR BLEManagerImpl::MapBLEError(int bleErr) +{ + switch (bleErr) + { + case SL_STATUS_OK: + return CHIP_NO_ERROR; + case SL_STATUS_BT_ATT_INVALID_ATT_LENGTH: + return CHIP_ERROR_INVALID_STRING_LENGTH; + case SL_STATUS_INVALID_PARAMETER: + return CHIP_ERROR_INVALID_ARGUMENT; + case SL_STATUS_INVALID_STATE: + return CHIP_ERROR_INCORRECT_STATE; + case SL_STATUS_NOT_SUPPORTED: + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; + default: + return CHIP_ERROR(ChipError::Range::kPlatform, bleErr + CHIP_DEVICE_CONFIG_SILABS_BLE_ERROR_MIN); + } +} + +void BLEManagerImpl::DriveBLEState(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // Check if BLE stack is initialized + VerifyOrExit(mFlags.Has(Flags::kEFRBLEStackInitialized), /* */); + + // Start advertising if needed... + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kAdvertisingEnabled) && + NumConnections() < kMaxConnections) + { + // Start/re-start advertising if not already started, or if there is a pending change + // to the advertising configuration. + if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kRestartAdvertising)) + { + err = StartAdvertising(); + SuccessOrExit(err); + } + } + + // Otherwise, stop advertising if it is enabled. + else if (mFlags.Has(Flags::kAdvertising)) + { + err = StopAdvertising(); + SuccessOrExit(err); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + } +} + +CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) +{ + sl_status_t ret; + ChipBLEDeviceIdentificationInfo mDeviceIdInfo; + CHIP_ERROR err; + uint8_t responseData[MAX_RESPONSE_DATA_LEN]; + uint8_t advData[MAX_ADV_DATA_LEN]; + uint32_t index = 0; + uint32_t mDeviceNameLength = 0; + uint8_t mDeviceIdInfoLength = 0; + + VerifyOrExit((kMaxDeviceNameLength + 1) < UINT8_MAX, err = CHIP_ERROR_INVALID_ARGUMENT); + + memset(responseData, 0, MAX_RESPONSE_DATA_LEN); + memset(advData, 0, MAX_ADV_DATA_LEN); + + err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(mDeviceIdInfo); + SuccessOrExit(err); + + if (!mFlags.Has(Flags::kDeviceNameSet)) + { + uint16_t discriminator; + SuccessOrExit(err = GetCommissionableDataProvider()->GetSetupDiscriminator(discriminator)); + + snprintf(mDeviceName, sizeof(mDeviceName), "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator); + + mDeviceName[kMaxDeviceNameLength] = 0; + mDeviceNameLength = strlen(mDeviceName); + + VerifyOrExit(mDeviceNameLength < kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT); + } + + mDeviceNameLength = strlen(mDeviceName); // Device Name length + length field + VerifyOrExit(mDeviceNameLength < kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT); + + mDeviceIdInfoLength = sizeof(mDeviceIdInfo); // Servicedatalen + length+ UUID (Short) + static_assert(sizeof(mDeviceIdInfo) + CHIP_ADV_SHORT_UUID_LEN + 1 <= UINT8_MAX, "Our length won't fit in a uint8_t"); + static_assert(2 + CHIP_ADV_SHORT_UUID_LEN + sizeof(mDeviceIdInfo) + 1 <= MAX_ADV_DATA_LEN, "Our buffer is not big enough"); + + index = 0; + advData[index++] = 0x02; // length + advData[index++] = CHIP_ADV_DATA_TYPE_FLAGS; // AD type : flags + advData[index++] = CHIP_ADV_DATA_FLAGS; // AD value + advData[index++] = static_cast(mDeviceIdInfoLength + CHIP_ADV_SHORT_UUID_LEN + 1); // AD length + advData[index++] = CHIP_ADV_DATA_TYPE_SERVICE_DATA; // AD type : Service Data + advData[index++] = ShortUUID_CHIPoBLEService[0]; // AD value + advData[index++] = ShortUUID_CHIPoBLEService[1]; + memcpy(&advData[index], (void *) &mDeviceIdInfo, mDeviceIdInfoLength); // AD value + index += mDeviceIdInfoLength; + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + ReturnErrorOnFailure(EncodeAdditionalDataTlv()); +#endif + + if (0xff != advertising_set_handle) + { + sl_bt_advertiser_delete_set(advertising_set_handle); + advertising_set_handle = 0xff; + } + + ret = sl_bt_advertiser_create_set(&advertising_set_handle); + if (ret != SL_STATUS_OK) + { + err = MapBLEError(ret); + ChipLogError(DeviceLayer, "sl_bt_advertiser_create_set() failed: %s", ErrorStr(err)); + ExitNow(); + } + + ret = sl_bt_legacy_advertiser_set_data(advertising_set_handle, sl_bt_advertiser_advertising_data_packet, index, + (uint8_t *) advData); + + if (ret != SL_STATUS_OK) + { + err = MapBLEError(ret); + ChipLogError(DeviceLayer, "sl_bt_legacy_advertiser_set_data() - Advertising Data failed: %s", ErrorStr(err)); + ExitNow(); + } + + index = 0; + + responseData[index++] = CHIP_ADV_SHORT_UUID_LEN + 1; // AD length + responseData[index++] = CHIP_ADV_DATA_TYPE_UUID; // AD type : uuid + responseData[index++] = ShortUUID_CHIPoBLEService[0]; // AD value + responseData[index++] = ShortUUID_CHIPoBLEService[1]; + + responseData[index++] = static_cast(mDeviceNameLength + 1); // length + responseData[index++] = CHIP_ADV_DATA_TYPE_NAME; // AD type : name + memcpy(&responseData[index], mDeviceName, mDeviceNameLength); // AD value + index += mDeviceNameLength; + + ret = sl_bt_legacy_advertiser_set_data(advertising_set_handle, sl_bt_advertiser_scan_response_packet, index, + (uint8_t *) responseData); + + if (ret != SL_STATUS_OK) + { + err = MapBLEError(ret); + ChipLogError(DeviceLayer, "sl_bt_legacy_advertiser_set_data() - Scan Response failed: %s", ErrorStr(err)); + ExitNow(); + } + + err = MapBLEError(ret); + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::StartAdvertising(void) +{ + CHIP_ERROR err; + sl_status_t ret; + uint32_t interval_min; + uint32_t interval_max; + uint16_t numConnectionss = NumConnections(); + uint8_t connectableAdv = + (numConnectionss < kMaxConnections) ? sl_bt_advertiser_connectable_scannable : sl_bt_advertiser_scannable_non_connectable; + + // If already advertising, stop it, before changing values + if (mFlags.Has(Flags::kAdvertising)) + { + sl_bt_advertiser_stop(advertising_set_handle); + } + else + { + ChipLogDetail(DeviceLayer, "Start BLE advertissement"); + } + + const uint8_t kResolvableRandomAddrType = 2; // Private resolvable random address type + bd_addr unusedBdAddr; // We can ignore this field when setting random address. + sl_bt_advertiser_set_random_address(advertising_set_handle, kResolvableRandomAddrType, unusedBdAddr, &unusedBdAddr); + (void) unusedBdAddr; + + err = ConfigureAdvertisingData(); + SuccessOrExit(err); + + mFlags.Clear(Flags::kRestartAdvertising); + + if (mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + interval_min = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN; + interval_max = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX; + } + else + { + interval_min = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; + interval_max = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + } + + ret = sl_bt_advertiser_set_timing(advertising_set_handle, interval_min, interval_max, 0, 0); + err = MapBLEError(ret); + SuccessOrExit(err); + + sl_bt_advertiser_configure(advertising_set_handle, 1); + ret = sl_bt_legacy_advertiser_start(advertising_set_handle, connectableAdv); + + if (SL_STATUS_OK == ret) + { + if (mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + StartBleAdvTimeoutTimer(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME); + } + mFlags.Set(Flags::kAdvertising); + } + + err = MapBLEError(ret); + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::StopAdvertising(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + sl_status_t ret; + + if (mFlags.Has(Flags::kAdvertising)) + { + mFlags.Clear(Flags::kAdvertising).Clear(Flags::kRestartAdvertising); + mFlags.Set(Flags::kFastAdvertisingEnabled, true); + + ret = sl_bt_advertiser_stop(advertising_set_handle); + sl_bt_advertiser_delete_set(advertising_set_handle); + advertising_set_handle = 0xff; + err = MapBLEError(ret); + SuccessOrExit(err); + + CancelBleAdvTimeoutTimer(); + } + +exit: + return err; +} + +void BLEManagerImpl::UpdateMtu(volatile sl_bt_msg_t * evt) +{ + CHIPoBLEConState * bleConnState = GetConnectionState(evt->data.evt_gatt_mtu_exchanged.connection); + if (bleConnState != NULL) + { + // bleConnState->MTU is a 10-bit field inside a uint16_t. We're + // assigning to it from a uint16_t, and compilers warn about + // possibly not fitting. There's no way to suppress that warning + // via explicit cast; we have to disable the warning around the + // assignment. + // + // TODO: https://github.com/project-chip/connectedhomeip/issues/2569 + // tracks making this safe with a check or explaining why no check + // is needed. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" + bleConnState->mtu = evt->data.evt_gatt_mtu_exchanged.mtu; +#pragma GCC diagnostic pop + ; + } +} + +void BLEManagerImpl::HandleBootEvent(void) +{ + mFlags.Set(Flags::kEFRBLEStackInitialized); + PlatformMgr().ScheduleWork(DriveBLEState, 0); +} + +void BLEManagerImpl::HandleConnectEvent(volatile sl_bt_msg_t * evt) +{ + sl_bt_evt_connection_opened_t * conn_evt = (sl_bt_evt_connection_opened_t *) &(evt->data); + uint8_t connHandle = conn_evt->connection; + uint8_t bondingHandle = conn_evt->bonding; + + ChipLogProgress(DeviceLayer, "Connect Event for handle : %d", connHandle); + + AddConnection(connHandle, bondingHandle); + + PlatformMgr().ScheduleWork(DriveBLEState, 0); +} + +void BLEManagerImpl::HandleConnectionCloseEvent(volatile sl_bt_msg_t * evt) +{ + sl_bt_evt_connection_closed_t * conn_evt = (sl_bt_evt_connection_closed_t *) &(evt->data); + uint8_t connHandle = conn_evt->connection; + + ChipLogProgress(DeviceLayer, "Disconnect Event for handle : %d", connHandle); + + if (RemoveConnection(connHandle)) + { + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEConnectionError; + event.CHIPoBLEConnectionError.ConId = connHandle; + + switch (conn_evt->reason) + { + case SL_STATUS_BT_CTRL_REMOTE_USER_TERMINATED: + case SL_STATUS_BT_CTRL_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES: + case SL_STATUS_BT_CTRL_REMOTE_POWERING_OFF: + event.CHIPoBLEConnectionError.Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; + break; + + case SL_STATUS_BT_CTRL_CONNECTION_TERMINATED_BY_LOCAL_HOST: + event.CHIPoBLEConnectionError.Reason = BLE_ERROR_APP_CLOSED_CONNECTION; + break; + + default: + event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; + break; + } + + ChipLogProgress(DeviceLayer, "BLE GATT connection closed (con %u, reason %u)", connHandle, conn_evt->reason); + + PlatformMgr().PostEventOrDie(&event); + + // Arrange to re-enable connectable advertising in case it was disabled due to the + // maximum connection limit being reached. + mFlags.Set(Flags::kRestartAdvertising); + mFlags.Set(Flags::kFastAdvertisingEnabled); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } +} + +void BLEManagerImpl::HandleWriteEvent(volatile sl_bt_msg_t * evt) +{ + uint16_t attribute = evt->data.evt_gatt_server_user_write_request.characteristic; + + ChipLogProgress(DeviceLayer, "Char Write Req, char : %d", attribute); + + if (gattdb_CHIPoBLEChar_Rx == attribute) + { + HandleRXCharWrite(evt); + } +} + +void BLEManagerImpl::HandleTXCharCCCDWrite(volatile sl_bt_msg_t * evt) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + CHIPoBLEConState * bleConnState; + bool isIndicationEnabled = false; + ChipDeviceEvent event; + + bleConnState = GetConnectionState(evt->data.evt_gatt_server_user_write_request.connection); + VerifyOrExit(bleConnState != NULL, err = CHIP_ERROR_NO_MEMORY); + + // Determine if the client is enabling or disabling notification/indication. + isIndicationEnabled = (evt->data.evt_gatt_server_characteristic_status.client_config_flags == sl_bt_gatt_indication); + + ChipLogProgress(DeviceLayer, "HandleTXcharCCCDWrite - Config Flags value : %d", + evt->data.evt_gatt_server_characteristic_status.client_config_flags); + ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", isIndicationEnabled ? "subscribe" : "unsubscribe"); + + if (isIndicationEnabled) + { + // If indications are not already enabled for the connection... + if (!bleConnState->subscribed) + { + bleConnState->subscribed = 1; + // Post an event to the CHIP queue to process either a CHIPoBLE Subscribe or Unsubscribe based on + // whether the client is enabling or disabling indications. + { + event.Type = DeviceEventType::kCHIPoBLESubscribe; + event.CHIPoBLESubscribe.ConId = evt->data.evt_gatt_server_user_write_request.connection; + err = PlatformMgr().PostEvent(&event); + } + } + } + else + { + bleConnState->subscribed = 0; + event.Type = DeviceEventType::kCHIPoBLEUnsubscribe; + event.CHIPoBLESubscribe.ConId = evt->data.evt_gatt_server_user_write_request.connection; + err = PlatformMgr().PostEvent(&event); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err)); + } +} + +void BLEManagerImpl::HandleRXCharWrite(volatile sl_bt_msg_t * evt) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + System::PacketBufferHandle buf; + uint16_t writeLen = evt->data.evt_gatt_server_user_write_request.value.len; + uint8_t * data = (uint8_t *) evt->data.evt_gatt_server_user_write_request.value.data; + + // Copy the data to a packet buffer. + buf = System::PacketBufferHandle::NewWithData(data, writeLen, 0, 0); + VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY); + + ChipLogDetail(DeviceLayer, "Write request/command received for CHIPoBLE RX characteristic (con %u, len %u)", + evt->data.evt_gatt_server_user_write_request.connection, buf->DataLength()); + + // Post an event to the CHIP queue to deliver the data into the CHIP stack. + { + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEWriteReceived; + event.CHIPoBLEWriteReceived.ConId = evt->data.evt_gatt_server_user_write_request.connection; + event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease(); + err = PlatformMgr().PostEvent(&event); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err)); + } +} + +void BLEManagerImpl::HandleTxConfirmationEvent(BLE_CONNECTION_OBJECT conId) +{ + ChipDeviceEvent event; + uint8_t timerHandle = sInstance.GetTimerHandle(conId, false); + + ChipLogProgress(DeviceLayer, "Tx Confirmation received"); + + // stop indication confirmation timer + if (timerHandle < kMaxConnections) + { + ChipLogProgress(DeviceLayer, " stop soft timer"); + sl_bt_system_set_lazy_soft_timer(0, 0, timerHandle, false); + } + + event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm; + event.CHIPoBLEIndicateConfirm.ConId = conId; + PlatformMgr().PostEventOrDie(&event); +} + +void BLEManagerImpl::HandleSoftTimerEvent(volatile sl_bt_msg_t * evt) +{ + // BLE Manager starts soft timers with timer handles less than kMaxConnections + // If we receive a callback for unknown timer handle ignore this. + if (evt->data.evt_system_soft_timer.handle < kMaxConnections) + { + ChipLogProgress(DeviceLayer, "BLEManagerImpl::HandleSoftTimerEvent CHIPOBLE_PROTOCOL_ABORT"); + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEConnectionError; + event.CHIPoBLEConnectionError.ConId = mIndConfId[evt->data.evt_system_soft_timer.handle]; + sInstance.mIndConfId[evt->data.evt_system_soft_timer.handle] = kUnusedIndex; + event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; + PlatformMgr().PostEventOrDie(&event); + } +} + +bool BLEManagerImpl::RemoveConnection(uint8_t connectionHandle) +{ + CHIPoBLEConState * bleConnState = GetConnectionState(connectionHandle, true); + bool status = false; + + if (bleConnState != NULL) + { + memset(bleConnState, 0, sizeof(CHIPoBLEConState)); + status = true; + } + + return status; +} + +void BLEManagerImpl::AddConnection(uint8_t connectionHandle, uint8_t bondingHandle) +{ + CHIPoBLEConState * bleConnState = GetConnectionState(connectionHandle, true); + + if (bleConnState != NULL) + { + memset(bleConnState, 0, sizeof(CHIPoBLEConState)); + bleConnState->allocated = 1; + bleConnState->connectionHandle = connectionHandle; + bleConnState->bondingHandle = bondingHandle; + } +} + +BLEManagerImpl::CHIPoBLEConState * BLEManagerImpl::GetConnectionState(uint8_t connectionHandle, bool allocate) +{ + uint8_t freeIndex = kMaxConnections; + + for (uint8_t i = 0; i < kMaxConnections; i++) + { + if (mBleConnections[i].allocated == 1) + { + if (mBleConnections[i].connectionHandle == connectionHandle) + { + return &mBleConnections[i]; + } + } + + else if (i < freeIndex) + { + freeIndex = i; + } + } + + if (allocate) + { + if (freeIndex < kMaxConnections) + { + return &mBleConnections[freeIndex]; + } + + ChipLogError(DeviceLayer, "Failed to allocate CHIPoBLEConState"); + } + + return NULL; +} + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING +CHIP_ERROR BLEManagerImpl::EncodeAdditionalDataTlv() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + BitFlags additionalDataFields; + AdditionalDataPayloadGeneratorParams additionalDataPayloadParams; + +#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) + uint8_t rotatingDeviceIdUniqueId[ConfigurationManager::kRotatingDeviceIDUniqueIDLength] = {}; + MutableByteSpan rotatingDeviceIdUniqueIdSpan(rotatingDeviceIdUniqueId); + + err = DeviceLayer::GetDeviceInstanceInfoProvider()->GetRotatingDeviceIdUniqueId(rotatingDeviceIdUniqueIdSpan); + SuccessOrExit(err); + err = ConfigurationMgr().GetLifetimeCounter(additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter); + SuccessOrExit(err); + additionalDataPayloadParams.rotatingDeviceIdUniqueId = rotatingDeviceIdUniqueIdSpan; + additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId); +#endif /* CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) */ + + err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(additionalDataPayloadParams, c3AdditionalDataBufferHandle, + additionalDataFields); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data (%s)", __func__); + } + + return err; +} + +void BLEManagerImpl::HandleC3ReadRequest(volatile sl_bt_msg_t * evt) +{ + sl_bt_evt_gatt_server_user_read_request_t * readReq = + (sl_bt_evt_gatt_server_user_read_request_t *) &(evt->data.evt_gatt_server_user_read_request); + ChipLogDetail(DeviceLayer, "Read request received for CHIPoBLEChar_C3 - opcode:%d", readReq->att_opcode); + sl_status_t ret = sl_bt_gatt_server_send_user_read_response(readReq->connection, readReq->characteristic, 0, + sInstance.c3AdditionalDataBufferHandle->DataLength(), + sInstance.c3AdditionalDataBufferHandle->Start(), nullptr); + + if (ret != SL_STATUS_OK) + { + ChipLogDetail(DeviceLayer, "Failed to send read response, err:%ld", ret); + } +} +#endif // CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + +uint8_t BLEManagerImpl::GetTimerHandle(uint8_t connectionHandle, bool allocate) +{ + uint8_t freeIndex = kMaxConnections; + + for (uint8_t i = 0; i < kMaxConnections; i++) + { + if (mIndConfId[i] == connectionHandle) + { + return i; + } + else if (allocate) + { + if (i < freeIndex) + { + freeIndex = i; + } + } + } + + if (freeIndex < kMaxConnections) + { + mIndConfId[freeIndex] = connectionHandle; + } + else + { + ChipLogError(DeviceLayer, "Failed to Save Conn Handle for indication"); + } + + return freeIndex; +} + +void BLEManagerImpl::BleAdvTimeoutHandler(TimerHandle_t xTimer) +{ + if (BLEMgrImpl().mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start slow advertissment"); + BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising); + } +} + +void BLEManagerImpl::CancelBleAdvTimeoutTimer(void) +{ + if (xTimerStop(sbleAdvTimeoutTimer, 0) == pdFAIL) + { + ChipLogError(DeviceLayer, "Failed to stop BledAdv timeout timer"); + } +} + +void BLEManagerImpl::StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs) +{ + if (xTimerIsTimerActive(sbleAdvTimeoutTimer)) + { + CancelBleAdvTimeoutTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sbleAdvTimeoutTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) + { + ChipLogError(DeviceLayer, "Failed to start BledAdv timeout timer"); + } +} + +void BLEManagerImpl::DriveBLEState(intptr_t arg) +{ + sInstance.DriveBLEState(); +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +extern "C" void sl_bt_on_event(sl_bt_msg_t * evt) +{ + // As this is running in a separate thread, we need to block CHIP from operating, + // until the events are handled. + chip::DeviceLayer::PlatformMgr().LockChipStack(); + + // handle bluetooth events + switch (SL_BT_MSG_ID(evt->header)) + { + case sl_bt_evt_system_boot_id: { + ChipLogProgress(DeviceLayer, "Bluetooth stack booted: v%d.%d.%d-b%d", evt->data.evt_system_boot.major, + evt->data.evt_system_boot.minor, evt->data.evt_system_boot.patch, evt->data.evt_system_boot.build); + chip::DeviceLayer::Internal::BLEMgrImpl().HandleBootEvent(); + + RAIL_Version_t railVer; + RAIL_GetVersion(&railVer, true); + ChipLogProgress(DeviceLayer, "RAIL version:, v%d.%d.%d-b%d", railVer.major, railVer.minor, railVer.rev, railVer.build); + sl_bt_connection_set_default_parameters(BLE_CONFIG_MIN_INTERVAL, BLE_CONFIG_MAX_INTERVAL, BLE_CONFIG_LATENCY, + BLE_CONFIG_TIMEOUT, BLE_CONFIG_MIN_CE_LENGTH, BLE_CONFIG_MAX_CE_LENGTH); + } + break; + + case sl_bt_evt_connection_opened_id: { + chip::DeviceLayer::Internal::BLEMgrImpl().HandleConnectEvent(evt); + } + break; + case sl_bt_evt_connection_parameters_id: { + // ChipLogProgress(DeviceLayer, "Connection parameter ID received"); + } + break; + case sl_bt_evt_connection_phy_status_id: { + // ChipLogProgress(DeviceLayer, "PHY update procedure is completed"); + } + break; + case sl_bt_evt_connection_closed_id: { + chip::DeviceLayer::Internal::BLEMgrImpl().HandleConnectionCloseEvent(evt); + } + break; + + /* This event indicates that a remote GATT client is attempting to write a value of an + * attribute in to the local GATT database, where the attribute was defined in the GATT + * XML firmware configuration file to have type="user". */ + case sl_bt_evt_gatt_server_attribute_value_id: { + chip::DeviceLayer::Internal::BLEMgrImpl().HandleWriteEvent(evt); + } + break; + + case sl_bt_evt_gatt_mtu_exchanged_id: { + chip::DeviceLayer::Internal::BLEMgrImpl().UpdateMtu(evt); + } + break; + + // confirmation of indication received from remote GATT client + case sl_bt_evt_gatt_server_characteristic_status_id: { + sl_bt_gatt_server_characteristic_status_flag_t StatusFlags; + + StatusFlags = (sl_bt_gatt_server_characteristic_status_flag_t) evt->data.evt_gatt_server_characteristic_status.status_flags; + + if (sl_bt_gatt_server_confirmation == StatusFlags) + { + chip::DeviceLayer::Internal::BLEMgrImpl().HandleTxConfirmationEvent( + evt->data.evt_gatt_server_characteristic_status.connection); + } + else if ((evt->data.evt_gatt_server_characteristic_status.characteristic == gattdb_CHIPoBLEChar_Tx) && + (evt->data.evt_gatt_server_characteristic_status.status_flags == gatt_server_client_config)) + { + chip::DeviceLayer::Internal::BLEMgrImpl().HandleTXCharCCCDWrite(evt); + } + } + break; + + /* Software Timer event */ + case sl_bt_evt_system_soft_timer_id: { + chip::DeviceLayer::Internal::BLEMgrImpl().HandleSoftTimerEvent(evt); + } + break; + + case sl_bt_evt_gatt_server_user_read_request_id: { + ChipLogProgress(DeviceLayer, "GATT server user_read_request"); +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + if (evt->data.evt_gatt_server_user_read_request.characteristic == gattdb_CHIPoBLEChar_C3) + { + chip::DeviceLayer::Internal::BLEMgrImpl().HandleC3ReadRequest(evt); + } +#endif // CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + } + break; + + case sl_bt_evt_connection_remote_used_features_id: { + // ChipLogProgress(DeviceLayer, "link layer features supported by the remote device"); + } + break; + + default: + ChipLogProgress(DeviceLayer, "evt_UNKNOWN id = %08" PRIx32, SL_BT_MSG_ID(evt->header)); + break; + } + + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); +} + +#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/src/platform/silabs/SiWx917/BUILD.gn b/src/platform/silabs/SiWx917/BUILD.gn new file mode 100644 index 00000000000000..b67c63c486a719 --- /dev/null +++ b/src/platform/silabs/SiWx917/BUILD.gn @@ -0,0 +1,125 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") + +import("${chip_root}/src/platform/device.gni") + +import("${chip_root}/build/chip/buildconfig_header.gni") +import("${chip_root}/src/crypto/crypto.gni") + +silabs_platform_dir = "${chip_root}/src/platform/silabs" + +assert(chip_device_platform == "efr32") + +if (chip_enable_openthread) { + import("//build_overrides/openthread.gni") +} + +if (chip_crypto == "platform") { + import("//build_overrides/mbedtls.gni") +} + +static_library("EFR32") { + sources = [ + "${silabs_platform_dir}/BLEManagerImpl.h", + "${silabs_platform_dir}/BlePlatformConfig.h", + "${silabs_platform_dir}/CHIPDevicePlatformConfig.h", + "${silabs_platform_dir}/CHIPDevicePlatformEvent.h", + "${silabs_platform_dir}/CHIPMem-Platform.cpp", + "${silabs_platform_dir}/CHIPPlatformConfig.h", + "${silabs_platform_dir}/ConfigurationManagerImpl.h", + "${silabs_platform_dir}/ConnectivityManagerImpl.h", + "${silabs_platform_dir}/DiagnosticDataProviderImpl.cpp", + "${silabs_platform_dir}/DiagnosticDataProviderImpl.h", + "${silabs_platform_dir}/InetPlatformConfig.h", + "${silabs_platform_dir}/KeyValueStoreManagerImpl.h", + "${silabs_platform_dir}/Logging.cpp", + "${silabs_platform_dir}/PlatformManagerImpl.h", + "${silabs_platform_dir}/SilabsConfig.cpp", + "${silabs_platform_dir}/SilabsConfig.h", + "${silabs_platform_dir}/SystemPlatformConfig.h", + "../../FreeRTOS/SystemTimeSupport.cpp", + "../../SingletonConfigurationManager.cpp", + "BLEManagerImpl.cpp", + "ConfigurationManagerImpl.cpp", + "KeyValueStoreManagerImpl.cpp", + "PlatformManagerImpl.cpp", + ] + + if (chip_enable_ota_requestor) { + sources += [ + "OTAImageProcessorImpl.cpp", + "OTAImageProcessorImpl.h", + ] + } + + public_deps = [ "${chip_root}/src/platform:platform_base" ] + + # Add platform crypto implementation + if (chip_crypto == "platform") { + sources += [ + "CHIPCryptoPALPsaEfr32.cpp", + "Efr32OpaqueKeypair.h", + "Efr32PsaOpaqueKeypair.cpp", + "Efr32PsaOperationalKeystore.cpp", + "Efr32PsaOperationalKeystore.h", + ] + + public_deps += [ + "${chip_root}/src/crypto", + "${mbedtls_root}:mbedtls", + ] + } + + # Add pigweed KVS + deps = [ + "$dir_pw_kvs:crc16", + "$dir_pw_log", + ] + public_deps += [ + "$dir_pw_checksum", + "$dir_pw_kvs", + ] + if (chip_enable_openthread) { + public_deps += [ "${chip_root}/third_party/openthread:openthread" ] + + deps += [ "${chip_root}/third_party/openthread:openthread_cli" ] + + sources += [ + "${silabs_platform_dir}/ThreadStackManagerImpl.h", + "../../OpenThread/OpenThreadUtils.cpp", + "ConnectivityManagerImpl.cpp", + "ThreadStackManagerImpl.cpp", + ] + + if (chip_mdns == "platform") { + sources += [ "../../OpenThread/DnssdImpl.cpp" ] + deps += [ "${chip_root}/src/lib/dnssd:platform_header" ] + } + + public_configs = [ + "${chip_root}/src/lib/address_resolve:default_address_resolve_config", + ] + } + + if (chip_enable_wifi) { + sources += [ + "${silabs_platform_dir}/ConnectivityManagerImpl_WIFI.cpp", + "${silabs_platform_dir}/NetworkCommissioningWiFiDriver.cpp", + "${silabs_platform_dir}/NetworkCommissioningWiFiDriver.h", + ] + } +} diff --git a/src/platform/silabs/SiWx917/CHIPCryptoPALPsaEfr32.cpp b/src/platform/silabs/SiWx917/CHIPCryptoPALPsaEfr32.cpp new file mode 100644 index 00000000000000..13af1ae5a557b6 --- /dev/null +++ b/src/platform/silabs/SiWx917/CHIPCryptoPALPsaEfr32.cpp @@ -0,0 +1,1879 @@ +/* + * + * Copyright (c) 2020-2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * PSA Crypto API based implementation of CHIP crypto primitives + * with Silicon Labs SDK modifications + */ + +#include + +#include + +// Include version header to get configuration information +#include + +#if !defined(MBEDTLS_PSA_CRYPTO_C) +#error "This implementation needs PSA Crypto" +#endif + +#if !defined(MBEDTLS_USE_PSA_CRYPTO) +#error "This implementation requires that PSA Crypto keys can be used for CSR generation" +#endif + +#include "psa/crypto.h" + +// Go straight for the driver wrappers for speed on plaintext keys +extern "C" { +#include "psa_crypto_core.h" +#include "psa_crypto_driver_wrappers.h" +} + +// Includes needed for SPAKE2+ ECP operations +#include +#include + +// Includes needed for certificate parsing +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#include +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) +#include +#include +#include + +#if defined(MBEDTLS_ERROR_C) +#include +#endif // defined(MBEDTLS_ERROR_C) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace chip { +namespace Crypto { + +using chip::Platform::MemoryCalloc; +using chip::Platform::MemoryFree; + +#define MAX_ERROR_STR_LEN 128 +#define NUM_BYTES_IN_SHA256_HASH 32 + +// In mbedTLS 3.0.0 direct access to structure fields was replaced with using MBEDTLS_PRIVATE macro. +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) +#define CHIP_CRYPTO_PAL_PRIVATE(x) MBEDTLS_PRIVATE(x) +#else +#define CHIP_CRYPTO_PAL_PRIVATE(x) x +#endif + +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000 && MBEDTLS_VERSION_NUMBER < 0x03010000) +#define CHIP_CRYPTO_PAL_PRIVATE_X509(x) MBEDTLS_PRIVATE(x) +#else +#define CHIP_CRYPTO_PAL_PRIVATE_X509(x) x +#endif + +static void _log_mbedTLS_error(int error_code) +{ + if (error_code != 0) + { +#if defined(MBEDTLS_ERROR_C) + char error_str[MAX_ERROR_STR_LEN]; + mbedtls_strerror(error_code, error_str, sizeof(error_str)); + ChipLogError(Crypto, "mbedTLS error: %s", error_str); +#else + // Error codes defined in 16-bit negative hex numbers. Ease lookup by printing likewise + ChipLogError(Crypto, "mbedTLS error: -0x%04X", -static_cast(error_code)); +#endif + } +} + +static void _log_PSA_error(psa_status_t status) +{ + if (status != 0) + { + // Error codes defined in 16-bit negative hex numbers. Ease lookup by printing likewise + ChipLogError(Crypto, "PSA error: %ld", status); + } +} + +static bool _isValidTagLength(size_t tag_length) +{ + if (tag_length == 8 || tag_length == 12 || tag_length == 16) + { + return true; + } + return false; +} + +/** + * @brief Compare two times + * + * @param t1 First time to compare + * @param t2 Second time to compare + * @return int 0 If both times are idential to the second, -1 if t1 < t2, 1 if t1 > t2. + */ +static int timeCompare(mbedtls_x509_time * t1, mbedtls_x509_time * t2) +{ + VerifyOrReturnValue(t1->year >= t2->year, -1); + VerifyOrReturnValue(t1->year <= t2->year, 1); + // Same year + VerifyOrReturnValue(t1->mon >= t2->mon, -1); + VerifyOrReturnValue(t1->mon <= t2->mon, 1); + // Same month + VerifyOrReturnValue(t1->day >= t2->day, -1); + VerifyOrReturnValue(t1->day <= t2->day, 1); + // Same day + VerifyOrReturnValue(t1->hour >= t2->hour, -1); + VerifyOrReturnValue(t1->hour <= t2->hour, 1); + // Same hour + VerifyOrReturnValue(t1->min >= t2->min, -1); + VerifyOrReturnValue(t1->min <= t2->min, 1); + // Same minute + VerifyOrReturnValue(t1->sec >= t2->sec, -1); + VerifyOrReturnValue(t1->sec <= t2->sec, 1); + // Same second + return 0; +} + +CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, + const uint8_t * key, size_t key_length, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, + uint8_t * tag, size_t tag_length) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + size_t output_length = 0; + uint8_t * buffer = nullptr; + bool allocated_buffer = false; + + VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(key_length == kAES_CCM128_Key_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(key_length == kAES_CCM128_Key_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(CanCastTo(nonce_length), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + + // If the ciphertext and tag outputs aren't a contiguous buffer, the PSA API requires buffer copying + if (Uint8::to_uchar(ciphertext) + plaintext_length != Uint8::to_uchar(tag)) + { + buffer = (uint8_t *) MemoryCalloc(1, plaintext_length + tag_length); + allocated_buffer = true; + VerifyOrExit(buffer != nullptr, error = CHIP_ERROR_NO_MEMORY); + } + + psa_crypto_init(); + + psa_set_key_type(&attr, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attr, key_length * 8); + psa_set_key_algorithm(&attr, PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT); + + status = psa_driver_wrapper_aead_encrypt( + &attr, Uint8::to_const_uchar(key), key_length, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), + Uint8::to_const_uchar(nonce), nonce_length, Uint8::to_const_uchar(aad), aad_length, Uint8::to_const_uchar(plaintext), + plaintext_length, allocated_buffer ? buffer : ciphertext, plaintext_length + tag_length, &output_length); + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(output_length == plaintext_length + tag_length, error = CHIP_ERROR_INTERNAL); + + if (allocated_buffer) + { + memcpy(Uint8::to_uchar(ciphertext), buffer, plaintext_length); + memcpy(Uint8::to_uchar(tag), buffer + plaintext_length, tag_length); + memset(buffer, 0, plaintext_length + tag_length); + } + +exit: + if (allocated_buffer) + { + MemoryFree(buffer); + } + psa_reset_key_attributes(&attr); + return error; +} + +CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, const uint8_t * aad, size_t aad_len, + const uint8_t * tag, size_t tag_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, + size_t nonce_length, uint8_t * plaintext) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + size_t output_length = 0; + uint8_t * buffer = nullptr; + bool allocated_buffer = false; + + VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(key_length == kAES_CCM128_Key_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + + // If the ciphertext and tag outputs aren't a contiguous buffer, the PSA API requires buffer copying + if (Uint8::to_const_uchar(ciphertext) + ciphertext_len != Uint8::to_const_uchar(tag)) + { + buffer = (uint8_t *) MemoryCalloc(1, ciphertext_len + tag_length); + allocated_buffer = true; + VerifyOrExit(buffer != nullptr, error = CHIP_ERROR_NO_MEMORY); + } + + psa_crypto_init(); + + psa_set_key_type(&attr, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attr, key_length * 8); + psa_set_key_algorithm(&attr, PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DECRYPT); + + if (allocated_buffer) + { + memcpy(buffer, ciphertext, ciphertext_len); + memcpy(buffer + ciphertext_len, tag, tag_length); + } + + status = psa_driver_wrapper_aead_decrypt( + &attr, Uint8::to_const_uchar(key), key_length, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), + Uint8::to_const_uchar(nonce), nonce_length, Uint8::to_const_uchar(aad), aad_len, allocated_buffer ? buffer : ciphertext, + ciphertext_len + tag_length, plaintext, ciphertext_len, &output_length); + + if (allocated_buffer) + { + memset(buffer, 0, ciphertext_len + tag_length); + } + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(output_length == ciphertext_len, error = CHIP_ERROR_INTERNAL); +exit: + if (allocated_buffer) + { + MemoryFree(buffer); + } + + psa_reset_key_attributes(&attr); + return error; +} + +CHIP_ERROR Hash_SHA256(const uint8_t * data, const size_t data_length, uint8_t * out_buffer) +{ + size_t output_length = 0; + + psa_crypto_init(); + + const psa_status_t result = + psa_hash_compute(PSA_ALG_SHA_256, data, data_length, out_buffer, PSA_HASH_LENGTH(PSA_ALG_SHA_256), &output_length); + + VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Hash_SHA1(const uint8_t * data, const size_t data_length, uint8_t * out_buffer) +{ + size_t output_length = 0; + + psa_crypto_init(); + + const psa_status_t result = + psa_hash_compute(PSA_ALG_SHA_1, data, data_length, out_buffer, PSA_HASH_LENGTH(PSA_ALG_SHA_1), &output_length); + + VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_1), CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +static_assert(kMAX_Hash_SHA256_Context_Size >= sizeof(psa_hash_operation_t), + "kMAX_Hash_SHA256_Context_Size is too small for the size of underlying psa_hash_operation_t"); + +static inline psa_hash_operation_t * to_inner_hash_sha256_context(HashSHA256OpaqueContext * context) +{ + return SafePointerCast(context); +} + +Hash_SHA256_stream::Hash_SHA256_stream(void) +{ + psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); + const psa_hash_operation_t initial_context = PSA_HASH_OPERATION_INIT; + memcpy(context, &initial_context, sizeof(psa_hash_operation_t)); +} + +Hash_SHA256_stream::~Hash_SHA256_stream(void) +{ + psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); + psa_hash_abort(context); + Clear(); +} + +CHIP_ERROR Hash_SHA256_stream::Begin(void) +{ + psa_crypto_init(); + + psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); + *context = PSA_HASH_OPERATION_INIT; + const psa_status_t result = psa_hash_setup(context, PSA_ALG_SHA_256); + + VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Hash_SHA256_stream::AddData(const ByteSpan data) +{ + psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); + const psa_status_t result = psa_hash_update(context, Uint8::to_const_uchar(data.data()), data.size()); + + VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Hash_SHA256_stream::GetDigest(MutableByteSpan & out_buffer) +{ + CHIP_ERROR result = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + size_t output_length = 0; + psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); + + VerifyOrReturnError(out_buffer.size() >= kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL); + + // Clone the context first since calculating the digest finishes the operation + psa_hash_operation_t digest_context = PSA_HASH_OPERATION_INIT; + status = psa_hash_clone(context, &digest_context); + + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + // Calculate digest on the cloned context + status = psa_hash_finish(&digest_context, Uint8::to_uchar(out_buffer.data()), out_buffer.size(), &output_length); + + VerifyOrExit(status == PSA_SUCCESS, result = CHIP_ERROR_INTERNAL); + VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), result = CHIP_ERROR_INTERNAL); +exit: + psa_hash_abort(&digest_context); + return result; +} + +CHIP_ERROR Hash_SHA256_stream::Finish(MutableByteSpan & out_buffer) +{ + psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); + size_t output_length = 0; + + VerifyOrReturnError(out_buffer.size() >= kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL); + const psa_status_t status = psa_hash_finish(context, Uint8::to_uchar(out_buffer.data()), out_buffer.size(), &output_length); + + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +void Hash_SHA256_stream::Clear(void) +{ + psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); + psa_hash_abort(context); +} + +CHIP_ERROR HKDF_sha::HKDF_SHA256(const uint8_t * secret, const size_t secret_length, const uint8_t * salt, const size_t salt_length, + const uint8_t * info, const size_t info_length, uint8_t * out_buffer, size_t out_length) +{ + VerifyOrReturnError(secret != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(secret_length > 0, CHIP_ERROR_INVALID_ARGUMENT); + + // Salt is optional + if (salt_length > 0) + { + VerifyOrReturnError(salt != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + } + + VerifyOrReturnError(info_length > 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(info != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_length > 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; + + psa_crypto_init(); + + status = psa_key_derivation_setup(&operation, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + + if (salt_length > 0) + { + status = + psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, Uint8::to_const_uchar(salt), salt_length); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + } + + status = + psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SECRET, Uint8::to_const_uchar(secret), secret_length); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + + status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_INFO, Uint8::to_const_uchar(info), info_length); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + + status = psa_key_derivation_output_bytes(&operation, out_buffer, out_length); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); +exit: + psa_key_derivation_abort(&operation); + + return error; +} + +CHIP_ERROR HMAC_sha::HMAC_SHA256(const uint8_t * key, size_t key_length, const uint8_t * message, size_t message_length, + uint8_t * out_buffer, size_t out_length) +{ + VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(key_length > 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(message != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(message_length > 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_length >= kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; + size_t output_length = 0; + + psa_crypto_init(); + + psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attr, key_length * 8); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_HASH); + psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + + status = psa_driver_wrapper_mac_compute(&attr, Uint8::to_const_uchar(key), key_length, PSA_ALG_HMAC(PSA_ALG_SHA_256), + Uint8::to_const_uchar(message), message_length, out_buffer, out_length, &output_length); + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), error = CHIP_ERROR_INTERNAL); +exit: + psa_mac_abort(&operation); + psa_reset_key_attributes(&attr); + return error; +} + +CHIP_ERROR PBKDF2_sha256::pbkdf2_sha256(const uint8_t * password, size_t plen, const uint8_t * salt, size_t slen, + unsigned int iteration_count, uint32_t key_length, uint8_t * output) +{ + // TODO: replace inlined algorithm with usage of the PSA key derivation API once implemented + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + size_t output_length = 0; + + // Align these buffers on the native data size to speed up the XOR + static const size_t hash_size_in_native = + ((PSA_HASH_LENGTH(PSA_ALG_SHA_256) + sizeof(unsigned int) - 1) / sizeof(unsigned int)); + static_assert(hash_size_in_native * sizeof(unsigned int) >= PSA_HASH_LENGTH(PSA_ALG_SHA_256)); + + unsigned int md1_buffer[hash_size_in_native]; + unsigned int work_buffer[hash_size_in_native]; + uint8_t * md1 = (uint8_t *) md1_buffer; + uint8_t * work = (uint8_t *) work_buffer; + + size_t use_len; + unsigned char * out_p = output; + uint8_t * U1 = (uint8_t *) MemoryCalloc(1, slen + 4); + + VerifyOrExit(U1 != nullptr, error = CHIP_ERROR_NO_MEMORY); + VerifyOrExit(password != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(plen > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(salt != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(slen >= kSpake2p_Min_PBKDF_Salt_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(slen <= kSpake2p_Max_PBKDF_Salt_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(key_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(output != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + + psa_crypto_init(); + + psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attr, plen * 8); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_HASH); + psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + + // Start with initializing the salt + counter + memcpy(U1, salt, slen); + U1[slen] = 0; + U1[slen + 1] = 0; + U1[slen + 2] = 0; + U1[slen + 3] = 1; + + // Loop until we have generated the requested key length + while (key_length) + { + // U1 ends up in work + status = psa_driver_wrapper_mac_compute(&attr, password, plen, PSA_ALG_HMAC(PSA_ALG_SHA_256), U1, slen + 4, work, + PSA_HASH_LENGTH(PSA_ALG_SHA_256), &output_length); + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), error = CHIP_ERROR_INTERNAL); + + memcpy(md1, work, PSA_HASH_LENGTH(PSA_ALG_SHA_256)); + + for (size_t i = 1; i < iteration_count; i++) + { + // U2 ends up in md1 + // + + status = psa_driver_wrapper_mac_compute(&attr, password, plen, PSA_ALG_HMAC(PSA_ALG_SHA_256), md1, sizeof(md1_buffer), + md1, sizeof(md1_buffer), &output_length); + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), error = CHIP_ERROR_INTERNAL); + + // U1 xor U2 + // + for (size_t j = 0; j < hash_size_in_native; j++) + { + work_buffer[j] ^= md1_buffer[j]; + } + } + + use_len = (key_length < PSA_HASH_LENGTH(PSA_ALG_SHA_256)) ? key_length : PSA_HASH_LENGTH(PSA_ALG_SHA_256); + memcpy(out_p, work, use_len); + + key_length -= (uint32_t) use_len; + out_p += use_len; + + for (size_t i = 4; i > 0; i--) + { + if (++U1[slen + i - 1] != 0) + { + break; + } + } + } + +exit: + MemoryFree(U1); + psa_reset_key_attributes(&attr); + return error; +} + +CHIP_ERROR add_entropy_source(entropy_source fn_source, void * p_source, size_t threshold) +{ + // PSA Crypto has its own entropy and doesn't support an override mechanism + (void) fn_source; + (void) p_source; + (void) threshold; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DRBG_get_bytes(uint8_t * out_buffer, const size_t out_length) +{ + VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_length > 0, CHIP_ERROR_INVALID_ARGUMENT); + + psa_crypto_init(); + const psa_status_t result = psa_generate_random(Uint8::to_uchar(out_buffer), out_length); + VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +// CryptoRNG's definition is needed to use the mbedTLS-backed SPAKE2+ and certificate operations +static int CryptoRNG(void * ctxt, uint8_t * out_buffer, size_t out_length) +{ + return (chip::Crypto::DRBG_get_bytes(out_buffer, out_length) == CHIP_NO_ERROR) ? 0 : 1; +} + +// Mapping function is used as part of the certificate operations +mbedtls_ecp_group_id MapECPGroupId(SupportedECPKeyTypes keyType) +{ + switch (keyType) + { + case SupportedECPKeyTypes::ECP256R1: + return MBEDTLS_ECP_DP_SECP256R1; + default: + return MBEDTLS_ECP_DP_NONE; + } +} + +/******************************************************************************* + * + * WARNING: The default (base) implementation of P256Keypair is UNSAFE! + * + * Because of the way CHIPCryptoPAL has evolved, it is dictating how a base + * P256Keypair should behave. This includes: + * * Allowing using a P256 key for both ECDSA and ECDH operations + * * Needing to support copying a key through Serialize()/Deserialize() + * operations. This can't easily be done opaquely on an opaque backend + * without convoluted forms of reference tracking. + * * Not including a way to figure out whether the created key is supposed + * to be ephemeral or long-lived. + * * Needing to support ingestion of specific-format keys through + * Deserialize() (to support e.g. the example DAC provider). + * + * These conditions have lead to the base implementation of this class in this + * crypto backend being backed by a plaintext key buffer instead of opaque key + * references. Usage of the base class is strongly discouraged, and is only + * implemented to support the in-tree examples which instantiate keys of this + * base class. + * + ******************************************************************************/ + +typedef struct +{ + uint8_t privkey[32]; + size_t bitlen; +} psa_plaintext_ecp_keypair; + +static inline psa_plaintext_ecp_keypair * to_keypair(P256KeypairContext * context) +{ + return SafePointerCast(context); +} + +static inline const psa_plaintext_ecp_keypair * to_const_keypair(const P256KeypairContext * context) +{ + return SafePointerCast(context); +} + +CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + size_t output_length = 0; + const psa_plaintext_ecp_keypair * keypair = to_const_keypair(&mKeypair); + + VerifyOrExit(mInitialized, error = CHIP_ERROR_WELL_UNINITIALIZED); + VerifyOrExit((msg != nullptr) && (msg_length > 0), error = CHIP_ERROR_INVALID_ARGUMENT); + + psa_crypto_init(); + + psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attr, keypair->bitlen); + psa_set_key_algorithm(&attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE); + + // use imported key to sign a message + status = + psa_driver_wrapper_sign_message(&attr, keypair->privkey, PSA_BITS_TO_BYTES(keypair->bitlen), PSA_ALG_ECDSA(PSA_ALG_SHA_256), + msg, msg_length, out_signature.Bytes(), out_signature.Capacity(), &output_length); + + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(output_length == kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(out_signature.SetLength(output_length) == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); + +exit: + _log_PSA_error(status); + psa_reset_key_attributes(&attr); + + return error; +} + +CHIP_ERROR P256PublicKey::ECDSA_validate_msg_signature(const uint8_t * msg, const size_t msg_length, + const P256ECDSASignature & signature) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + + VerifyOrExit((msg != nullptr) && (msg_length > 0), error = CHIP_ERROR_INVALID_ARGUMENT); + + psa_crypto_init(); + + psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attr, 256); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_VERIFY_MESSAGE); + psa_set_key_algorithm(&attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + + // use imported key to verify a message + status = psa_driver_wrapper_verify_message(&attr, Uint8::to_const_uchar(*this), Length(), PSA_ALG_ECDSA(PSA_ALG_SHA_256), msg, + msg_length, signature.ConstBytes(), signature.Length()); + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INVALID_SIGNATURE); +exit: + _log_PSA_error(status); + psa_reset_key_attributes(&attr); + + return error; +} + +CHIP_ERROR P256PublicKey::ECDSA_validate_hash_signature(const uint8_t * hash, const size_t hash_length, + const P256ECDSASignature & signature) const +{ + VerifyOrReturnError(hash != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(hash_length == kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(signature.Length() == kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INVALID_ARGUMENT); + + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + + // Step 1: import public key as volatile + psa_crypto_init(); + + psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attr, 256); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + + // use imported key to verify a hash + status = psa_driver_wrapper_verify_hash(&attr, Uint8::to_const_uchar(*this), Length(), PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, + hash_length, signature.ConstBytes(), signature.Length()); + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INVALID_SIGNATURE); +exit: + _log_PSA_error(status); + psa_reset_key_attributes(&attr); + return error; +} + +CHIP_ERROR P256Keypair::ECDH_derive_secret(const P256PublicKey & remote_public_key, P256ECDHDerivedSecret & out_secret) const +{ + // Todo: replace with driver call once key derivation through the driver wrapper has been figured out + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + mbedtls_svc_key_id_t key_id = 0; + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + size_t output_length = 0; + const psa_plaintext_ecp_keypair * keypair = to_const_keypair(&mKeypair); + + VerifyOrExit(mInitialized, error = CHIP_ERROR_WELL_UNINITIALIZED); + + // Step 1: import plaintext key as volatile for ECDH + psa_crypto_init(); + + psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attr, keypair->bitlen); + psa_set_key_algorithm(&attr, PSA_ALG_ECDH); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE); + + status = psa_import_key(&attr, keypair->privkey, PSA_BITS_TO_BYTES(keypair->bitlen), &key_id); + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + + // Step 2: do key derivation + status = psa_raw_key_agreement(PSA_ALG_ECDH, key_id, Uint8::to_const_uchar(remote_public_key), remote_public_key.Length(), + Uint8::to_uchar(out_secret), + (out_secret.Length() == 0) ? out_secret.Capacity() : out_secret.Length(), &output_length); + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + SuccessOrExit(out_secret.SetLength(output_length)); + +exit: + _log_PSA_error(status); + // Step 3: destroy imported key + psa_reset_key_attributes(&attr); + if (key_id != 0) + { + psa_destroy_key(key_id); + } + return error; +} + +void ClearSecretData(uint8_t * buf, size_t len) +{ + mbedtls_platform_zeroize(buf, len); +} + +// THE BELOW IS FROM `third_party/openthread/repo/third_party/mbedtls/repo/library/constant_time.c` since +// mbedtls_ct_memcmp is not available on Linux somehow :( +int mbedtls_ct_memcmp_copy(const void * a, const void * b, size_t n) +{ + size_t i; + volatile const unsigned char * A = (volatile const unsigned char *) a; + volatile const unsigned char * B = (volatile const unsigned char *) b; + volatile unsigned char diff = 0; + + for (i = 0; i < n; i++) + { + /* Read volatile data in order before computing diff. + * This avoids IAR compiler warning: + * 'the order of volatile accesses is undefined ..' */ + unsigned char x = A[i], y = B[i]; + diff |= x ^ y; + } + + return ((int) diff); +} + +bool IsBufferContentEqualConstantTime(const void * a, const void * b, size_t n) +{ + return mbedtls_ct_memcmp_copy(a, b, n) == 0; +} + +CHIP_ERROR P256Keypair::Initialize() +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_plaintext_ecp_keypair * keypair = to_keypair(&mKeypair); + size_t output_length; + + if (mInitialized) + { + return CHIP_ERROR_INCORRECT_STATE; + } + + // Step 1: Generate a volatile new key + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + psa_crypto_init(); + + psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attr, 256); + psa_set_key_algorithm(&attr, PSA_ALG_ECDH); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT); + + status = psa_driver_wrapper_generate_key(&attr, keypair->privkey, sizeof(keypair->privkey), &output_length); + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(output_length == kP256_PrivateKey_Length, error = CHIP_ERROR_INTERNAL); + + keypair->bitlen = 256; + + // Step 2: Export the public key into the pubkey member + status = psa_driver_wrapper_export_public_key(&attr, keypair->privkey, sizeof(keypair->privkey), Uint8::to_uchar(mPublicKey), + mPublicKey.Length(), &output_length); + + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(output_length == kP256_PublicKey_Length, error = CHIP_ERROR_INTERNAL); + +exit: + _log_PSA_error(status); + if (error == CHIP_NO_ERROR) + { + mInitialized = true; + } + psa_reset_key_attributes(&attr); + + return error; +} + +CHIP_ERROR P256Keypair::Serialize(P256SerializedKeypair & output) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + const psa_plaintext_ecp_keypair * keypair = to_const_keypair(&mKeypair); + size_t len = output.Length() == 0 ? output.Capacity() : output.Length(); + Encoding::BufferWriter bbuf(output, len); + + VerifyOrExit(mInitialized, error = CHIP_ERROR_WELL_UNINITIALIZED); + + bbuf.Put(mPublicKey, mPublicKey.Length()); + + VerifyOrExit(bbuf.Available() == sizeof(keypair->privkey), error = CHIP_ERROR_INTERNAL); + + bbuf.Put(keypair->privkey, PSA_BITS_TO_BYTES(keypair->bitlen)); + VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_BUFFER_TOO_SMALL); + + output.SetLength(bbuf.Needed()); + +exit: + return error; +} + +CHIP_ERROR P256Keypair::Deserialize(P256SerializedKeypair & input) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_plaintext_ecp_keypair * keypair = to_keypair(&mKeypair); + Encoding::BufferWriter bbuf(mPublicKey, mPublicKey.Length()); + + VerifyOrExit(input.Length() == mPublicKey.Length() + kP256_PrivateKey_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + + Clear(); + + memcpy(keypair->privkey, Uint8::to_uchar(input) + mPublicKey.Length(), kP256_PrivateKey_Length); + keypair->bitlen = 256; + + bbuf.Put((const uint8_t *) input, mPublicKey.Length()); + VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_NO_MEMORY); + + mInitialized = true; + +exit: + return error; +} + +void P256Keypair::Clear() +{ + if (mInitialized) + { + psa_plaintext_ecp_keypair * keypair = to_keypair(&mKeypair); + memset(keypair, 0, sizeof(psa_plaintext_ecp_keypair)); + mInitialized = false; + } +} + +P256Keypair::~P256Keypair() +{ + Clear(); +} + +CHIP_ERROR P256Keypair::NewCertificateSigningRequest(uint8_t * out_csr, size_t & csr_length) const +{ + MutableByteSpan csr(out_csr, csr_length); + CHIP_ERROR err = GenerateCertificateSigningRequest(this, csr); + csr_length = (CHIP_NO_ERROR == err) ? csr.size() : 0; + return err; +} + +CHIP_ERROR VerifyCertificateSigningRequest(const uint8_t * csr_buf, size_t csr_length, P256PublicKey & pubkey) +{ +#if defined(MBEDTLS_X509_CSR_PARSE_C) + ReturnErrorOnFailure(VerifyCertificateSigningRequestFormat(csr_buf, csr_length)); + + // TODO: For some embedded targets, mbedTLS library doesn't have mbedtls_x509_csr_parse_der, and mbedtls_x509_csr_parse_free. + // Taking a step back, embedded targets likely will not process CSR requests. Adding this action item to reevaluate + // this if there's a need for this processing for embedded targets. + CHIP_ERROR error = CHIP_NO_ERROR; + size_t pubkey_size = 0; + + mbedtls_ecp_keypair * keypair = nullptr; + + P256ECDSASignature signature; + MutableByteSpan out_raw_sig_span(signature.Bytes(), signature.Capacity()); + + mbedtls_x509_csr csr; + mbedtls_x509_csr_init(&csr); + + int result = mbedtls_x509_csr_parse_der(&csr, csr_buf, csr_length); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + // Verify the signature algorithm and public key type + VerifyOrExit(csr.CHIP_CRYPTO_PAL_PRIVATE(sig_md) == MBEDTLS_MD_SHA256, error = CHIP_ERROR_UNSUPPORTED_SIGNATURE_TYPE); + VerifyOrExit(csr.CHIP_CRYPTO_PAL_PRIVATE(sig_pk) == MBEDTLS_PK_ECDSA, error = CHIP_ERROR_WRONG_KEY_TYPE); + + keypair = mbedtls_pk_ec(csr.CHIP_CRYPTO_PAL_PRIVATE_X509(pk)); + + // Copy the public key from the CSR + result = mbedtls_ecp_point_write_binary(&keypair->CHIP_CRYPTO_PAL_PRIVATE(grp), &keypair->CHIP_CRYPTO_PAL_PRIVATE(Q), + MBEDTLS_ECP_PF_UNCOMPRESSED, &pubkey_size, Uint8::to_uchar(pubkey), pubkey.Length()); + + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(pubkey_size == pubkey.Length(), error = CHIP_ERROR_INTERNAL); + + // Convert DER signature to raw signature + error = EcdsaAsn1SignatureToRaw(kP256_FE_Length, + ByteSpan{ csr.CHIP_CRYPTO_PAL_PRIVATE(sig).CHIP_CRYPTO_PAL_PRIVATE_X509(p), + csr.CHIP_CRYPTO_PAL_PRIVATE(sig).CHIP_CRYPTO_PAL_PRIVATE_X509(len) }, + out_raw_sig_span); + + VerifyOrExit(error == CHIP_NO_ERROR, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(out_raw_sig_span.size() == (kP256_FE_Length * 2), error = CHIP_ERROR_INTERNAL); + signature.SetLength(out_raw_sig_span.size()); + + // Verify the signature using the public key + error = pubkey.ECDSA_validate_msg_signature(csr.CHIP_CRYPTO_PAL_PRIVATE_X509(cri).CHIP_CRYPTO_PAL_PRIVATE_X509(p), + csr.CHIP_CRYPTO_PAL_PRIVATE_X509(cri).CHIP_CRYPTO_PAL_PRIVATE_X509(len), signature); + + SuccessOrExit(error); + +exit: + mbedtls_x509_csr_free(&csr); + _log_mbedTLS_error(result); + return error; +#else + ChipLogError(Crypto, "MBEDTLS_X509_CSR_PARSE_C is not enabled. CSR cannot be parsed"); + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif +} + +typedef struct Spake2p_Context +{ + mbedtls_ecp_group curve; + mbedtls_ecp_point M; + mbedtls_ecp_point N; + mbedtls_ecp_point X; + mbedtls_ecp_point Y; + mbedtls_ecp_point L; + mbedtls_ecp_point Z; + mbedtls_ecp_point V; + + mbedtls_mpi w0; + mbedtls_mpi w1; + mbedtls_mpi xy; + mbedtls_mpi tempbn; +} Spake2p_Context; + +static inline Spake2p_Context * to_inner_spake2p_context(Spake2pOpaqueContext * context) +{ + return SafePointerCast(context); +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::InitInternal(void) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + + Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); + + memset(context, 0, sizeof(Spake2p_Context)); + + mbedtls_ecp_group_init(&context->curve); + result = mbedtls_ecp_group_load(&context->curve, MBEDTLS_ECP_DP_SECP256R1); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + VerifyOrExit(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256) != nullptr, error = CHIP_ERROR_INTERNAL); + + mbedtls_ecp_point_init(&context->M); + mbedtls_ecp_point_init(&context->N); + mbedtls_ecp_point_init(&context->X); + mbedtls_ecp_point_init(&context->Y); + mbedtls_ecp_point_init(&context->L); + mbedtls_ecp_point_init(&context->V); + mbedtls_ecp_point_init(&context->Z); + M = &context->M; + N = &context->N; + X = &context->X; + Y = &context->Y; + L = &context->L; + V = &context->V; + Z = &context->Z; + + mbedtls_mpi_init(&context->w0); + mbedtls_mpi_init(&context->w1); + mbedtls_mpi_init(&context->xy); + mbedtls_mpi_init(&context->tempbn); + w0 = &context->w0; + w1 = &context->w1; + xy = &context->xy; + tempbn = &context->tempbn; + + G = &context->curve.G; + order = &context->curve.N; + + return error; + +exit: + _log_mbedTLS_error(result); + Clear(); + return error; +} + +void Spake2p_P256_SHA256_HKDF_HMAC::Clear() +{ + VerifyOrReturn(state != CHIP_SPAKE2P_STATE::PREINIT); + + Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); + + mbedtls_ecp_point_free(&context->M); + mbedtls_ecp_point_free(&context->N); + mbedtls_ecp_point_free(&context->X); + mbedtls_ecp_point_free(&context->Y); + mbedtls_ecp_point_free(&context->L); + mbedtls_ecp_point_free(&context->Z); + mbedtls_ecp_point_free(&context->V); + + mbedtls_mpi_free(&context->w0); + mbedtls_mpi_free(&context->w1); + mbedtls_mpi_free(&context->xy); + mbedtls_mpi_free(&context->tempbn); + + mbedtls_ecp_group_free(&context->curve); + + state = CHIP_SPAKE2P_STATE::PREINIT; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::Mac(const uint8_t * key, size_t key_len, const uint8_t * in, size_t in_len, + MutableByteSpan & out_span) +{ + HMAC_sha hmac; + VerifyOrReturnError(out_span.size() >= kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(hmac.HMAC_SHA256(key, key_len, in, in_len, out_span.data(), kSHA256_Hash_Length)); + out_span = out_span.SubSpan(0, kSHA256_Hash_Length); + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::MacVerify(const uint8_t * key, size_t key_len, const uint8_t * mac, size_t mac_len, + const uint8_t * in, size_t in_len) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + + uint8_t computed_mac[kSHA256_Hash_Length]; + MutableByteSpan computed_mac_span{ computed_mac }; + VerifyOrExit(mac_len == kSHA256_Hash_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + + SuccessOrExit(error = Mac(key, key_len, in, in_len, computed_mac_span)); + VerifyOrExit(computed_mac_span.size() == mac_len, error = CHIP_ERROR_INTERNAL); + + VerifyOrExit(IsBufferContentEqualConstantTime(mac, computed_mac, kSHA256_Hash_Length), error = CHIP_ERROR_INTERNAL); + +exit: + _log_mbedTLS_error(result); + return error; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::FELoad(const uint8_t * in, size_t in_len, void * fe) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + + result = mbedtls_mpi_read_binary((mbedtls_mpi *) fe, Uint8::to_const_uchar(in), in_len); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + result = mbedtls_mpi_mod_mpi((mbedtls_mpi *) fe, (mbedtls_mpi *) fe, (const mbedtls_mpi *) order); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + +exit: + _log_mbedTLS_error(result); + return error; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::FEWrite(const void * fe, uint8_t * out, size_t out_len) +{ + if (mbedtls_mpi_write_binary((const mbedtls_mpi *) fe, Uint8::to_uchar(out), out_len) != 0) + { + return CHIP_ERROR_INTERNAL; + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::FEGenerate(void * fe) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + + Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); + + result = mbedtls_ecp_gen_privkey(&context->curve, (mbedtls_mpi *) fe, CryptoRNG, nullptr); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + +exit: + _log_mbedTLS_error(result); + return error; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::FEMul(void * fer, const void * fe1, const void * fe2) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + + result = mbedtls_mpi_mul_mpi((mbedtls_mpi *) fer, (const mbedtls_mpi *) fe1, (const mbedtls_mpi *) fe2); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + result = mbedtls_mpi_mod_mpi((mbedtls_mpi *) fer, (mbedtls_mpi *) fer, (const mbedtls_mpi *) order); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + +exit: + _log_mbedTLS_error(result); + return error; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointLoad(const uint8_t * in, size_t in_len, void * R) +{ + Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); + + if (mbedtls_ecp_point_read_binary(&context->curve, (mbedtls_ecp_point *) R, Uint8::to_const_uchar(in), in_len) != 0) + { + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointWrite(const void * R, uint8_t * out, size_t out_len) +{ + memset(out, 0, out_len); + + size_t mbedtls_out_len = out_len; + + Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); + + if (mbedtls_ecp_point_write_binary(&context->curve, (const mbedtls_ecp_point *) R, MBEDTLS_ECP_PF_UNCOMPRESSED, + &mbedtls_out_len, Uint8::to_uchar(out), out_len) != 0) + { + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointMul(void * R, const void * P1, const void * fe1) +{ + Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); + + if (mbedtls_ecp_mul(&context->curve, (mbedtls_ecp_point *) R, (const mbedtls_mpi *) fe1, (const mbedtls_ecp_point *) P1, + CryptoRNG, nullptr) != 0) + { + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointAddMul(void * R, const void * P1, const void * fe1, const void * P2, + const void * fe2) +{ + Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); + + if (mbedtls_ecp_muladd(&context->curve, (mbedtls_ecp_point *) R, (const mbedtls_mpi *) fe1, (const mbedtls_ecp_point *) P1, + (const mbedtls_mpi *) fe2, (const mbedtls_ecp_point *) P2) != 0) + { + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointInvert(void * R) +{ + mbedtls_ecp_point * Rp = (mbedtls_ecp_point *) R; + Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); + + if (mbedtls_mpi_sub_mpi(&Rp->CHIP_CRYPTO_PAL_PRIVATE(Y), &context->curve.P, &Rp->CHIP_CRYPTO_PAL_PRIVATE(Y)) != 0) + { + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointCofactorMul(void * R) +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::ComputeL(uint8_t * Lout, size_t * L_len, const uint8_t * w1in, size_t w1in_len) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + + mbedtls_ecp_group curve; + mbedtls_mpi w1_bn; + mbedtls_ecp_point Ltemp; + + mbedtls_ecp_group_init(&curve); + mbedtls_mpi_init(&w1_bn); + mbedtls_ecp_point_init(&Ltemp); + + result = mbedtls_ecp_group_load(&curve, MBEDTLS_ECP_DP_SECP256R1); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + result = mbedtls_mpi_read_binary(&w1_bn, Uint8::to_const_uchar(w1in), w1in_len); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + result = mbedtls_mpi_mod_mpi(&w1_bn, &w1_bn, &curve.N); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + result = mbedtls_ecp_mul(&curve, &Ltemp, &w1_bn, &curve.G, CryptoRNG, nullptr); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + memset(Lout, 0, *L_len); + + result = mbedtls_ecp_point_write_binary(&curve, &Ltemp, MBEDTLS_ECP_PF_UNCOMPRESSED, L_len, Uint8::to_uchar(Lout), *L_len); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + +exit: + _log_mbedTLS_error(result); + mbedtls_ecp_point_free(&Ltemp); + mbedtls_mpi_free(&w1_bn); + mbedtls_ecp_group_free(&curve); + + return error; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointIsValid(void * R) +{ + Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); + + if (mbedtls_ecp_check_pubkey(&context->curve, (mbedtls_ecp_point *) R) != 0) + { + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +constexpr uint8_t sOID_AttributeType_CommonName[] = { 0x55, 0x04, 0x03 }; +constexpr uint8_t sOID_AttributeType_MatterVendorId[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x02, 0x01 }; +constexpr uint8_t sOID_AttributeType_MatterProductId[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x02, 0x02 }; +constexpr uint8_t sOID_SigAlgo_ECDSAWithSHA256[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 }; +constexpr uint8_t sOID_Extension_BasicConstraints[] = { 0x55, 0x1D, 0x13 }; +constexpr uint8_t sOID_Extension_KeyUsage[] = { 0x55, 0x1D, 0x0F }; +constexpr uint8_t sOID_Extension_SubjectKeyIdentifier[] = { 0x55, 0x1D, 0x0E }; +constexpr uint8_t sOID_Extension_AuthorityKeyIdentifier[] = { 0x55, 0x1D, 0x23 }; + +/** + * Compares an mbedtls_asn1_buf structure (oidBuf) to a reference OID represented as uint8_t array (oid). + */ +#define OID_CMP(oid, oidBuf) \ + ((MBEDTLS_ASN1_OID == (oidBuf).CHIP_CRYPTO_PAL_PRIVATE_X509(tag)) && \ + (sizeof(oid) == (oidBuf).CHIP_CRYPTO_PAL_PRIVATE_X509(len)) && \ + (memcmp((oid), (oidBuf).CHIP_CRYPTO_PAL_PRIVATE_X509(p), (oidBuf).CHIP_CRYPTO_PAL_PRIVATE_X509(len)) == 0)) + +CHIP_ERROR VerifyAttestationCertificateFormat(const ByteSpan & cert, AttestationCertType certType) +{ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + mbedtls_x509_crt mbed_cert; + unsigned char * p = nullptr; + const unsigned char * end = nullptr; + size_t len = 0; + bool extBasicPresent = false; + bool extKeyUsagePresent = false; + + VerifyOrReturnError(!cert.empty(), CHIP_ERROR_INVALID_ARGUMENT); + + mbedtls_x509_crt_init(&mbed_cert); + + result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(cert.data()), cert.size()); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + // "version" value is 1 higher than the actual encoded value. + VerifyOrExit(mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(version) - 1 == 2, error = CHIP_ERROR_INTERNAL); + + // Verify signature algorithms is ECDSA with SHA256. + VerifyOrExit(OID_CMP(sOID_SigAlgo_ECDSAWithSHA256, mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(sig_oid)), + error = CHIP_ERROR_INTERNAL); + + // Verify public key presence and format. + { + Crypto::P256PublicKey pubkey; + SuccessOrExit(error = ExtractPubkeyFromX509Cert(cert, pubkey)); + } + + p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + end = p + mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + while (p < end) + { + mbedtls_x509_buf extOID = { 0, 0, nullptr }; + int extCritical = 0; + + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + /* Get extension ID */ + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + extOID.CHIP_CRYPTO_PAL_PRIVATE_X509(tag) = MBEDTLS_ASN1_OID; + extOID.CHIP_CRYPTO_PAL_PRIVATE_X509(len) = len; + extOID.CHIP_CRYPTO_PAL_PRIVATE_X509(p) = p; + p += len; + + /* Get optional critical */ + result = mbedtls_asn1_get_bool(&p, end, &extCritical); + VerifyOrExit(result == 0 || result == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG, error = CHIP_ERROR_INTERNAL); + + /* Data should be octet string type */ + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + if (OID_CMP(sOID_Extension_BasicConstraints, extOID)) + { + int isCA = 0; + int pathLen = -1; + unsigned char * seqStart = p; + + VerifyOrExit(extCritical, error = CHIP_ERROR_INTERNAL); + extBasicPresent = true; + + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + if (len > 0) + { + result = mbedtls_asn1_get_bool(&p, end, &isCA); + VerifyOrExit(result == 0 || result == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG, error = CHIP_ERROR_INTERNAL); + + if (p != seqStart + len) + { + result = mbedtls_asn1_get_int(&p, end, &pathLen); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + } + } + + if (certType == AttestationCertType::kDAC) + { + VerifyOrExit(!isCA && pathLen == -1, error = CHIP_ERROR_INTERNAL); + } + else if (certType == AttestationCertType::kPAI) + { + VerifyOrExit(isCA && pathLen == 0, error = CHIP_ERROR_INTERNAL); + } + else + { + VerifyOrExit(isCA && (pathLen == -1 || pathLen == 0 || pathLen == 1), error = CHIP_ERROR_INTERNAL); + } + } + else if (OID_CMP(sOID_Extension_KeyUsage, extOID)) + { + mbedtls_x509_bitstring bs = { 0, 0, nullptr }; + unsigned int keyUsage = 0; + + VerifyOrExit(extCritical, error = CHIP_ERROR_INTERNAL); + extKeyUsagePresent = true; + + result = mbedtls_asn1_get_bitstring(&p, p + len, &bs); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + for (size_t i = 0; i < bs.CHIP_CRYPTO_PAL_PRIVATE_X509(len) && i < sizeof(unsigned int); i++) + { + keyUsage |= static_cast(bs.CHIP_CRYPTO_PAL_PRIVATE_X509(p)[i]) << (8 * i); + } + + if (certType == AttestationCertType::kDAC) + { + // SHALL only have the digitalSignature bit set. + VerifyOrExit(keyUsage == MBEDTLS_X509_KU_DIGITAL_SIGNATURE, error = CHIP_ERROR_INTERNAL); + } + else + { + bool keyCertSignFlag = keyUsage & MBEDTLS_X509_KU_KEY_CERT_SIGN; + bool crlSignFlag = keyUsage & MBEDTLS_X509_KU_CRL_SIGN; + bool otherFlags = + keyUsage & ~(MBEDTLS_X509_KU_CRL_SIGN | MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_DIGITAL_SIGNATURE); + VerifyOrExit(keyCertSignFlag && crlSignFlag && !otherFlags, error = CHIP_ERROR_INTERNAL); + } + } + else + { + p += len; + } + } + + // Verify basic and key usage extensions are present. + VerifyOrExit(extBasicPresent && extKeyUsagePresent, error = CHIP_ERROR_INTERNAL); + + // Verify that SKID and AKID extensions are present. + { + uint8_t kidBuf[kSubjectKeyIdentifierLength]; + MutableByteSpan kid(kidBuf); + SuccessOrExit(error = ExtractSKIDFromX509Cert(cert, kid)); + if (certType == AttestationCertType::kDAC || certType == AttestationCertType::kPAI) + { + // Mandatory extension for DAC and PAI certs. + SuccessOrExit(error = ExtractAKIDFromX509Cert(cert, kid)); + } + } + +exit: + _log_mbedTLS_error(result); + mbedtls_x509_crt_free(&mbed_cert); + +#else + (void) cert; + (void) certType; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + + return error; +} + +CHIP_ERROR ValidateCertificateChain(const uint8_t * rootCertificate, size_t rootCertificateLen, const uint8_t * caCertificate, + size_t caCertificateLen, const uint8_t * leafCertificate, size_t leafCertificateLen, + CertificateChainValidationResult & result) +{ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + CHIP_ERROR error = CHIP_NO_ERROR; + mbedtls_x509_crt certChain; + mbedtls_x509_crt rootCert; + mbedtls_x509_time leaf_valid_from; + mbedtls_x509_crt * cert = NULL; + int mbedResult; + uint32_t flags; + int compare_from = 0; + int compare_until = 0; + + result = CertificateChainValidationResult::kInternalFrameworkError; + + VerifyOrReturnError(rootCertificate != nullptr && rootCertificateLen != 0, + (result = CertificateChainValidationResult::kRootArgumentInvalid, CHIP_ERROR_INVALID_ARGUMENT)); + VerifyOrReturnError(leafCertificate != nullptr && leafCertificateLen != 0, + (result = CertificateChainValidationResult::kLeafArgumentInvalid, CHIP_ERROR_INVALID_ARGUMENT)); + + mbedtls_x509_crt_init(&certChain); + mbedtls_x509_crt_init(&rootCert); + + /* Start of chain */ + mbedResult = mbedtls_x509_crt_parse(&certChain, Uint8::to_const_uchar(leafCertificate), leafCertificateLen); + VerifyOrExit(mbedResult == 0, (result = CertificateChainValidationResult::kLeafFormatInvalid, error = CHIP_ERROR_INTERNAL)); + leaf_valid_from = certChain.valid_from; + + /* Add the intermediate to the chain, if present */ + if (caCertificate != nullptr && caCertificateLen > 0) + { + mbedResult = mbedtls_x509_crt_parse(&certChain, Uint8::to_const_uchar(caCertificate), caCertificateLen); + VerifyOrExit(mbedResult == 0, (result = CertificateChainValidationResult::kICAFormatInvalid, error = CHIP_ERROR_INTERNAL)); + } + + /* Parse the root cert */ + mbedResult = mbedtls_x509_crt_parse(&rootCert, Uint8::to_const_uchar(rootCertificate), rootCertificateLen); + VerifyOrExit(mbedResult == 0, (result = CertificateChainValidationResult::kRootFormatInvalid, error = CHIP_ERROR_INTERNAL)); + + /* Validates that intermediate and root certificates are valid at the time of the leaf certificate's start time. */ + compare_from = timeCompare(&leaf_valid_from, &rootCert.valid_from); + compare_until = timeCompare(&leaf_valid_from, &rootCert.valid_to); + VerifyOrExit((compare_from >= 0) && (compare_until <= 0), + (result = CertificateChainValidationResult::kChainInvalid, error = CHIP_ERROR_CERT_NOT_TRUSTED)); + cert = certChain.next; + while (cert) + { + compare_from = timeCompare(&leaf_valid_from, &cert->valid_from); + compare_until = timeCompare(&leaf_valid_from, &cert->valid_to); + VerifyOrExit((compare_from >= 0) && (compare_until <= 0), + (result = CertificateChainValidationResult::kChainInvalid, error = CHIP_ERROR_CERT_NOT_TRUSTED)); + cert = cert->next; + } + + /* Verify the chain against the root */ + mbedResult = mbedtls_x509_crt_verify(&certChain, &rootCert, NULL, NULL, &flags, NULL, NULL); + + switch (mbedResult) + { + case 0: + VerifyOrExit(flags == 0, (result = CertificateChainValidationResult::kInternalFrameworkError, error = CHIP_ERROR_INTERNAL)); + result = CertificateChainValidationResult::kSuccess; + break; + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + result = CertificateChainValidationResult::kChainInvalid; + error = CHIP_ERROR_CERT_NOT_TRUSTED; + break; + default: + SuccessOrExit((result = CertificateChainValidationResult::kInternalFrameworkError, error = CHIP_ERROR_INTERNAL)); + } + +exit: + _log_mbedTLS_error(mbedResult); + mbedtls_x509_crt_free(&certChain); + mbedtls_x509_crt_free(&rootCert); + +#else + (void) rootCertificate; + (void) rootCertificateLen; + (void) caCertificate; + (void) caCertificateLen; + (void) leafCertificate; + (void) leafCertificateLen; + (void) result; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + + return error; +} + +inline bool IsTimeGreaterThanEqual(const mbedtls_x509_time * const timeA, const mbedtls_x509_time * const timeB) +{ + + // checks if two values are different and if yes, then returns first > second. +#define RETURN_STRICTLY_GREATER_IF_DIFFERENT(component) \ + { \ + auto valueA = timeA->CHIP_CRYPTO_PAL_PRIVATE_X509(component); \ + auto valueB = timeB->CHIP_CRYPTO_PAL_PRIVATE_X509(component); \ + \ + if (valueA != valueB) \ + { \ + return valueA > valueB; \ + } \ + } + + RETURN_STRICTLY_GREATER_IF_DIFFERENT(year); + RETURN_STRICTLY_GREATER_IF_DIFFERENT(mon); + RETURN_STRICTLY_GREATER_IF_DIFFERENT(day); + RETURN_STRICTLY_GREATER_IF_DIFFERENT(hour); + RETURN_STRICTLY_GREATER_IF_DIFFERENT(min); + RETURN_STRICTLY_GREATER_IF_DIFFERENT(sec); + + // all above are equal + return true; +} + +CHIP_ERROR IsCertificateValidAtIssuance(const ByteSpan & referenceCertificate, const ByteSpan & toBeEvaluatedCertificate) +{ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + CHIP_ERROR error = CHIP_NO_ERROR; + mbedtls_x509_crt mbedReferenceCertificate; + mbedtls_x509_crt mbedToBeEvaluatedCertificate; + mbedtls_x509_time refNotBeforeTime; + mbedtls_x509_time tbeNotBeforeTime; + mbedtls_x509_time tbeNotAfterTime; + int result; + + VerifyOrReturnError(!referenceCertificate.empty() && !toBeEvaluatedCertificate.empty(), CHIP_ERROR_INVALID_ARGUMENT); + + mbedtls_x509_crt_init(&mbedReferenceCertificate); + mbedtls_x509_crt_init(&mbedToBeEvaluatedCertificate); + + result = mbedtls_x509_crt_parse(&mbedReferenceCertificate, Uint8::to_const_uchar(referenceCertificate.data()), + referenceCertificate.size()); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + result = mbedtls_x509_crt_parse(&mbedToBeEvaluatedCertificate, Uint8::to_const_uchar(toBeEvaluatedCertificate.data()), + toBeEvaluatedCertificate.size()); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + refNotBeforeTime = mbedReferenceCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(valid_from); + tbeNotBeforeTime = mbedToBeEvaluatedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(valid_from); + tbeNotAfterTime = mbedToBeEvaluatedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(valid_to); + + // check if referenceCertificate is issued at or after tbeCertificate's notBefore timestamp + VerifyOrExit(IsTimeGreaterThanEqual(&refNotBeforeTime, &tbeNotBeforeTime), error = CHIP_ERROR_CERT_EXPIRED); + + // check if referenceCertificate is issued at or before tbeCertificate's notAfter timestamp + VerifyOrExit(IsTimeGreaterThanEqual(&tbeNotAfterTime, &refNotBeforeTime), error = CHIP_ERROR_CERT_EXPIRED); + +exit: + _log_mbedTLS_error(result); + mbedtls_x509_crt_free(&mbedReferenceCertificate); + mbedtls_x509_crt_free(&mbedToBeEvaluatedCertificate); + +#else + (void) referenceCertificate; + (void) toBeEvaluatedCertificate; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + + return error; +} + +CHIP_ERROR IsCertificateValidAtCurrentTime(const ByteSpan & certificate) +{ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + CHIP_ERROR error = CHIP_NO_ERROR; + mbedtls_x509_crt mbedCertificate; + int result; + + VerifyOrReturnError(!certificate.empty(), CHIP_ERROR_INVALID_ARGUMENT); + + mbedtls_x509_crt_init(&mbedCertificate); + + result = mbedtls_x509_crt_parse(&mbedCertificate, Uint8::to_const_uchar(certificate.data()), certificate.size()); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + // check if certificate's notBefore timestamp is earlier than or equal to current time. + result = mbedtls_x509_time_is_past(&mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(valid_from)); + VerifyOrExit(result == 1, error = CHIP_ERROR_CERT_EXPIRED); + + // check if certificate's notAfter timestamp is later than current time. + result = mbedtls_x509_time_is_future(&mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(valid_to)); + VerifyOrExit(result == 1, error = CHIP_ERROR_CERT_EXPIRED); + +exit: + _log_mbedTLS_error(result); + mbedtls_x509_crt_free(&mbedCertificate); + +#else + (void) certificate; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + + return error; +} + +CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256PublicKey & pubkey) +{ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + CHIP_ERROR error = CHIP_NO_ERROR; + mbedtls_x509_crt mbed_cert; + mbedtls_ecp_keypair * keypair = nullptr; + size_t pubkey_size = 0; + + mbedtls_x509_crt_init(&mbed_cert); + + int result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size()); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + VerifyOrExit(mbedtls_pk_get_type(&(mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(pk))) == MBEDTLS_PK_ECKEY, + error = CHIP_ERROR_INVALID_ARGUMENT); + + keypair = mbedtls_pk_ec(mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(pk)); + VerifyOrExit(keypair->CHIP_CRYPTO_PAL_PRIVATE(grp).id == MapECPGroupId(pubkey.Type()), error = CHIP_ERROR_INVALID_ARGUMENT); + // Copy the public key from the cert in raw point format + result = + mbedtls_ecp_point_write_binary(&keypair->CHIP_CRYPTO_PAL_PRIVATE(grp), &keypair->CHIP_CRYPTO_PAL_PRIVATE(Q), + MBEDTLS_ECP_PF_UNCOMPRESSED, &pubkey_size, Uint8::to_uchar(pubkey.Bytes()), pubkey.Length()); + + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(pubkey_size == pubkey.Length(), error = CHIP_ERROR_INTERNAL); + +exit: + _log_mbedTLS_error(result); + mbedtls_x509_crt_free(&mbed_cert); + +#else + (void) certificate; + (void) pubkey; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + + return error; +} + +namespace { + +CHIP_ERROR ExtractKIDFromX509Cert(bool extractSKID, const ByteSpan & certificate, MutableByteSpan & kid) +{ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + CHIP_ERROR error = CHIP_ERROR_NOT_FOUND; + mbedtls_x509_crt mbed_cert; + unsigned char * p = nullptr; + const unsigned char * end = nullptr; + size_t len = 0; + + mbedtls_x509_crt_init(&mbed_cert); + + int result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size()); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + // TODO: The mbedTLS team is working on supporting SKID and AKID extensions processing. + // Once it is supported, this code should be updated. + + p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + end = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(p) + + mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); + + while (p < end) + { + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); + VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); + + mbedtls_x509_buf extOID = { MBEDTLS_ASN1_OID, len, p }; + bool extractCurrentExtSKID = extractSKID && OID_CMP(sOID_Extension_SubjectKeyIdentifier, extOID); + bool extractCurrentExtAKID = !extractSKID && OID_CMP(sOID_Extension_AuthorityKeyIdentifier, extOID); + p += len; + + int is_critical = 0; + result = mbedtls_asn1_get_bool(&p, end, &is_critical); + VerifyOrExit(result == 0 || result == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG, error = CHIP_ERROR_WRONG_CERT_TYPE); + + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); + VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); + + if (extractCurrentExtSKID || extractCurrentExtAKID) + { + if (extractCurrentExtSKID) + { + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); + VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); + } + else + { + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); + result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC); + VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); + // Other optional fields, authorityCertIssuer and authorityCertSerialNumber, + // will be skipped if present. + } + VerifyOrExit(len == kSubjectKeyIdentifierLength, error = CHIP_ERROR_WRONG_CERT_TYPE); + VerifyOrExit(len <= kid.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(kid.data(), p, len); + if (kid.size() > len) + { + kid.reduce_size(len); + } + ExitNow(error = CHIP_NO_ERROR); + break; + } + p += len; + } + +exit: + _log_mbedTLS_error(result); + mbedtls_x509_crt_free(&mbed_cert); + +#else + (void) certificate; + (void) kid; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + + return error; +} + +} // namespace + +CHIP_ERROR ExtractSKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan & skid) +{ + return ExtractKIDFromX509Cert(true, certificate, skid); +} + +CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan & akid) +{ + return ExtractKIDFromX509Cert(false, certificate, akid); +} + +CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCertVidPid & vidpid) +{ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + CHIP_ERROR error = CHIP_NO_ERROR; + mbedtls_x509_crt mbed_cert; + mbedtls_asn1_named_data * dnIterator = nullptr; + AttestationCertVidPid vidpidFromCN; + + mbedtls_x509_crt_init(&mbed_cert); + + int result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size()); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + for (dnIterator = &mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(subject); dnIterator != nullptr; + dnIterator = dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(next)) + { + DNAttrType attrType = DNAttrType::kUnspecified; + if (OID_CMP(sOID_AttributeType_CommonName, dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(oid))) + { + attrType = DNAttrType::kCommonName; + } + else if (OID_CMP(sOID_AttributeType_MatterVendorId, dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(oid))) + { + attrType = DNAttrType::kMatterVID; + } + else if (OID_CMP(sOID_AttributeType_MatterProductId, dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(oid))) + { + attrType = DNAttrType::kMatterPID; + } + + size_t val_len = dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(val).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + uint8_t * val_p = dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(val).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + error = ExtractVIDPIDFromAttributeString(attrType, ByteSpan(val_p, val_len), vidpid, vidpidFromCN); + SuccessOrExit(error); + } + + // If Matter Attributes were not found use values extracted from the CN Attribute, + // which might be uninitialized as well. + if (!vidpid.Initialized()) + { + vidpid = vidpidFromCN; + } + +exit: + _log_mbedTLS_error(result); + mbedtls_x509_crt_free(&mbed_cert); + +#else + (void) certificate; + (void) vidpid; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + + return error; +} + +} // namespace Crypto +} // namespace chip diff --git a/src/platform/silabs/SiWx917/ConfigurationManagerImpl.cpp b/src/platform/silabs/SiWx917/ConfigurationManagerImpl.cpp new file mode 100644 index 00000000000000..aad749374aa943 --- /dev/null +++ b/src/platform/silabs/SiWx917/ConfigurationManagerImpl.cpp @@ -0,0 +1,317 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Nest Labs, Inc. + * + * 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 implementation of the Device Layer ConfigurationManager object + * for EFR32 platforms using the Silicon Labs SDK. + */ +/* this file behaves like a config.h, comes first */ +#include + +#include + +#include +#include +#include + +#include "em_rmu.h" + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION +#include "wfx_host_events.h" +#endif + +namespace chip { +namespace DeviceLayer { + +using namespace ::chip::DeviceLayer::Internal; + +ConfigurationManagerImpl & ConfigurationManagerImpl::GetDefaultInstance() +{ + static ConfigurationManagerImpl sInstance; + return sInstance; +} + +CHIP_ERROR ConfigurationManagerImpl::Init() +{ + CHIP_ERROR err; + + // Initialize the generic implementation base class. + err = Internal::GenericConfigurationManagerImpl::Init(); + SuccessOrExit(err); + + // TODO: Initialize the global GroupKeyStore object here (#1626) + + IncreaseBootCount(); + // It is possible to configure the possible reset sources with RMU_ResetControl + // In this case, we keep Reset control at default setting + rebootCause = RMU_ResetCauseGet(); + RMU_ResetCauseClear(); + + err = CHIP_NO_ERROR; + +exit: + return err; +} + +bool ConfigurationManagerImpl::CanFactoryReset() +{ + // TODO: query the application to determine if factory reset is allowed. + return true; +} + +void ConfigurationManagerImpl::InitiateFactoryReset() +{ + PlatformMgr().ScheduleWork(DoFactoryReset); +} + +CHIP_ERROR ConfigurationManagerImpl::GetRebootCount(uint32_t & rebootCount) +{ + return SILABSConfig::ReadConfigValue(SILABSConfig::kConfigKey_BootCount, rebootCount); +} + +CHIP_ERROR ConfigurationManagerImpl::IncreaseBootCount(void) +{ + uint32_t bootCount = 0; + + if (SILABSConfig::ConfigValueExists(SILABSConfig::kConfigKey_BootCount)) + { + GetRebootCount(bootCount); + } + + return SILABSConfig::WriteConfigValue(SILABSConfig::kConfigKey_BootCount, bootCount + 1); +} + +CHIP_ERROR ConfigurationManagerImpl::GetBootReason(uint32_t & bootReason) +{ + // rebootCause is obtained at bootup. + BootReasonType matterBootCause; +#if defined(_SILICON_LABS_32B_SERIES_1) + if (rebootCause & RMU_RSTCAUSE_PORST || rebootCause & RMU_RSTCAUSE_EXTRST) // PowerOn or External pin reset + { + matterBootCause = BootReasonType::kPowerOnReboot; + } + else if (rebootCause & RMU_RSTCAUSE_AVDDBOD || rebootCause & RMU_RSTCAUSE_DVDDBOD || rebootCause & RMU_RSTCAUSE_DECBOD) + { + matterBootCause = BootReasonType::kBrownOutReset; + } + else if (rebootCause & RMU_RSTCAUSE_SYSREQRST) + { + matterBootCause = BootReasonType::kSoftwareReset; + } + else if (rebootCause & RMU_RSTCAUSE_WDOGRST) + { + matterBootCause = BootReasonType::kSoftwareWatchdogReset; + } + else + { + matterBootCause = BootReasonType::kUnspecified; + } + // Not tracked HARDWARE_WATCHDOG_RESET && SOFTWARE_UPDATE_COMPLETED +#elif defined(_SILICON_LABS_32B_SERIES_2) + if (rebootCause & EMU_RSTCAUSE_POR || rebootCause & EMU_RSTCAUSE_PIN) // PowerOn or External pin reset + { + matterBootCause = BootReasonType::kPowerOnReboot; + } + else if (rebootCause & EMU_RSTCAUSE_AVDDBOD || rebootCause & EMU_RSTCAUSE_DVDDBOD || rebootCause & EMU_RSTCAUSE_DECBOD || + rebootCause & EMU_RSTCAUSE_VREGIN || rebootCause & EMU_RSTCAUSE_IOVDD0BOD || rebootCause & EMU_RSTCAUSE_DVDDLEBOD) + { + matterBootCause = BootReasonType::kBrownOutReset; + } + else if (rebootCause & EMU_RSTCAUSE_SYSREQ) + { + matterBootCause = BootReasonType::kSoftwareReset; + } + else if (rebootCause & EMU_RSTCAUSE_WDOG0 || rebootCause & EMU_RSTCAUSE_WDOG1) + { + matterBootCause = BootReasonType::kSoftwareWatchdogReset; + } + else + { + matterBootCause = BootReasonType::kUnspecified; + } + // Not tracked HARDWARE_WATCHDOG_RESET && SOFTWARE_UPDATE_COMPLETED +#else + matterBootCause = BootReasonType::kUnspecified; +#endif + + bootReason = to_underlying(matterBootCause); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ConfigurationManagerImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + if (!SILABSConfig::ConfigValueExists(SILABSConfig::kConfigKey_TotalOperationalHours)) + { + totalOperationalHours = 0; + return CHIP_NO_ERROR; + } + + return SILABSConfig::ReadConfigValue(SILABSConfig::kConfigKey_TotalOperationalHours, totalOperationalHours); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreTotalOperationalHours(uint32_t totalOperationalHours) +{ + return SILABSConfig::WriteConfigValue(SILABSConfig::kConfigKey_TotalOperationalHours, totalOperationalHours); +} + +CHIP_ERROR ConfigurationManagerImpl::ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key persistedStorageKey, + uint32_t & value) +{ + // This method reads CHIP Persisted Counter type nvm3 objects. + // (where persistedStorageKey represents an index to the counter). + CHIP_ERROR err; + + err = SILABSConfig::ReadConfigValueCounter(persistedStorageKey, value); + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + } + SuccessOrExit(err); + +exit: + return err; +} + +CHIP_ERROR ConfigurationManagerImpl::WritePersistedStorageValue(::chip::Platform::PersistedStorage::Key persistedStorageKey, + uint32_t value) +{ + // This method reads CHIP Persisted Counter type nvm3 objects. + // (where persistedStorageKey represents an index to the counter). + CHIP_ERROR err; + + err = SILABSConfig::WriteConfigValueCounter(persistedStorageKey, value); + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + } + SuccessOrExit(err); + +exit: + return err; +} + +CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, bool & val) +{ + return SILABSConfig::ReadConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, uint32_t & val) +{ + return SILABSConfig::ReadConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, uint64_t & val) +{ + return SILABSConfig::ReadConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) +{ + return SILABSConfig::ReadConfigValueStr(key, buf, bufSize, outLen); +} + +CHIP_ERROR ConfigurationManagerImpl::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) +{ + return SILABSConfig::ReadConfigValueBin(key, buf, bufSize, outLen); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, bool val) +{ + return SILABSConfig::WriteConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, uint32_t val) +{ + return SILABSConfig::WriteConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, uint64_t val) +{ + return SILABSConfig::WriteConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueStr(Key key, const char * str) +{ + return SILABSConfig::WriteConfigValueStr(key, str); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueStr(Key key, const char * str, size_t strLen) +{ + return SILABSConfig::WriteConfigValueStr(key, str, strLen); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) +{ + return SILABSConfig::WriteConfigValueBin(key, data, dataLen); +} + +void ConfigurationManagerImpl::RunConfigUnitTest(void) +{ + SILABSConfig::RunConfigUnitTest(); +} + +void ConfigurationManagerImpl::DoFactoryReset(intptr_t arg) +{ + CHIP_ERROR err; + + ChipLogProgress(DeviceLayer, "Performing factory reset"); + + err = SILABSConfig::FactoryResetConfig(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "FactoryResetConfig() failed: %s", chip::ErrorStr(err)); + } + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + + ChipLogProgress(DeviceLayer, "Clearing Thread provision"); + ThreadStackMgr().ErasePersistentInfo(); + +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD + + PersistedStorage::KeyValueStoreMgrImpl().ErasePartition(); + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION + ChipLogProgress(DeviceLayer, "Clearing WiFi provision"); + wfx_clear_wifi_provision(); +#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION + + // Restart the system. + ChipLogProgress(DeviceLayer, "System restarting"); + NVIC_SystemReset(); +} + +#ifdef SL_WIFI +CHIP_ERROR ConfigurationManagerImpl::GetPrimaryWiFiMACAddress(uint8_t * buf) +{ + sl_wfx_mac_address_t macaddr; + wfx_get_wifi_mac_addr(SL_WFX_STA_INTERFACE, &macaddr); + memcpy(buf, &macaddr.octet[0], sizeof(macaddr.octet)); + + return CHIP_NO_ERROR; +} +#endif + +ConfigurationManager & ConfigurationMgrImpl() +{ + return ConfigurationManagerImpl::GetDefaultInstance(); +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/silabs/SiWx917/ConnectivityManagerImpl.cpp b/src/platform/silabs/SiWx917/ConnectivityManagerImpl.cpp new file mode 100644 index 00000000000000..c38a5e5bb1e268 --- /dev/null +++ b/src/platform/silabs/SiWx917/ConnectivityManagerImpl.cpp @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Nest Labs, Inc. + * + * 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 +#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::Inet; +using namespace ::chip::System; +using namespace ::chip::TLV; +using namespace ::chip::DeviceLayer::Internal; + +namespace chip { +namespace DeviceLayer { + +ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; + +CHIP_ERROR ConnectivityManagerImpl::_Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // Initialize the generic base classes that require it. +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + GenericConnectivityManagerImpl_Thread::_Init(); +#endif + SuccessOrExit(err); + +exit: + return err; +} + +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/silabs/SiWx917/Efr32OpaqueKeypair.h b/src/platform/silabs/SiWx917/Efr32OpaqueKeypair.h new file mode 100644 index 00000000000000..58123c106ed892 --- /dev/null +++ b/src/platform/silabs/SiWx917/Efr32OpaqueKeypair.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2022 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 { +namespace Internal { + +typedef uint16_t EFR32OpaqueKeyId; +constexpr EFR32OpaqueKeyId kEFR32OpaqueKeyIdUnknown = 0xFFFFU; // Do not modify, will impact existing deployments +constexpr EFR32OpaqueKeyId kEFR32OpaqueKeyIdVolatile = 0xFFFEU; // Do not modify, will impact existing deployments +constexpr EFR32OpaqueKeyId kEFR32OpaqueKeyIdPersistentMin = 0x0U; // Do not modify, will impact existing deployments +constexpr EFR32OpaqueKeyId kEFR32OpaqueKeyIdPersistentMax = 0x1FFU; // Do not decrease, will impact existing deployments + +enum class EFR32OpaqueKeyUsages : uint8_t +{ + ECDSA_P256_SHA256 = 0, + ECDH_P256 = 1, +}; + +/** + * @brief Base class for opaque keys + * + * Deriving from this class allows using it as a base class for operations + * which don't expose the private key independent of key size. + **/ +class EFR32OpaqueKeypair +{ +public: + EFR32OpaqueKeypair(); + virtual ~EFR32OpaqueKeypair(); + + /** + * @brief Load a keypair with given key ID + * + * If no key exists under the given ID, an error is returned + * and the object is unusable for operations. + * + * @param key_id key ID under which this key was created + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Load(EFR32OpaqueKeyId key_id); + + /** + * @brief Create a new keypair with given ID and usage + * + * If a key already exists under the given ID, an error is returned + * and no new key is created. + * + * @param key_id key ID under which to store this key. Set to 0 + * for a non-persistent key which gets destructed + * when the lifetime of this object ends, or set + * to any other value to store the key under that + * ID. + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Create(EFR32OpaqueKeyId key_id, EFR32OpaqueKeyUsages usage); + + /** + * @brief Get the public key for this keypair + * + * @param output Output buffer to put public key (in 0x04 || X || Y format) + * @param output_size Size of \p output + * @param output_length Amount of bytes put in \p output on success + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR GetPublicKey(uint8_t * output, size_t output_size, size_t * output_length) const; + + /** + * @brief Get the key ID for this keypair + * + * @return Returns kEFR32OpaqueKeyIdUnknown for an uninitialised/invalid + * key, kEFR32OpaqueKeyIdVolatile for a volatile key, and a key + * ID in the range [kEFR32OpaqueKeyIdPersistentMin, kEFR32OpaqueKeyIdPersistentMax] + * for valid persistent keys. + **/ + EFR32OpaqueKeyId GetKeyId() const; + + /** + * @brief Use this keypair to sign a message using the ECDSA-SHA256 algorithm + * + * @param msg Message buffer to sign + * @param msg_len Size of \p msg in bytes + * @param output Output buffer to write signature to. Signature + * is in raw format (i.e. binary concatenation of + * r and s) + * @param output_size Size of output buffer + * @param output_length Amount of bytes written into output buffer + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Sign(const uint8_t * msg, size_t msg_len, uint8_t * output, size_t output_size, size_t * output_length) const; + + /** + * @brief Use this keypair to derive a key using the raw ECDH algorithm + * + * @param their_key Buffer containing raw uncompressed public key + * of party to derive with + * @param their_key_len Size of \p their_key in bytes + * @param output Output buffer to write derived bytes to + * @param output_size Size of output buffer + * @param output_length Amount of bytes written into output buffer + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Derive(const uint8_t * their_key, size_t their_key_len, uint8_t * output, size_t output_size, + size_t * output_length) const; + + /** + * @brief Delete the keypair from storage + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Delete(); + +protected: + void * mContext = nullptr; + bool mHasKey = false; + bool mIsPersistent = false; + uint8_t * mPubkeyRef = nullptr; + size_t mPubkeySize = 0; + size_t mPubkeyLength = 0; +}; + +/** + * @brief Derived class of P256Keypair for using opaque keys + * + * The signature and compiled form of this class is suboptimal due to how + * the P256Keypair isn't really an abstract interface, but rather partly + * interface / partly implementation. Future optimisation should look at + * converting P256Keypair to a fully abstract interface. + **/ +class EFR32OpaqueP256Keypair : public chip::Crypto::P256Keypair, public EFR32OpaqueKeypair +{ +public: + EFR32OpaqueP256Keypair(); + ~EFR32OpaqueP256Keypair() override; + + /** + * @brief Initialize the keypair. + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Initialize() override; + + /** + * @brief Serialize the keypair (unsupported on opaque keys) + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Serialize(chip::Crypto::P256SerializedKeypair & output) const override; + + /** + * @brief Deserialize the keypair (unsupported on opaque keys) + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Deserialize(chip::Crypto::P256SerializedKeypair & input) override; + + /** + * @brief Generate a new Certificate Signing Request (CSR). + * @param csr Newly generated CSR in DER format + * @param csr_length The caller provides the length of input buffer (csr). The function returns the actual length of generated + *CSR. + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const override; + + /** + * @brief A function to sign a msg using ECDSA + * @param msg Message that needs to be signed + * @param msg_length Length of message + * @param out_signature Buffer that will hold the output signature. The signature consists of: 2 EC elements (r and s), + * in raw point form (see SEC1). + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, + chip::Crypto::P256ECDSASignature & out_signature) const override; + + /** + * @brief A function to derive a shared secret using ECDH + * + * This implements the CHIP_Crypto_ECDH(PrivateKey myPrivateKey, PublicKey theirPublicKey) cryptographic primitive + * from the specification, using this class's private key from `mKeypair` as `myPrivateKey` and the remote + * public key from `remote_public_key` as `theirPublicKey`. + * + * @param remote_public_key Public key of remote peer with which we are trying to establish secure channel. remote_public_key is + * ASN.1 DER encoded as padded big-endian field elements as described in SEC 1: Elliptic Curve Cryptography + * [https://www.secg.org/sec1-v2.pdf] + * @param out_secret Buffer to write out secret into. This is a byte array representing the x coordinate of the shared secret. + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR ECDH_derive_secret(const chip::Crypto::P256PublicKey & remote_public_key, + chip::Crypto::P256ECDHDerivedSecret & out_secret) const override; + + /** @brief Return public key for the keypair. + **/ + const chip::Crypto::P256PublicKey & Pubkey() const override; + +private: + chip::Crypto::P256PublicKey mPubKey; +}; + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/silabs/SiWx917/Efr32PsaOpaqueKeypair.cpp b/src/platform/silabs/SiWx917/Efr32PsaOpaqueKeypair.cpp new file mode 100644 index 00000000000000..ae9a0f66c13cad --- /dev/null +++ b/src/platform/silabs/SiWx917/Efr32PsaOpaqueKeypair.cpp @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2022 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 "Efr32OpaqueKeypair.h" +#include "em_device.h" +#include + +#include +#include +#include +using chip::Platform::MemoryCalloc; +using chip::Platform::MemoryFree; + +using chip::Crypto::P256ECDHDerivedSecret; +using chip::Crypto::P256ECDSASignature; +using chip::Crypto::P256Keypair; +using chip::Crypto::P256PublicKey; +using chip::Crypto::P256SerializedKeypair; + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +/******************************************************************************* + * + * PSA key ID range for storing Matter Opaque keys + * + ******************************************************************************/ +#define PSA_KEY_ID_FOR_MATTER_MIN (0x00004400) +#define PSA_KEY_ID_FOR_MATTER_MAX (0x000045FF) +#define PSA_KEY_ID_FOR_MATTER_SIZE (PSA_KEY_ID_FOR_MATTER_MAX - PSA_KEY_ID_FOR_MATTER_MIN + 1) + +static_assert((kEFR32OpaqueKeyIdPersistentMax - kEFR32OpaqueKeyIdPersistentMin) < PSA_KEY_ID_FOR_MATTER_SIZE, + "Not enough PSA range to store all allowed opaque key IDs"); + +#if defined(SEMAILBOX_PRESENT) && (_SILICON_LABS_SECURITY_FEATURE == _SILICON_LABS_SECURITY_FEATURE_VAULT) +#define PSA_CRYPTO_LOCATION_FOR_DEVICE PSA_KEY_LOCATION_SL_SE_OPAQUE +#elif defined(CRYPTOACC_PRESENT) && defined(SEPUF_PRESENT) && defined(SL_TRUSTZONE_NONSECURE) +#define PSA_CRYPTO_LOCATION_FOR_DEVICE PSA_KEY_LOCATION_SL_CRYPTOACC_OPAQUE +#else +#define PSA_CRYPTO_LOCATION_FOR_DEVICE PSA_KEY_LOCATION_LOCAL_STORAGE +#endif + +static void _log_PSA_error(psa_status_t status) +{ + if (status != PSA_SUCCESS) + { + ChipLogError(Crypto, "PSA error: %ld", status); + } +} + +/******************************************************************************* + * + * PSA Crypto backed implementation of EFR32OpaqueKeypair + * + ******************************************************************************/ + +static bool is_opaque_key_valid(EFR32OpaqueKeyId id) +{ + if (id == kEFR32OpaqueKeyIdVolatile) + { + return true; + } + else if (id >= kEFR32OpaqueKeyIdPersistentMin && id <= (kEFR32OpaqueKeyIdPersistentMin + PSA_KEY_ID_FOR_MATTER_SIZE)) + { + return true; + } + + return false; +} + +static mbedtls_svc_key_id_t psa_key_id_from_opaque(EFR32OpaqueKeyId id) +{ + if (id == kEFR32OpaqueKeyIdVolatile || !is_opaque_key_valid(id)) + { + return 0; + } + + return PSA_KEY_ID_FOR_MATTER_MIN + (id - kEFR32OpaqueKeyIdPersistentMin); +} + +static EFR32OpaqueKeyId opaque_key_id_from_psa(mbedtls_svc_key_id_t id) +{ + if (id == 0) + { + return kEFR32OpaqueKeyIdVolatile; + } + else if (id >= PSA_KEY_ID_FOR_MATTER_MIN && id <= PSA_KEY_ID_FOR_MATTER_MAX) + { + return (id + kEFR32OpaqueKeyIdPersistentMin) - PSA_KEY_ID_FOR_MATTER_MIN; + } + else + { + return kEFR32OpaqueKeyIdUnknown; + } +} + +EFR32OpaqueKeypair::EFR32OpaqueKeypair() +{ + psa_crypto_init(); + // Avoid having a reference to PSA datatypes in the signature of this class + mContext = MemoryCalloc(1, sizeof(mbedtls_svc_key_id_t)); +} + +EFR32OpaqueKeypair::~EFR32OpaqueKeypair() +{ + // Free key resources + if (mContext != nullptr) + { + // Delete volatile keys, since nobody else can after we drop the key ID. + if (!mIsPersistent) + { + Delete(); + } + + MemoryFree(mContext); + mContext = nullptr; + } +} + +CHIP_ERROR EFR32OpaqueKeypair::Load(EFR32OpaqueKeyId opaque_id) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + mbedtls_svc_key_id_t key_id = 0; + + VerifyOrExit(opaque_id != kEFR32OpaqueKeyIdVolatile, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(is_opaque_key_valid(opaque_id), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(mContext, error = CHIP_ERROR_INCORRECT_STATE); + + // If the object contains a volatile key, clean it up before reusing the object storage + if (mHasKey && !mIsPersistent) + { + Delete(); + } + + key_id = psa_key_id_from_opaque(opaque_id); + + status = psa_export_public_key(key_id, mPubkeyRef, mPubkeySize, &mPubkeyLength); + + if (status == PSA_ERROR_DOES_NOT_EXIST) + { + error = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + goto exit; + } + + VerifyOrExit(status == PSA_SUCCESS, { + _log_PSA_error(status); + error = CHIP_ERROR_INTERNAL; + }); + + // Store the key ID and mark the key as valid + *(mbedtls_svc_key_id_t *) mContext = key_id; + mHasKey = true; + mIsPersistent = true; + +exit: + if (error != CHIP_NO_ERROR) + { + memset(mPubkeyRef, 0, mPubkeySize); + } + + return error; +} + +CHIP_ERROR EFR32OpaqueKeypair::Create(EFR32OpaqueKeyId opaque_id, EFR32OpaqueKeyUsages usage) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + mbedtls_svc_key_id_t key_id = 0; + + VerifyOrExit(is_opaque_key_valid(opaque_id), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(mContext, error = CHIP_ERROR_INCORRECT_STATE); + + if (opaque_id == kEFR32OpaqueKeyIdVolatile) + { + psa_set_key_lifetime( + &attr, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_LIFETIME_VOLATILE, PSA_CRYPTO_LOCATION_FOR_DEVICE)); + } + else + { + psa_key_handle_t key_handle; + + key_id = psa_key_id_from_opaque(opaque_id); + + // Check if the key already exists + int ret = psa_open_key(key_id, &key_handle); + if (PSA_SUCCESS == ret) + { + // WARNING: Existing key! This is caused by a problem in the key store. + // The key must be destroyed, otherwhise the device won't recover. + ChipLogError(Crypto, "WARNING: PSA key recycled: %d / %ld", opaque_id, key_id); + psa_destroy_key(key_id); + } + + psa_set_key_id(&attr, key_id); + psa_set_key_lifetime( + &attr, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_LIFETIME_PERSISTENT, PSA_CRYPTO_LOCATION_FOR_DEVICE)); + } + + switch (usage) + { + case EFR32OpaqueKeyUsages::ECDSA_P256_SHA256: + psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attr, 256); + psa_set_key_algorithm(&attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + // Need hash signing permissions because the CSR generation uses sign_hash internally + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_SIGN_HASH); + break; + case EFR32OpaqueKeyUsages::ECDH_P256: + psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attr, 256); + psa_set_key_algorithm(&attr, PSA_ALG_ECDH); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE); + break; + } + + status = psa_generate_key(&attr, &key_id); + VerifyOrExit(status == PSA_SUCCESS, { + _log_PSA_error(status); + error = CHIP_ERROR_INTERNAL; + }); + + // Export the public key + status = psa_export_public_key(key_id, mPubkeyRef, mPubkeySize, &mPubkeyLength); + if (PSA_SUCCESS != status) + { + _log_PSA_error(status); + // Key generation succeeded, but pubkey export did not. To avoid + // memory leaks, delete the generated key before returning the error + psa_destroy_key(key_id); + error = CHIP_ERROR_INTERNAL; + goto exit; + } + + // Store the key ID and mark the key as valid + mHasKey = true; + mIsPersistent = opaque_id != kEFR32OpaqueKeyIdVolatile; + +exit: + psa_reset_key_attributes(&attr); + if (mContext) + { + if (CHIP_NO_ERROR == error) + { + *(mbedtls_svc_key_id_t *) mContext = key_id; + } + else + { + *(mbedtls_svc_key_id_t *) mContext = 0; + } + } + return error; +} + +CHIP_ERROR EFR32OpaqueKeypair::GetPublicKey(uint8_t * output, size_t output_size, size_t * output_length) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + VerifyOrExit(mHasKey, error = CHIP_ERROR_INCORRECT_STATE); + + if (output_size >= mPubkeyLength) + { + memcpy(output, mPubkeyRef, mPubkeyLength); + *output_length = mPubkeyLength; + } + else + { + error = CHIP_ERROR_BUFFER_TOO_SMALL; + } +exit: + return error; +} + +EFR32OpaqueKeyId EFR32OpaqueKeypair::GetKeyId() const +{ + if (!mHasKey) + { + return kEFR32OpaqueKeyIdUnknown; + } + + if (!mIsPersistent) + { + return kEFR32OpaqueKeyIdVolatile; + } + + return opaque_key_id_from_psa(*(mbedtls_svc_key_id_t *) mContext); +} + +CHIP_ERROR EFR32OpaqueKeypair::Sign(const uint8_t * msg, size_t msg_len, uint8_t * output, size_t output_size, + size_t * output_length) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + + VerifyOrExit(mContext, error = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mHasKey, error = CHIP_ERROR_INCORRECT_STATE); + + status = psa_sign_message(*(mbedtls_svc_key_id_t *) mContext, PSA_ALG_ECDSA(PSA_ALG_SHA_256), msg, msg_len, output, output_size, + output_length); + + VerifyOrExit(status == PSA_SUCCESS, { + _log_PSA_error(status); + error = CHIP_ERROR_INTERNAL; + }); + +exit: + return error; +} + +CHIP_ERROR EFR32OpaqueKeypair::Derive(const uint8_t * their_key, size_t their_key_len, uint8_t * output, size_t output_size, + size_t * output_length) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + + VerifyOrExit(mHasKey, error = CHIP_ERROR_INCORRECT_STATE); + + status = psa_raw_key_agreement(PSA_ALG_ECDH, *(mbedtls_svc_key_id_t *) mContext, their_key, their_key_len, output, output_size, + output_length); + + VerifyOrExit(status == PSA_SUCCESS, { + _log_PSA_error(status); + error = CHIP_ERROR_INTERNAL; + }); + +exit: + return error; +} + +CHIP_ERROR EFR32OpaqueKeypair::Delete() +{ + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_ERROR_BAD_STATE; + + VerifyOrExit(mHasKey, error = CHIP_ERROR_INCORRECT_STATE); + + status = psa_destroy_key(*(mbedtls_svc_key_id_t *) mContext); + VerifyOrExit(status == PSA_SUCCESS, { + _log_PSA_error(status); + error = CHIP_ERROR_INTERNAL; + }); + +exit: + mHasKey = false; + mIsPersistent = false; + memset(mPubkeyRef, 0, mPubkeySize); + if (mContext) + { + *(mbedtls_svc_key_id_t *) mContext = 0; + } + return error; +} + +/******************************************************************************* + * + * PSA Crypto backed implementation of EFR32OpaqueP256Keypair + * + ******************************************************************************/ +EFR32OpaqueP256Keypair::EFR32OpaqueP256Keypair() +{ + mPubkeyRef = mPubKey.Bytes(); + mPubkeySize = mPubKey.Length(); + mPubkeyLength = 0; +} + +EFR32OpaqueP256Keypair::~EFR32OpaqueP256Keypair() {} + +CHIP_ERROR EFR32OpaqueP256Keypair::Initialize() +{ + if (mPubkeyLength > 0) + { + // already have a key - ECDH use case where CASESession is calling Initialize() + return CHIP_NO_ERROR; + } + + ChipLogError(Crypto, "Initialize() is invalid on opaque keys, use Create() instead"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR EFR32OpaqueP256Keypair::Serialize(P256SerializedKeypair & output) const +{ + ChipLogError(Crypto, "Serialisation is invalid on opaque keys, share the object instead"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR EFR32OpaqueP256Keypair::Deserialize(P256SerializedKeypair & input) +{ + ChipLogError(Crypto, "Serialisation is invalid on opaque keys"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR EFR32OpaqueP256Keypair::NewCertificateSigningRequest(uint8_t * out_csr, size_t & csr_length) const +{ + MutableByteSpan csr(out_csr, csr_length); + CHIP_ERROR err = GenerateCertificateSigningRequest(this, csr); + csr_length = (CHIP_NO_ERROR == err) ? csr.size() : 0; + return err; +} + +CHIP_ERROR EFR32OpaqueP256Keypair::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + size_t output_length = 0; + + VerifyOrExit((msg != nullptr) && (msg_length > 0), error = CHIP_ERROR_INVALID_ARGUMENT); + + error = Sign(msg, msg_length, out_signature.Bytes(), out_signature.Capacity(), &output_length); + + SuccessOrExit(error); + SuccessOrExit(out_signature.SetLength(output_length)); +exit: + return error; +} + +CHIP_ERROR EFR32OpaqueP256Keypair::ECDH_derive_secret(const P256PublicKey & remote_public_key, + P256ECDHDerivedSecret & out_secret) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + size_t output_length = 0; + + error = Derive(Uint8::to_const_uchar(remote_public_key), remote_public_key.Length(), Uint8::to_uchar(out_secret), + (out_secret.Length() == 0) ? out_secret.Capacity() : out_secret.Length(), &output_length); + + SuccessOrExit(error); + SuccessOrExit(out_secret.SetLength(output_length)); +exit: + return error; +} + +const P256PublicKey & EFR32OpaqueP256Keypair::Pubkey() const +{ + return mPubKey; +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/silabs/SiWx917/Efr32PsaOperationalKeystore.cpp b/src/platform/silabs/SiWx917/Efr32PsaOperationalKeystore.cpp new file mode 100644 index 00000000000000..e8fdf61ff1c903 --- /dev/null +++ b/src/platform/silabs/SiWx917/Efr32PsaOperationalKeystore.cpp @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2022 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 "Efr32PsaOperationalKeystore.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "Efr32OpaqueKeypair.h" +#include + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +static_assert((sizeof(FabricIndex) == 1), "Implementation is not prepared for large fabric indices"); +static_assert(SL_MATTER_MAX_STORED_OP_KEYS <= (kEFR32OpaqueKeyIdPersistentMax - kEFR32OpaqueKeyIdPersistentMin), + "Not enough opaque keys available to cover all requested operational keys"); +static_assert((CHIP_CONFIG_MAX_FABRICS + 1) <= SL_MATTER_MAX_STORED_OP_KEYS, + "Not enough operational keys requested to cover all potential fabrics (+1 staging for fabric update)"); +static_assert(SL_MATTER_MAX_STORED_OP_KEYS >= 1, "Minimum supported amount of operational keys is 1"); + +using namespace chip::Crypto; + +using chip::Platform::MemoryCalloc; +using chip::Platform::MemoryFree; + +Efr32PsaOperationalKeystore::~Efr32PsaOperationalKeystore() +{ + Deinit(); +} + +CHIP_ERROR Efr32PsaOperationalKeystore::Init() +{ + // Detect existing keymap size + CHIP_ERROR error = CHIP_NO_ERROR; + size_t wantedLen = SL_MATTER_MAX_STORED_OP_KEYS * sizeof(FabricIndex); + size_t existingLen = 0; + bool update_cache = false; + + if (SILABSConfig::ConfigValueExists(SILABSConfig::kConfigKey_OpKeyMap, existingLen)) + { + // There's a pre-existing key map on disk. Size the map to read it fully. + size_t outLen = 0; + + if (existingLen > (kEFR32OpaqueKeyIdPersistentMax - kEFR32OpaqueKeyIdPersistentMin) * sizeof(FabricIndex)) + { + return CHIP_ERROR_INTERNAL; + } + + // Upsize the map if the config was changed + if (existingLen < wantedLen) + { + existingLen = wantedLen; + } + + mKeyMap = (FabricIndex *) MemoryCalloc(1, existingLen); + VerifyOrExit(mKeyMap, error = CHIP_ERROR_NO_MEMORY); + + // Read the existing key map + error = SILABSConfig::ReadConfigValueBin(SILABSConfig::kConfigKey_OpKeyMap, (uint8_t *) mKeyMap, existingLen, outLen); + SuccessOrExit(error); + + // If upsizing, extend the map with undefined indices + for (size_t i = (outLen / sizeof(FabricIndex)); i < (existingLen / sizeof(FabricIndex)); i++) + { + mKeyMap[i] = kUndefinedFabricIndex; + } + + // If the config has changed, check whether it can be downsized fully or partially + if (existingLen > wantedLen) + { + size_t highest_found_index = 0; + for (size_t i = (wantedLen / sizeof(FabricIndex)); i < (existingLen / sizeof(FabricIndex)); i++) + { + if (mKeyMap[i] != kUndefinedFabricIndex) + { + highest_found_index = i; + } + } + + // set size to the smallest that will fit the upper opaque key ID in use + if (highest_found_index > 0) + { + existingLen = (highest_found_index + 1) * sizeof(FabricIndex); + update_cache = true; + } + } + + // Set the key map size + mKeyMapSize = existingLen; + } + else + { + // No key map on disk. Create and initialize a new one. + mKeyMap = (FabricIndex *) MemoryCalloc(1, wantedLen); + VerifyOrExit(mKeyMap, error = CHIP_ERROR_NO_MEMORY); + + for (size_t i = 0; i < (wantedLen / sizeof(FabricIndex)); i++) + { + mKeyMap[i] = kUndefinedFabricIndex; + } + + mKeyMapSize = wantedLen; + + update_cache = true; + } + + // Write-out keymap if needed + if (update_cache) + { + error = SILABSConfig::WriteConfigValueBin(SILABSConfig::kConfigKey_OpKeyMap, mKeyMap, mKeyMapSize); + SuccessOrExit(error); + } + + // Initialize cache key + mCachedKey = Platform::New(); + VerifyOrExit(mCachedKey, error = CHIP_ERROR_NO_MEMORY); + +exit: + if (error != CHIP_NO_ERROR) + { + Deinit(); + return error; + } + + mIsInitialized = true; + return CHIP_NO_ERROR; +} + +EFR32OpaqueKeyId Efr32PsaOperationalKeystore::FindKeyIdForFabric(FabricIndex fabricIndex) const +{ + // Search the map linearly to find a matching index slot + for (size_t i = 0; i < (mKeyMapSize / sizeof(FabricIndex)); i++) + { + if (mKeyMap[i] == fabricIndex) + { + // Found a match + return i + kEFR32OpaqueKeyIdPersistentMin; + } + } + + return kEFR32OpaqueKeyIdUnknown; +} + +bool Efr32PsaOperationalKeystore::HasOpKeypairForFabric(FabricIndex fabricIndex) const +{ + VerifyOrReturnError(mIsInitialized, false); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), false); + + // If there was a pending keypair, then there's really a usable key + if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex) && (mPendingKeypair != nullptr)) + { + return true; + } + + // Check whether we have a match in the map + if (FindKeyIdForFabric(fabricIndex) != kEFR32OpaqueKeyIdUnknown) + { + return true; + } + + return false; +} + +CHIP_ERROR Efr32PsaOperationalKeystore::NewOpKeypairForFabric(FabricIndex fabricIndex, + MutableByteSpan & outCertificateSigningRequest) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + VerifyOrReturnError(mIsInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // If a key is pending, we cannot generate for a different fabric index until we commit or revert. + if ((mPendingFabricIndex != kUndefinedFabricIndex) && (fabricIndex != mPendingFabricIndex)) + { + return CHIP_ERROR_INVALID_FABRIC_INDEX; + } + + VerifyOrReturnError(outCertificateSigningRequest.size() >= Crypto::kMAX_CSR_Length, CHIP_ERROR_BUFFER_TOO_SMALL); + + // Generate new key + EFR32OpaqueKeyId id = kEFR32OpaqueKeyIdUnknown; + + if (mPendingFabricIndex != kUndefinedFabricIndex) + { + // If we already have a pending key, delete it and put a new one in its place + id = mPendingKeypair->GetKeyId(); + if (id == kEFR32OpaqueKeyIdUnknown) + { + ResetPendingKey(); + } + else + { + mPendingKeypair->Delete(); + if (id == kEFR32OpaqueKeyIdVolatile) + { + id = kEFR32OpaqueKeyIdUnknown; + } + } + } + + if (id == kEFR32OpaqueKeyIdUnknown) + { + // Try to find an available opaque ID in the map + id = FindKeyIdForFabric(kUndefinedFabricIndex); + + if (!mPendingKeypair) + { + mPendingKeypair = Platform::New(); + } + } + + if (id == kEFR32OpaqueKeyIdUnknown) + { + // Could not find a free spot in the map + return CHIP_ERROR_NO_MEMORY; + } + + // Create new key on the old or found key ID + error = mPendingKeypair->Create(id, EFR32OpaqueKeyUsages::ECDSA_P256_SHA256); + if (error != CHIP_NO_ERROR) + { + ResetPendingKey(); + return error; + } + + // Set CSR and state + size_t csrLength = outCertificateSigningRequest.size(); + error = mPendingKeypair->NewCertificateSigningRequest(outCertificateSigningRequest.data(), csrLength); + if (error != CHIP_NO_ERROR) + { + ResetPendingKey(); + return error; + } + + outCertificateSigningRequest.reduce_size(csrLength); + mPendingFabricIndex = fabricIndex; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Efr32PsaOperationalKeystore::ActivateOpKeypairForFabric(FabricIndex fabricIndex, + const Crypto::P256PublicKey & nocPublicKey) +{ + VerifyOrReturnError(mIsInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Validate public key being activated matches last generated pending keypair + VerifyOrReturnError(mPendingKeypair->Pubkey().Matches(nocPublicKey), CHIP_ERROR_INVALID_PUBLIC_KEY); + + mIsPendingKeypairActive = true; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Efr32PsaOperationalKeystore::CommitOpKeypairForFabric(FabricIndex fabricIndex) +{ + VerifyOrReturnError(mIsInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + VerifyOrReturnError(mIsPendingKeypairActive == true, CHIP_ERROR_INCORRECT_STATE); + + // Add key association to key map + EFR32OpaqueKeyId id = mPendingKeypair->GetKeyId(); + + if (id == kEFR32OpaqueKeyIdUnknown || id == kEFR32OpaqueKeyIdVolatile) + { + ResetPendingKey(); + return CHIP_ERROR_INTERNAL; + } + + // Guard against array out-of-bounds (should not happen with correctly initialised keys) + size_t keymap_index = id - kEFR32OpaqueKeyIdPersistentMin; + if (keymap_index >= (mKeyMapSize / sizeof(FabricIndex))) + { + return CHIP_ERROR_INTERNAL; + } + + if (mKeyMap[keymap_index] != kUndefinedFabricIndex) + { + ResetPendingKey(); + return CHIP_ERROR_INTERNAL; + } + + mKeyMap[keymap_index] = fabricIndex; + + // Persist key map + CHIP_ERROR error = SILABSConfig::WriteConfigValueBin(SILABSConfig::kConfigKey_OpKeyMap, mKeyMap, mKeyMapSize); + if (error != CHIP_NO_ERROR) + { + return error; + } + + // There's a good chance we'll need the key again soon + mCachedKey->Load(id); + + mPendingKeypair = nullptr; + mIsPendingKeypairActive = false; + mPendingFabricIndex = kUndefinedFabricIndex; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Efr32PsaOperationalKeystore::RemoveOpKeypairForFabric(FabricIndex fabricIndex) +{ + VerifyOrReturnError(mIsInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Remove pending keypair if we have it and the fabric ID matches + if ((mPendingKeypair != nullptr) && (fabricIndex == mPendingFabricIndex)) + { + RevertPendingKeypair(); + } + + EFR32OpaqueKeyId id = FindKeyIdForFabric(fabricIndex); + if (id == kEFR32OpaqueKeyIdUnknown) + { + // Fabric is not in the map, so assume it's gone already + return CHIP_NO_ERROR; + } + + // Guard against array out-of-bounds (should not happen with correctly initialised keys) + size_t keymap_index = id - kEFR32OpaqueKeyIdPersistentMin; + if (keymap_index >= (mKeyMapSize / sizeof(FabricIndex))) + { + return CHIP_ERROR_INTERNAL; + } + + // Reset the key mapping since we'll be deleting this key + mKeyMap[keymap_index] = kUndefinedFabricIndex; + + // Persist key map + CHIP_ERROR error = SILABSConfig::WriteConfigValueBin(SILABSConfig::kConfigKey_OpKeyMap, mKeyMap, mKeyMapSize); + if (error != CHIP_NO_ERROR) + { + return error; + } + + // Check if key is cached + EFR32OpaqueKeyId cachedId = mCachedKey->GetKeyId(); + + if (id == cachedId) + { + // Delete from persistent storage and unload + mCachedKey->Delete(); + return CHIP_NO_ERROR; + } + + // Load it for purposes of deletion + error = mCachedKey->Load(id); + if (error != CHIP_NO_ERROR && error != CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + return CHIP_ERROR_INTERNAL; + } + + mCachedKey->Delete(); + + return CHIP_NO_ERROR; +} + +void Efr32PsaOperationalKeystore::RevertPendingKeypair() +{ + if (mIsInitialized) + { + // Just delete the pending key from storage + ResetPendingKey(); + } +} + +CHIP_ERROR Efr32PsaOperationalKeystore::SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message, + Crypto::P256ECDSASignature & outSignature) const +{ + VerifyOrReturnError(mIsInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Check to see whether the key is an activated pending key + if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex)) + { + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INTERNAL); + return mPendingKeypair->ECDSA_sign_msg(message.data(), message.size(), outSignature); + } + + // Figure out which key ID we're looking for + EFR32OpaqueKeyId id = FindKeyIdForFabric(fabricIndex); + + if (id == kEFR32OpaqueKeyIdUnknown) + { + // Fabric is not in the map, but the caller thinks it's there? + return CHIP_ERROR_INTERNAL; + } + + // Check whether we have the key in cache + EFR32OpaqueKeyId cachedId = mCachedKey->GetKeyId(); + + if (id == cachedId) + { + return mCachedKey->ECDSA_sign_msg(message.data(), message.size(), outSignature); + } + + // If not, we need to recreate from the backend + CHIP_ERROR error = mCachedKey->Load(id); + if (error != CHIP_NO_ERROR) + { + return CHIP_ERROR_INTERNAL; + } + + // Sign with retrieved key + error = mCachedKey->ECDSA_sign_msg(message.data(), message.size(), outSignature); + if (error != CHIP_NO_ERROR) + { + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +Crypto::P256Keypair * Efr32PsaOperationalKeystore::AllocateEphemeralKeypairForCASE() +{ + EFR32OpaqueP256Keypair * new_key = Platform::New(); + + if (new_key != nullptr) + { + new_key->Create(kEFR32OpaqueKeyIdVolatile, EFR32OpaqueKeyUsages::ECDH_P256); + } + + return new_key; +} + +void Efr32PsaOperationalKeystore::ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) +{ + Platform::Delete((EFR32OpaqueP256Keypair *) keypair); +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/silabs/SiWx917/Efr32PsaOperationalKeystore.h b/src/platform/silabs/SiWx917/Efr32PsaOperationalKeystore.h new file mode 100644 index 00000000000000..4203724bd0dba7 --- /dev/null +++ b/src/platform/silabs/SiWx917/Efr32PsaOperationalKeystore.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#include "Efr32OpaqueKeypair.h" +#include + +// Set SL_MATTER_MAX_STORED_OP_KEYS to the preferred size of the mapping table +// between fabric IDs and opaque key indices. It can not be less than +// CHIP_CONFIG_MAX_FABRICS + 1 (since there would be too few map elements to +// support all fabrics the application wants to support in addition to an extra +// pending key), but can be larger in case a consistent on-disk size of the map +// is required. +#ifndef SL_MATTER_MAX_STORED_OP_KEYS +#define SL_MATTER_MAX_STORED_OP_KEYS (CHIP_CONFIG_MAX_FABRICS + 1) +#endif + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +/** + * @brief OperationalKeystore implementation making use of the EFR32 SDK-provided + * storage mechanisms to load/store keypairs. + * + * WARNING: Ensure that any implementation that uses this one as a starting point + * DOES NOT have the raw key material (in usable form) passed up/down to + * direct storage APIs that may make copies on heap/stack without sanitization. + */ +class Efr32PsaOperationalKeystore : public chip::Crypto::OperationalKeystore +{ +public: + Efr32PsaOperationalKeystore(){}; + virtual ~Efr32PsaOperationalKeystore() override; + + // Non-copyable + Efr32PsaOperationalKeystore(Efr32PsaOperationalKeystore const &) = delete; + void operator=(Efr32PsaOperationalKeystore const &) = delete; + + /** + * @brief Initialize the Operational Keystore + */ + CHIP_ERROR Init(); + + bool HasPendingOpKeypair() const override { return (mPendingKeypair != nullptr); } + + bool HasOpKeypairForFabric(FabricIndex fabricIndex) const override; + CHIP_ERROR NewOpKeypairForFabric(FabricIndex fabricIndex, MutableByteSpan & outCertificateSigningRequest) override; + CHIP_ERROR ActivateOpKeypairForFabric(FabricIndex fabricIndex, const chip::Crypto::P256PublicKey & nocPublicKey) override; + CHIP_ERROR CommitOpKeypairForFabric(FabricIndex fabricIndex) override; + CHIP_ERROR RemoveOpKeypairForFabric(FabricIndex fabricIndex) override; + void RevertPendingKeypair() override; + CHIP_ERROR SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message, + chip::Crypto::P256ECDSASignature & outSignature) const override; + Crypto::P256Keypair * AllocateEphemeralKeypairForCASE() override; + void ReleaseEphemeralKeypair(chip::Crypto::P256Keypair * keypair) override; + +protected: + // The keymap maps PSA Crypto persistent key ID offsets against fabric IDs. + // The keymap is persisted in NVM3, and the keys are stored through the PSA + // API. + FabricIndex * mKeyMap = nullptr; + size_t mKeyMapSize = 0; + + // The key cache is to avoid having to reconstruct keys from the storage + // backend all the time (since it is rather slow). + EFR32OpaqueP256Keypair * mCachedKey = nullptr; + + // This pending fabric index is `kUndefinedFabricIndex` if there isn't a + // pending keypair override for a given fabric. + FabricIndex mPendingFabricIndex = kUndefinedFabricIndex; + EFR32OpaqueP256Keypair * mPendingKeypair = nullptr; + bool mIsPendingKeypairActive = false; + bool mIsInitialized = false; + +private: + void ResetPendingKey() + { + if (mPendingKeypair != nullptr) + { + mPendingKeypair->Delete(); + Platform::Delete(mPendingKeypair); + } + mPendingKeypair = nullptr; + mIsPendingKeypairActive = false; + mPendingFabricIndex = kUndefinedFabricIndex; + } + + void Deinit() + { + ResetPendingKey(); + + if (mCachedKey != nullptr) + { + Platform::Delete(mCachedKey); + mCachedKey = nullptr; + } + + if (mKeyMap != nullptr) + { + Platform::MemoryFree(mKeyMap); + mKeyMap = nullptr; + mKeyMapSize = 0; + } + + mIsInitialized = false; + } + + /** + * @brief Find the opaque key ID stored in the map for a given + * fabric ID. + * + * @param fabricIndex The fabric index to find the opaque key ID for. + * Can also be kUndefinedFabricIndex to find the first + * unoccupied key ID. + * + * @return a valid key ID on match, or kEFR32OpaqueKeyIdUnknown if no + * match is found. + */ + EFR32OpaqueKeyId FindKeyIdForFabric(FabricIndex fabricIndex) const; +}; + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/silabs/SiWx917/KeyValueStoreManagerImpl.cpp b/src/platform/silabs/SiWx917/KeyValueStoreManagerImpl.cpp new file mode 100644 index 00000000000000..c752c757eb9cdb --- /dev/null +++ b/src/platform/silabs/SiWx917/KeyValueStoreManagerImpl.cpp @@ -0,0 +1,213 @@ +/* + * + * Copyright (c) 2021-2022 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 SILABS + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::DeviceLayer::Internal; + +#define CONVERT_KEYMAP_INDEX_TO_NVM3KEY(index) (SILABSConfig::kConfigKey_KvsFirstKeySlot + index) +#define CONVERT_NVM3KEY_TO_KEYMAP_INDEX(nvm3Key) (nvm3Key - SILABSConfig::kConfigKey_KvsFirstKeySlot) + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; +char mKvsStoredKeyString[KeyValueStoreManagerImpl::kMaxEntries][PersistentStorageDelegate::kKeyLengthMax + 1]; + +CHIP_ERROR KeyValueStoreManagerImpl::Init(void) +{ + CHIP_ERROR err; + err = SILABSConfig::Init(); + SuccessOrExit(err); + + memset(mKvsStoredKeyString, 0, sizeof(mKvsStoredKeyString)); + size_t outLen; + err = SILABSConfig::ReadConfigValueBin(SILABSConfig::kConfigKey_KvsStringKeyMap, + reinterpret_cast(mKvsStoredKeyString), sizeof(mKvsStoredKeyString), outLen); + + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) // Initial boot + { + err = CHIP_NO_ERROR; + } + +exit: + return err; +} + +bool KeyValueStoreManagerImpl::IsValidKvsNvm3Key(uint32_t nvm3Key) const +{ + return ((SILABSConfig::kConfigKey_KvsFirstKeySlot <= nvm3Key) && (nvm3Key <= SILABSConfig::kConfigKey_KvsLastKeySlot)); +} + +CHIP_ERROR KeyValueStoreManagerImpl::MapKvsKeyToNvm3(const char * key, uint32_t & nvm3Key, bool isSlotNeeded) const +{ + CHIP_ERROR err; + uint8_t firstEmptyKeySlot = kMaxEntries; + for (uint8_t keyIndex = 0; keyIndex < kMaxEntries; keyIndex++) + { + if (strcmp(key, mKvsStoredKeyString[keyIndex]) == 0) + { + nvm3Key = CONVERT_KEYMAP_INDEX_TO_NVM3KEY(keyIndex); + VerifyOrDie(IsValidKvsNvm3Key(nvm3Key) == true); + return CHIP_NO_ERROR; + } + + if (isSlotNeeded && (firstEmptyKeySlot == kMaxEntries) && (mKvsStoredKeyString[keyIndex][0] == 0)) + { + firstEmptyKeySlot = keyIndex; + } + } + + if (isSlotNeeded) + { + if (firstEmptyKeySlot != kMaxEntries) + { + nvm3Key = CONVERT_KEYMAP_INDEX_TO_NVM3KEY(firstEmptyKeySlot); + VerifyOrDie(IsValidKvsNvm3Key(nvm3Key) == true); + err = CHIP_NO_ERROR; + } + else + { + err = CHIP_ERROR_PERSISTED_STORAGE_FAILED; + } + } + else + { + err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + } + return err; +} + +void KeyValueStoreManagerImpl::ForceKeyMapSave() +{ + OnScheduledKeyMapSave(nullptr, nullptr); +} + +void KeyValueStoreManagerImpl::OnScheduledKeyMapSave(System::Layer * systemLayer, void * appState) +{ + SILABSConfig::WriteConfigValueBin(SILABSConfig::kConfigKey_KvsStringKeyMap, + reinterpret_cast(mKvsStoredKeyString), sizeof(mKvsStoredKeyString)); +} + +void KeyValueStoreManagerImpl::ScheduleKeyMapSave(void) +{ + /* + During commissioning, the key map will be modified multiples times subsequently. + Commit the key map in nvm once it as stabilized. + */ + SystemLayer().StartTimer( + std::chrono::duration_cast(System::Clock::Seconds32(SILABS_KVS_SAVE_DELAY_SECONDS)), + KeyValueStoreManagerImpl::OnScheduledKeyMapSave, NULL); +} + +CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size, + size_t offset_bytes) const +{ + VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + uint32_t nvm3Key; + CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); + + size_t outLen; + err = SILABSConfig::ReadConfigValueBin(nvm3Key, reinterpret_cast(value), value_size, outLen, offset_bytes); + if (read_bytes_size) + { + *read_bytes_size = outLen; + } + + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + } + + return err; +} + +CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value, size_t value_size) +{ + VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + uint32_t nvm3Key; + CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key, /* isSlotNeeded */ true); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); + + err = SILABSConfig::WriteConfigValueBin(nvm3Key, reinterpret_cast(value), value_size); + if (err == CHIP_NO_ERROR) + { + uint32_t keyIndex = nvm3Key - SILABSConfig::kConfigKey_KvsFirstKeySlot; + Platform::CopyString(mKvsStoredKeyString[keyIndex], key); + ScheduleKeyMapSave(); + } + + return err; +} + +CHIP_ERROR KeyValueStoreManagerImpl::_Delete(const char * key) +{ + VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + uint32_t nvm3Key; + CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); + + err = SILABSConfig::ClearConfigValue(nvm3Key); + if (err == CHIP_NO_ERROR) + { + uint32_t keyIndex = CONVERT_NVM3KEY_TO_KEYMAP_INDEX(nvm3Key); + memset(mKvsStoredKeyString[keyIndex], 0, sizeof(mKvsStoredKeyString[keyIndex])); + ScheduleKeyMapSave(); + } + + return err; +} + +CHIP_ERROR KeyValueStoreManagerImpl::ErasePartition(void) +{ + // Iterate over all the Matter Kvs nvm3 records and delete each one... + CHIP_ERROR err = CHIP_NO_ERROR; + for (uint32_t nvm3Key = SILABSConfig::kMinConfigKey_MatterKvs; nvm3Key < SILABSConfig::kMaxConfigKey_MatterKvs; nvm3Key++) + { + err = SILABSConfig::ClearConfigValue(nvm3Key); + + if (err != CHIP_NO_ERROR) + { + break; + } + } + + memset(mKvsStoredKeyString, 0, sizeof(mKvsStoredKeyString)); + return err; +} + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp b/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp new file mode 100644 index 00000000000000..f07fd947d03c17 --- /dev/null +++ b/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp @@ -0,0 +1,335 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OTAImageProcessorImpl.h" +#include +#include + +extern "C" { +#include "btl_interface.h" +#include "em_bus.h" // For CORE_CRITICAL_SECTION +} + +#include + +/// No error, operation OK +#define SL_BOOTLOADER_OK 0L + +namespace chip { + +// Define static memebers +uint8_t OTAImageProcessorImpl::mSlotId = 0; +uint32_t OTAImageProcessorImpl::mWriteOffset = 0; +uint16_t OTAImageProcessorImpl::writeBufOffset = 0; +uint8_t OTAImageProcessorImpl::writeBuffer[kAlignmentBytes] __attribute__((aligned(4))) = { 0 }; + +CHIP_ERROR OTAImageProcessorImpl::PrepareDownload() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandlePrepareDownload, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Finalize() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleFinalize, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} +CHIP_ERROR OTAImageProcessorImpl::Apply() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleApply, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Abort() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleAbort, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block) +{ + if ((block.data() == nullptr) || block.empty()) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + // Store block data for HandleProcessBlock to access + CHIP_ERROR err = SetBlock(block); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Cannot set block data: %" CHIP_ERROR_FORMAT, err.Format()); + } + + DeviceLayer::PlatformMgr().ScheduleWork(HandleProcessBlock, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +bool OTAImageProcessorImpl::IsFirstImageRun() +{ + OTARequestorInterface * requestor = chip::GetRequestorInstance(); + if (requestor == nullptr) + { + return false; + } + + return requestor->GetCurrentUpdateState() == OTARequestorInterface::OTAUpdateStateEnum::kApplying; +} + +CHIP_ERROR OTAImageProcessorImpl::ConfirmCurrentImage() +{ + OTARequestorInterface * requestor = chip::GetRequestorInstance(); + if (requestor == nullptr) + { + return CHIP_ERROR_INTERNAL; + } + + uint32_t currentVersion; + uint32_t targetVersion = requestor->GetTargetVersion(); + ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSoftwareVersion(currentVersion)); + if (currentVersion != targetVersion) + { + ChipLogError(SoftwareUpdate, "Current software version = %" PRIu32 ", expected software version = %" PRIu32, currentVersion, + targetVersion); + return CHIP_ERROR_INCORRECT_STATE; + } + + return CHIP_NO_ERROR; +} + +void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) +{ + int32_t err = SL_BOOTLOADER_OK; + auto * imageProcessor = reinterpret_cast(context); + + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + else if (imageProcessor->mDownloader == nullptr) + { + ChipLogError(SoftwareUpdate, "mDownloader is null"); + return; + } + + ChipLogProgress(SoftwareUpdate, "HandlePrepareDownload"); + + CORE_CRITICAL_SECTION(bootloader_init();) + mSlotId = 0; // Single slot until we support multiple images + writeBufOffset = 0; + mWriteOffset = 0; + imageProcessor->mParams.downloadedBytes = 0; + + imageProcessor->mHeaderParser.Init(); + + // Not calling bootloader_eraseStorageSlot(mSlotId) here because we erase during each write + + imageProcessor->mDownloader->OnPreparedForDownload(err == SL_BOOTLOADER_OK ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL); +} + +void OTAImageProcessorImpl::HandleFinalize(intptr_t context) +{ + uint32_t err = SL_BOOTLOADER_OK; + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + return; + } + + // Pad the remainder of the write buffer with zeros and write it to bootloader storage + if (writeBufOffset != 0) + { + // Account for last bytes of the image not yet written to storage + imageProcessor->mParams.downloadedBytes += writeBufOffset; + + while (writeBufOffset != kAlignmentBytes) + { + writeBuffer[writeBufOffset] = 0; + writeBufOffset++; + } + + CORE_CRITICAL_SECTION(err = bootloader_eraseWriteStorage(mSlotId, mWriteOffset, writeBuffer, kAlignmentBytes);) + if (err) + { + ChipLogError(SoftwareUpdate, "ERROR: In HandleFinalize bootloader_eraseWriteStorage() error %ld", err); + imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); + return; + } + } + + imageProcessor->ReleaseBlock(); + + ChipLogProgress(SoftwareUpdate, "OTA image downloaded successfully"); +} + +void OTAImageProcessorImpl::HandleApply(intptr_t context) +{ + uint32_t err = SL_BOOTLOADER_OK; + + ChipLogProgress(SoftwareUpdate, "OTAImageProcessorImpl::HandleApply()"); + + // Force KVS to store pending keys such as data from StoreCurrentUpdateInfo() + chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().ForceKeyMapSave(); + + CORE_CRITICAL_SECTION(err = bootloader_verifyImage(mSlotId, NULL);) + if (err != SL_BOOTLOADER_OK) + { + ChipLogError(SoftwareUpdate, "ERROR: bootloader_verifyImage() error %ld", err); + + return; + } + + CORE_CRITICAL_SECTION(err = bootloader_setImageToBootload(mSlotId);) + if (err != SL_BOOTLOADER_OK) + { + ChipLogError(SoftwareUpdate, "ERROR: bootloader_setImageToBootload() error %ld", err); + + return; + } + + // This reboots the device + CORE_CRITICAL_SECTION(bootloader_rebootAndInstall();) +} + +void OTAImageProcessorImpl::HandleAbort(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + return; + } + + // Not clearing the image storage area as it is done during each write + imageProcessor->ReleaseBlock(); +} + +void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) +{ + uint32_t err = SL_BOOTLOADER_OK; + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + else if (imageProcessor->mDownloader == nullptr) + { + ChipLogError(SoftwareUpdate, "mDownloader is null"); + return; + } + + ByteSpan block = imageProcessor->mBlock; + CHIP_ERROR chip_error = imageProcessor->ProcessHeader(block); + + if (chip_error != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Matter image header parser error %s", chip::ErrorStr(chip_error)); + imageProcessor->mDownloader->EndDownload(CHIP_ERROR_INVALID_FILE_IDENTIFIER); + return; + } + + // Copy data into the word-aligned writeBuffer, once it fills write its contents to the bootloader storage + // Final data block is handled in HandleFinalize(). + uint32_t blockReadOffset = 0; + while (blockReadOffset < block.size()) + { + writeBuffer[writeBufOffset] = *((block.data()) + blockReadOffset); + writeBufOffset++; + blockReadOffset++; + if (writeBufOffset == kAlignmentBytes) + { + writeBufOffset = 0; + + CORE_CRITICAL_SECTION(err = bootloader_eraseWriteStorage(mSlotId, mWriteOffset, writeBuffer, kAlignmentBytes);) + if (err) + { + ChipLogError(SoftwareUpdate, "ERROR: In HandleProcessBlock bootloader_eraseWriteStorage() error %ld", err); + imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); + return; + } + mWriteOffset += kAlignmentBytes; + imageProcessor->mParams.downloadedBytes += kAlignmentBytes; + } + } + + imageProcessor->mDownloader->FetchNextData(); +} + +CHIP_ERROR OTAImageProcessorImpl::ProcessHeader(ByteSpan & block) +{ + if (mHeaderParser.IsInitialized()) + { + OTAImageHeader header; + CHIP_ERROR error = mHeaderParser.AccumulateAndDecode(block, header); + + // Needs more data to decode the header + ReturnErrorCodeIf(error == CHIP_ERROR_BUFFER_TOO_SMALL, CHIP_NO_ERROR); + ReturnErrorOnFailure(error); + + // SL TODO -- store version somewhere + ChipLogProgress(SoftwareUpdate, "Image Header software version: %ld payload size: %lu", header.mSoftwareVersion, + (long unsigned int) header.mPayloadSize); + mParams.totalFileBytes = header.mPayloadSize; + mHeaderParser.Clear(); + } + return CHIP_NO_ERROR; +} + +// Store block data for HandleProcessBlock to access +CHIP_ERROR OTAImageProcessorImpl::SetBlock(ByteSpan & block) +{ + if ((block.data() == nullptr) || block.empty()) + { + return CHIP_NO_ERROR; + } + + // Allocate memory for block data if we don't have enough already + if (mBlock.size() < block.size()) + { + ReleaseBlock(); + + mBlock = MutableByteSpan(static_cast(chip::Platform::MemoryAlloc(block.size())), block.size()); + if (mBlock.data() == nullptr) + { + return CHIP_ERROR_NO_MEMORY; + } + } + + // Store the actual block data + CHIP_ERROR err = CopySpanToMutableSpan(block, mBlock); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Cannot copy block data: %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::ReleaseBlock() +{ + if (mBlock.data() != nullptr) + { + chip::Platform::MemoryFree(mBlock.data()); + } + + mBlock = MutableByteSpan(); + return CHIP_NO_ERROR; +} + +} // namespace chip diff --git a/src/platform/silabs/SiWx917/OTAImageProcessorImpl.h b/src/platform/silabs/SiWx917/OTAImageProcessorImpl.h new file mode 100644 index 00000000000000..30709bd7f32f3a --- /dev/null +++ b/src/platform/silabs/SiWx917/OTAImageProcessorImpl.h @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace chip { + +class OTAImageProcessorImpl : public OTAImageProcessorInterface +{ +public: + //////////// OTAImageProcessorInterface Implementation /////////////// + CHIP_ERROR PrepareDownload() override; + CHIP_ERROR Finalize() override; + CHIP_ERROR Apply() override; + CHIP_ERROR Abort() override; + CHIP_ERROR ProcessBlock(ByteSpan & block) override; + bool IsFirstImageRun() override; + CHIP_ERROR ConfirmCurrentImage() override; + + void SetOTADownloader(OTADownloader * downloader) { mDownloader = downloader; } + void SetOTAImageFile(const char * imageFile) { mImageFile = imageFile; } + +private: + //////////// Actual handlers for the OTAImageProcessorInterface /////////////// + static void HandlePrepareDownload(intptr_t context); + static void HandleFinalize(intptr_t context); + static void HandleApply(intptr_t context); + static void HandleAbort(intptr_t context); + static void HandleProcessBlock(intptr_t context); + CHIP_ERROR ProcessHeader(ByteSpan & block); + + /** + * Called to allocate memory for mBlock if necessary and set it to block + */ + CHIP_ERROR SetBlock(ByteSpan & block); + + /** + * Called to release allocated memory for mBlock + */ + CHIP_ERROR ReleaseBlock(); + + // EFR32 platform creates a single instance of OTAImageProcessorImpl class. + // If that changes then the use of static members and functions must be revisited + static uint32_t mWriteOffset; // End of last written block + static uint8_t mSlotId; // Bootloader storage slot + MutableByteSpan mBlock; + OTADownloader * mDownloader; + OTAImageHeaderParser mHeaderParser; + const char * mImageFile = nullptr; + static constexpr size_t kAlignmentBytes = 64; + // Intermediate, word-aligned buffer for writing to the bootloader storage. + // Bootloader storage API requires the buffer size to be a multiple of 4. + static uint8_t writeBuffer[kAlignmentBytes] __attribute__((aligned(4))); + // Offset indicates how far the write buffer has been filled + static uint16_t writeBufOffset; +}; + +} // namespace chip diff --git a/src/platform/silabs/SiWx917/PlatformManagerImpl.cpp b/src/platform/silabs/SiWx917/PlatformManagerImpl.cpp new file mode 100644 index 00000000000000..25de6d51d164b2 --- /dev/null +++ b/src/platform/silabs/SiWx917/PlatformManagerImpl.cpp @@ -0,0 +1,163 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Nest Labs, Inc. + * + * 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 + * for Silabs platforms using the Silicon Labs SDK. + */ +/* this file behaves like a config.h, comes first */ +#include + +#include +#include +#include +#include +#include + +#if CHIP_SYSTEM_CONFIG_USE_LWIP +#include +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP + +#include "AppConfig.h" +#include "FreeRTOS.h" + +namespace chip { +namespace DeviceLayer { + +PlatformManagerImpl PlatformManagerImpl::sInstance; + +CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) +{ + CHIP_ERROR err; + + // Initialize the configuration system. + err = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(); + SuccessOrExit(err); + +#if CHIP_SYSTEM_CONFIG_USE_LWIP + // Initialize LwIP. + tcpip_init(NULL, NULL); +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP + + ReturnErrorOnFailure(System::Clock::InitClock_RealTime()); + + // Call _InitChipStack() on the generic implementation base class + // to finish the initialization process. + err = Internal::GenericPlatformManagerImpl_FreeRTOS::_InitChipStack(); + SuccessOrExit(err); + +exit: + return err; +} + +void PlatformManagerImpl::_Shutdown() +{ + uint64_t upTime = 0; + + if (GetDiagnosticDataProvider().GetUpTime(upTime) == CHIP_NO_ERROR) + { + uint32_t totalOperationalHours = 0; + + if (ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours) == CHIP_NO_ERROR) + { + ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + static_cast(upTime / 3600)); + } + else + { + ChipLogError(DeviceLayer, "Failed to get total operational hours of the Node"); + } + } + else + { + ChipLogError(DeviceLayer, "Failed to get current uptime since the Node’s last reboot"); + } + + Internal::GenericPlatformManagerImpl_FreeRTOS::_Shutdown(); +} +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION +void PlatformManagerImpl::HandleWFXSystemEvent(wfx_event_base_t eventBase, sl_wfx_generic_message_t * eventData) +{ + ChipDeviceEvent event; + memset(&event, 0, sizeof(event)); + event.Type = DeviceEventType::kWFXSystemEvent; + event.Platform.WFXSystemEvent.eventBase = eventBase; + + if (eventBase == WIFI_EVENT) + { + switch (eventData->header.id) + { + case SL_WFX_STARTUP_IND_ID: + memcpy(&event.Platform.WFXSystemEvent.data.startupEvent, eventData, + sizeof(event.Platform.WFXSystemEvent.data.startupEvent)); + break; + case SL_WFX_CONNECT_IND_ID: + memcpy(&event.Platform.WFXSystemEvent.data.connectEvent, eventData, + sizeof(event.Platform.WFXSystemEvent.data.connectEvent)); + break; + case SL_WFX_DISCONNECT_IND_ID: + memcpy(&event.Platform.WFXSystemEvent.data.disconnectEvent, eventData, + sizeof(event.Platform.WFXSystemEvent.data.disconnectEvent)); + break; + // case SL_WFX_RECEIVED_IND_ID: + // memcpy(&event.Platform.WFXSystemEvent.data.receivedEvent, eventData, + // sizeof(event.Platform.WFXSystemEvent.data.receivedEvent)); + // break; + // case SL_WFX_GENERIC_IND_ID: + // memcpy(&event.Platform.WFXSystemEvent.data.genericEvent, eventData, + // sizeof(event.Platform.WFXSystemEvent.data.genericEvent)); + // break; + // case SL_WFX_EXCEPTION_IND_ID: + // memcpy(&event.Platform.WFXSystemEvent.data.exceptionEvent, eventData, + // sizeof(event.Platform.WFXSystemEvent.data.exceptionEvent)); + // break; + // case SL_WFX_ERROR_IND_ID: + // memcpy(&event.Platform.WFXSystemEvent.data.errorEvent, eventData, + // sizeof(event.Platform.WFXSystemEvent.data.errorEvent)); + // break; + default: + break; + } + } + else if (eventBase == IP_EVENT) + { + switch (eventData->header.id) + { + case IP_EVENT_STA_GOT_IP: + memcpy(&event.Platform.WFXSystemEvent.data.genericMsgEvent, eventData, + sizeof(event.Platform.WFXSystemEvent.data.genericMsgEvent)); + break; + case IP_EVENT_GOT_IP6: + memcpy(&event.Platform.WFXSystemEvent.data.genericMsgEvent, eventData, + sizeof(event.Platform.WFXSystemEvent.data.genericMsgEvent)); + break; + case IP_EVENT_STA_LOST_IP: + memcpy(&event.Platform.WFXSystemEvent.data.genericMsgEvent, eventData, + sizeof(event.Platform.WFXSystemEvent.data.genericMsgEvent)); + break; + default: + break; + } + } + + (void) sInstance.PostEvent(&event); +} +#endif + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/silabs/SiWx917/ThreadStackManagerImpl.cpp b/src/platform/silabs/SiWx917/ThreadStackManagerImpl.cpp new file mode 100644 index 00000000000000..16d792276644e4 --- /dev/null +++ b/src/platform/silabs/SiWx917/ThreadStackManagerImpl.cpp @@ -0,0 +1,173 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Nest Labs, Inc. + * + * 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 ThreadStackManager object for + * EFR32 platforms using the Silicon Labs SDK and the OpenThread + * stack. + * + */ +/* this file behaves like a config.h, comes first */ +#include + +#include +#include +#include +#include + +#include + +#include + +namespace chip { +namespace DeviceLayer { + +using namespace ::chip::DeviceLayer::Internal; + +ThreadStackManagerImpl ThreadStackManagerImpl::sInstance; + +CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack(void) +{ + return InitThreadStack(NULL); +} + +CHIP_ERROR ThreadStackManagerImpl::InitThreadStack(otInstance * otInst) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // Initialize the generic implementation base classes. + err = GenericThreadStackManagerImpl_FreeRTOS::DoInit(); + SuccessOrExit(err); + err = GenericThreadStackManagerImpl_OpenThread::DoInit(otInst); + SuccessOrExit(err); + +exit: + return err; +} + +bool ThreadStackManagerImpl::IsInitialized() +{ + return sInstance.mThreadStackLock != NULL; +} + +} // namespace DeviceLayer +} // namespace chip + +using namespace ::chip::DeviceLayer; + +/** + * Glue function called directly by the OpenThread stack when tasklet processing work + * is pending. + */ +extern "C" void otTaskletsSignalPending(otInstance * p_instance) +{ + ThreadStackMgrImpl().SignalThreadActivityPending(); +} + +/** + * Glue function called directly by the OpenThread stack when system event processing work + * is pending. + */ +extern "C" void otSysEventSignalPending(void) +{ + BaseType_t yieldRequired = ThreadStackMgrImpl().SignalThreadActivityPendingFromISR(); + portYIELD_FROM_ISR(yieldRequired); +} + +extern "C" void * otPlatCAlloc(size_t aNum, size_t aSize) +{ + return CHIPPlatformMemoryCalloc(aNum, aSize); +} + +extern "C" void otPlatFree(void * aPtr) +{ + CHIPPlatformMemoryFree(aPtr); +} + +extern "C" __WEAK void sl_openthread_init(void) +{ + // Place holder for enabling Silabs specific features available only through Simplicity Studio +} + +/** + * @brief Openthread UART implementation for the CLI is conflicting + * with the UART implemented for Pigweed RPC as they use the same UART port + * + * We now only build the uart as implemented in + * connectedhomeip/examples/platform/efr32/uart.c + * and remap OT functions to use our uart api. + * + * For now OT CLI isn't usable when the examples are built with pw_rpc + */ + +#ifndef PW_RPC_ENABLED +#include "uart.h" +#endif + +extern "C" otError otPlatUartEnable(void) +{ +#ifdef PW_RPC_ENABLED + return OT_ERROR_NOT_IMPLEMENTED; +#else + uartConsoleInit(); + return OT_ERROR_NONE; +#endif +} + +#if CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI + +extern "C" otError otPlatUartSend(const uint8_t * aBuf, uint16_t aBufLength) +{ +#ifdef PW_RPC_ENABLED + return OT_ERROR_NOT_IMPLEMENTED; +#else + if (uartConsoleWrite((const char *) aBuf, aBufLength) > 0) + { + otPlatUartSendDone(); + return OT_ERROR_NONE; + } + return OT_ERROR_FAILED; +#endif +} + +extern "C" void efr32UartProcess(void) +{ +#if !defined(PW_RPC_ENABLED) && !defined(ENABLE_CHIP_SHELL) + uint8_t tempBuf[128] = { 0 }; + // will read the data available up to 128bytes + uint16_t count = uartConsoleRead((char *) tempBuf, 128); + if (count > 0) + { + // ot process Received data for CLI cmds + otPlatUartReceived(tempBuf, count); + } +#endif +} + +extern "C" __WEAK otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + +extern "C" __WEAK otError otPlatUartDisable(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + +#endif // CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI diff --git a/src/platform/silabs/SiWx917/args.gni b/src/platform/silabs/SiWx917/args.gni new file mode 100644 index 00000000000000..6e7ac8dcb49e51 --- /dev/null +++ b/src/platform/silabs/SiWx917/args.gni @@ -0,0 +1,61 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/efr32_sdk.gni") +import("//build_overrides/pigweed.gni") + +import("${chip_root}/examples/platform/silabs/efr32/args.gni") +import("${chip_root}/src/crypto/crypto.gni") + +# ARM architecture flags will be set based on silabs_family. +arm_platform_config = "${efr32_sdk_build_root}/efr32_arm.gni" + +mbedtls_target = "${efr32_sdk_build_root}:efr32_sdk" + +openthread_external_mbedtls = mbedtls_target + +# default to platform crypto implementation but allow commandline override +if (chip_crypto == "") { + chip_crypto = "platform" +} + +chip_device_platform = "efr32" + +#Net work configuration OpenThread +lwip_platform = "efr32" +chip_mdns = "platform" +chip_inet_config_enable_ipv4 = false +chip_inet_config_enable_tcp_endpoint = false +chip_system_config_use_open_thread_inet_endpoints = true +chip_with_lwip = false + +chip_build_tests = false + +# Transitional CommissionableDataProvider not used anymore +# examples/platform/silabs/efr32/EFR32DeviceDataProvider is now used. +chip_use_transitional_commissionable_data_provider = false + +openthread_root = "${chip_root}/third_party/openthread/ot-efr32/openthread" +openthread_core_config_platform_check_file = + "openthread-core-efr32-config-check.h" +openthread_project_core_config_file = "OpenThreadConfig.h" +openthread_core_config_deps = [ "${chip_root}/examples/platform/silabs/efr32:openthread_core_config_efr32_chip_examples" ] + +chip_config_memory_management = "platform" + +pw_build_LINK_DEPS = [ + "$dir_pw_assert:impl", + "$dir_pw_log:impl", +] diff --git a/src/platform/silabs/SiWx917/efr32-chip-mbedtls-config.h b/src/platform/silabs/SiWx917/efr32-chip-mbedtls-config.h new file mode 100644 index 00000000000000..049c12cb084a65 --- /dev/null +++ b/src/platform/silabs/SiWx917/efr32-chip-mbedtls-config.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include + +#include "em_device.h" +#include "em_se.h" + +#if CHIP_HAVE_CONFIG_H +#include +#endif // CHIP_HAVE_CONFIG_H + +/** + * Enable H Crypto and Entropy modules + */ +#define MBEDTLS_AES_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_SHA224_C +#define MBEDTLS_SHA256_C + +#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf + +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CCM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CMAC_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ECDH_LEGACY_CONTEXT +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECDSA_DETERMINISTIC +#define MBEDTLS_ECJPAKE_C +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_ENTROPY_FORCE_SHA256 +#define MBEDTLS_ENTROPY_HARDWARE_ALT +#define MBEDTLS_ERROR_STRERROR_DUMMY +#define MBEDTLS_HAVE_ASM +#define MBEDTLS_HKDF_C +#define MBEDTLS_HMAC_DRBG_C +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED +#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#define MBEDTLS_MD_C +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PEM_WRITE_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PK_WRITE_C +#if CHIP_CRYPTO_MBEDTLS +#define MBEDTLS_PKCS5_C +#endif +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_PSA_CRYPTO_C +#define MBEDTLS_PSA_CRYPTO_CONFIG +#define MBEDTLS_PSA_CRYPTO_DRIVERS +#define MBEDTLS_PSA_CRYPTO_STORAGE_C +#define MBEDTLS_SHA256_SMALLER +#define MBEDTLS_SHA512_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_COOKIE_C +#define MBEDTLS_SSL_DTLS_ANTI_REPLAY +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY +#define MBEDTLS_SSL_EXPORT_KEYS +#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_PROTO_DTLS +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C + +#if CHIP_CRYPTO_PLATFORM +#define MBEDTLS_USE_PSA_CRYPTO +#endif + +#define MBEDTLS_X509_CREATE_C +#define MBEDTLS_X509_CSR_WRITE_C +#define MBEDTLS_X509_CRL_PARSE_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_CSR_PARSE_C +#define MBEDTLS_X509_USE_C + +#define MBEDTLS_MPI_WINDOW_SIZE 1 /**< Maximum windows size used. */ +#define MBEDTLS_MPI_MAX_SIZE 32 /**< Maximum number of bytes for usable MPIs. */ +#define MBEDTLS_ECP_MAX_BITS 256 /**< Maximum bit size of groups */ +#define MBEDTLS_ECP_WINDOW_SIZE 2 /**< Maximum window size used */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Enable fixed-point speed-up */ +#define MBEDTLS_ENTROPY_MAX_SOURCES 2 /**< Maximum number of sources supported */ + +#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#define MBEDTLS_SSL_MAX_CONTENT_LEN 900 /**< Maxium fragment length in bytes */ +#else +#define MBEDTLS_SSL_MAX_CONTENT_LEN 768 /**< Maxium fragment length in bytes */ +#endif + +#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + +#define MBEDTLS_CIPHER_MODE_WITH_PADDING + +#include "check_crypto_config.h" +#include "config-device-acceleration.h" +#include "mbedtls/check_config.h" +#include "mbedtls/config_psa.h" diff --git a/src/platform/silabs/SiWx917/efr32-mbedtls-psa-crypto-config.h b/src/platform/silabs/SiWx917/efr32-mbedtls-psa-crypto-config.h new file mode 100644 index 00000000000000..6df9724afa0808 --- /dev/null +++ b/src/platform/silabs/SiWx917/efr32-mbedtls-psa-crypto-config.h @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// ADD USER PSA CRYPTO CONFIG HERE +#define SL_PSA_KEY_USER_SLOT_COUNT (4) + +#define SL_PSA_ITS_USER_MAX_FILES (128) + +#include "em_device.h" +#if defined(SEMAILBOX_PRESENT) || defined(CRYPTOACC_PRESENT) +// Use accelerated HMAC when we have it +#define MBEDTLS_PSA_ACCEL_ALG_HMAC +// Use accelerated ECDSA/ECDH when we have it +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY +#define MBEDTLS_PSA_ACCEL_ECC_SECP_R1_256 +#define MBEDTLS_PSA_ACCEL_ALG_ECDH +#define MBEDTLS_PSA_ACCEL_ALG_ECDSA +#else +// Devices without SEMAILBOX or CRYPTOACC don't have HMAC top-level accelerated +#define MBEDTLS_PSA_BUILTIN_ALG_HMAC 1 +// Devices without SEMAILBOX or CRYPTOACC don't have fully implemented ECDSA/ECDH +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR 1 +#define MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_256 1 +#define MBEDTLS_PSA_BUILTIN_ALG_ECDH 1 +#define MBEDTLS_PSA_BUILTIN_ALG_ECDSA 1 +#endif +// end of user configuration section >>> + +// AUTO GENERATED PSA CONFIG SECTION BELOW. **KEEP AS IS FUTURE GSDK UPDATE** +#define PSA_WANT_KEY_TYPE_AES +#define PSA_WANT_ALG_CMAC +#define PSA_WANT_ALG_SHA_256 +#define PSA_WANT_ALG_CCM +#define PSA_WANT_ALG_ECB_NO_PADDING +#define PSA_WANT_ALG_ECDSA +#define PSA_WANT_ALG_ECDH +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR +#define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY +#define PSA_WANT_ECC_SECP_R1_256 +#define PSA_WANT_ALG_HKDF +#define PSA_WANT_ALG_HMAC +#define PSA_WANT_KEY_TYPE_HMAC +#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG +#define MBEDTLS_PSA_ACCEL_ALG_SHA_1 +#define MBEDTLS_PSA_ACCEL_ALG_SHA_224 +#define MBEDTLS_PSA_ACCEL_ALG_SHA_256 +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_AES +#define MBEDTLS_PSA_ACCEL_ALG_ECB_NO_PADDING +#define MBEDTLS_PSA_ACCEL_ALG_CBC_NO_PADDING +#define MBEDTLS_PSA_ACCEL_ALG_CBC_PKCS7 +#define MBEDTLS_PSA_ACCEL_ALG_CTR +#define MBEDTLS_PSA_ACCEL_ALG_CFB +#define MBEDTLS_PSA_ACCEL_ALG_OFB +#define MBEDTLS_PSA_ACCEL_ALG_GCM +#define MBEDTLS_PSA_ACCEL_ALG_CCM +#define MBEDTLS_PSA_ACCEL_ALG_CMAC + +#define MBEDTLS_PSA_KEY_SLOT_COUNT (15 + 1 + SL_PSA_KEY_USER_SLOT_COUNT) +#define SL_PSA_ITS_MAX_FILES (1 + SL_PSA_ITS_USER_MAX_FILES) diff --git a/src/platform/silabs/SiWx917/wifi/dhcp_client.cpp b/src/platform/silabs/SiWx917/wifi/dhcp_client.cpp new file mode 100644 index 00000000000000..15c678515a0e62 --- /dev/null +++ b/src/platform/silabs/SiWx917/wifi/dhcp_client.cpp @@ -0,0 +1,149 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if LWIP_IPV4 && LWIP_DHCP + +#include +#include +#include + +#include "em_bus.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" + +#include "dhcp_client.h" +#include "lwip/dhcp.h" +#include "wfx_host_events.h" +#include "wifi_config.h" + +#include "AppConfig.h" +#include "FreeRTOS.h" +#include "event_groups.h" + +#define MAX_DHCP_TRIES 4 +#define NETIF_IPV4_ADDRESS(X, Y) (((X) >> (8 * Y)) & 0xFF) + +/* Station IP address */ +uint8_t sta_ip_addr0 = STA_IP_ADDR0_DEFAULT; +uint8_t sta_ip_addr1 = STA_IP_ADDR1_DEFAULT; +uint8_t sta_ip_addr2 = STA_IP_ADDR2_DEFAULT; +uint8_t sta_ip_addr3 = STA_IP_ADDR3_DEFAULT; +uint8_t sta_netmask_addr0 = STA_NETMASK_ADDR0_DEFAULT; +uint8_t sta_netmask_addr1 = STA_NETMASK_ADDR1_DEFAULT; +uint8_t sta_netmask_addr2 = STA_NETMASK_ADDR2_DEFAULT; +uint8_t sta_netmask_addr3 = STA_NETMASK_ADDR3_DEFAULT; +uint8_t sta_gw_addr0 = STA_GW_ADDR0_DEFAULT; +uint8_t sta_gw_addr1 = STA_GW_ADDR1_DEFAULT; +uint8_t sta_gw_addr2 = STA_GW_ADDR2_DEFAULT; +uint8_t sta_gw_addr3 = STA_GW_ADDR3_DEFAULT; + +/// Current DHCP state machine state. +static volatile uint8_t dhcp_state = DHCP_OFF; + +/***************************************************************************** + * @fn void dhcpclient_set_link_state(int link_up) + * @brief + * Notify DHCP client task about the wifi status + * @param link_up link status + * @return None + ******************************************************************************/ +void dhcpclient_set_link_state(int link_up) +{ + if (link_up) + { + dhcp_state = DHCP_START; + SILABS_LOG("DHCP: Starting"); + } + else + { + /* Update DHCP state machine */ + dhcp_state = DHCP_LINK_DOWN; + } +} + +/********************************************************************************** + * @fn uint8_t dhcpclient_poll(void *arg) + * @brief + * Don't need a task here. We get polled every 250ms + * @return None + ************************************************************************************/ +uint8_t dhcpclient_poll(void * arg) +{ + struct netif * netif = (struct netif *) arg; + ip_addr_t ipaddr; + ip_addr_t netmask; + ip_addr_t gw; + struct dhcp * dhcp; + + switch (dhcp_state) + { + case DHCP_START: + SILABS_LOG("DHCP: Wait addr"); + ip_addr_set_zero_ip4(&netif->ip_addr); + ip_addr_set_zero_ip4(&netif->netmask); + ip_addr_set_zero_ip4(&netif->gw); + dhcp_start(netif); + dhcp_state = DHCP_WAIT_ADDRESS; + break; + + case DHCP_WAIT_ADDRESS: + if (dhcp_supplied_address(netif)) + { + dhcp_state = DHCP_ADDRESS_ASSIGNED; + + uint64_t addr = netif->ip_addr.u_addr.ip4.addr; + SILABS_LOG("DHCP IP: %d.%d.%d.%d", NETIF_IPV4_ADDRESS(addr, 0), NETIF_IPV4_ADDRESS(addr, 1), + NETIF_IPV4_ADDRESS(addr, 2), NETIF_IPV4_ADDRESS(addr, 3)); + } + else + { + dhcp = (struct dhcp *) netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP); + + /* DHCP timeout */ + if (dhcp->tries > MAX_DHCP_TRIES) + { + dhcp_state = DHCP_TIMEOUT; + + SILABS_LOG("*ERR*DHCP: Failed"); + /* Stop DHCP */ + dhcp_stop(netif); + + /* TODO - I am not sure that this is best */ + /* Static address used */ + IP_ADDR4(&ipaddr, sta_ip_addr0, sta_ip_addr1, sta_ip_addr2, sta_ip_addr3); + IP_ADDR4(&netmask, sta_netmask_addr0, sta_netmask_addr1, sta_netmask_addr2, sta_netmask_addr3); + IP_ADDR4(&gw, sta_gw_addr0, sta_gw_addr1, sta_gw_addr2, sta_gw_addr3); + netif_set_addr(netif, ip_2_ip4(&ipaddr), ip_2_ip4(&netmask), ip_2_ip4(&gw)); + } + } + break; + + case DHCP_LINK_DOWN: + /* Stop DHCP */ + SILABS_LOG("*ERR*DHCP Link down"); + dhcp_stop(netif); + dhcp_state = DHCP_OFF; + break; + default: + break; + } + return dhcp_state; +} + +#endif /* LWIP_IPV4 && LWIP_DHCP */ diff --git a/src/platform/silabs/SiWx917/wifi/dhcp_client.h b/src/platform/silabs/SiWx917/wifi/dhcp_client.h new file mode 100644 index 00000000000000..3040f7112fb954 --- /dev/null +++ b/src/platform/silabs/SiWx917/wifi/dhcp_client.h @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if LWIP_IPV4 && LWIP_DHCP + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +// DHCP client states +#define DHCP_OFF (uint8_t) 0 +#define DHCP_START (uint8_t) 1 +#define DHCP_WAIT_ADDRESS (uint8_t) 2 +#define DHCP_ADDRESS_ASSIGNED (uint8_t) 3 +#define DHCP_TIMEOUT (uint8_t) 4 +#define DHCP_LINK_DOWN (uint8_t) 5 + +/***************************************************************************** + * @fn void dhcpclient_set_link_state(int link_up) + * @brief + * Notify DHCP client task about the wifi status + * @param link_up link status + ******************************************************************************/ +void dhcpclient_set_link_state(int link_up); +uint8_t dhcpclient_poll(void * arg); +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 && LWIP_DHCP */ diff --git a/src/platform/silabs/SiWx917/wifi/ethernetif.cpp b/src/platform/silabs/SiWx917/wifi/ethernetif.cpp new file mode 100644 index 00000000000000..d1fcc01f3c4f9b --- /dev/null +++ b/src/platform/silabs/SiWx917/wifi/ethernetif.cpp @@ -0,0 +1,461 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Includes */ + +#include +#include +#include + +#include "em_bus.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" + +#ifndef WF200_WIFI +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" +#endif + +#include "wfx_host_events.h" +#include "wifi_config.h" +#ifdef WF200_WIFI +#include "sl_wfx.h" +#endif +/* LwIP includes. */ +#include "ethernetif.h" +#include "lwip/ethip6.h" +#include "lwip/timeouts.h" +#include "netif/etharp.h" + +#ifndef SILABS_LOG +extern "C" { +void efr32Log(const char * aFormat, ...); +#define SILABS_LOG(...) efr32Log(__VA_ARGS__); +} +#endif + +StaticSemaphore_t xEthernetIfSemaBuffer; + +/***************************************************************************** + * Defines + ******************************************************************************/ +#define STATION_NETIF0 's' +#define STATION_NETIF1 't' + +#define LWIP_FRAME_ALIGNMENT 60 + +uint32_t gOverrunCount = 0; + +/***************************************************************************** + * Variables + ******************************************************************************/ + +/***************************************************************************** + * @fn static void low_level_init(struct netif *netif) + * @brief + * Initializes the hardware parameters. Called from ethernetif_init(). + * + * @param[in] netif: the already initialized lwip network interface structure + * + * @return + * None + ******************************************************************************/ +static void low_level_init(struct netif * netif) +{ + /* set netif MAC hardware address length */ + netif->hwaddr_len = ETH_HWADDR_LEN; + + /* Set netif MAC hardware address */ + sl_wfx_mac_address_t mac_addr; + + wfx_get_wifi_mac_addr(SL_WFX_STA_INTERFACE, &mac_addr); + + netif->hwaddr[0] = mac_addr.octet[0]; + netif->hwaddr[1] = mac_addr.octet[1]; + netif->hwaddr[2] = mac_addr.octet[2]; + netif->hwaddr[3] = mac_addr.octet[3]; + netif->hwaddr[4] = mac_addr.octet[4]; + netif->hwaddr[5] = mac_addr.octet[5]; + + /* Set netif maximum transfer unit */ + netif->mtu = 1500; + + /* Accept broadcast address and ARP traffic */ + netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; + +#if LWIP_IPV6_MLD + netif->flags |= NETIF_FLAG_MLD6; +#endif /* LWIP_IPV6_MLD */ +} + +/******************************************************************************** + * @fn static void low_level_input(struct netif *netif, uint8_t *b, uint16_t len) + * @brief + * Make PBUF out of a linear buffer - that can be fed into lwip + * @param[in] netif: the already initialized lwip network interface structure + * @param[in] len: length + * @return + * None + ************************************************************************************/ +static void low_level_input(struct netif * netif, uint8_t * b, uint16_t len) +{ + struct pbuf *p, *q; + uint32_t bufferoffset; + + if (len <= 0) + { + return; + } + if (len < LWIP_FRAME_ALIGNMENT) + { /* 60 : LWIP frame alignment */ + len = LWIP_FRAME_ALIGNMENT; + } + + /* Drop packets originated from the same interface and is not destined for the said interface */ + const uint8_t * src_mac = b + netif->hwaddr_len; + const uint8_t * dst_mac = b; + + if (!(ip6_addr_ispreferred(netif_ip6_addr_state(netif, 0))) && (memcmp(netif->hwaddr, src_mac, netif->hwaddr_len) == 0) && + (memcmp(netif->hwaddr, dst_mac, netif->hwaddr_len) != 0)) + { +#ifdef WIFI_DEBUG_ENABLED + SILABS_LOG("%s: DROP, [%02x:%02x:%02x:%02x:%02x:%02x]<-[%02x:%02x:%02x:%02x:%02x:%02x] type=%02x%02x", __func__, + + dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], + + src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5], + + b[12], b[13]); +#endif + return; + } + + /* We allocate a pbuf chain of pbufs from the Lwip buffer pool + * and copy the data to the pbuf chain + */ + if ((p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL)) != STRUCT_PBUF) + { + for (q = p, bufferoffset = 0; q != NULL; q = q->next) + { + memcpy((uint8_t *) q->payload, (uint8_t *) b + bufferoffset, q->len); + bufferoffset += q->len; + } +#ifdef WIFI_DEBUG_ENABLED + SILABS_LOG("%s: ACCEPT %d, [%02x:%02x:%02x:%02x:%02x:%02x]<-[%02x:%02x:%02x:%02x:%02x:%02x] type=%02x%02x", __func__, + bufferoffset, + + dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], + + src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5], + + b[12], b[13]); +#endif + + if (netif->input(p, netif) != ERR_OK) + { + gOverrunCount++; + SILABS_LOG("overrun count entering when fail to alloc value %d", gOverrunCount); + pbuf_free(p); + } + } + else + { + gOverrunCount++; + SILABS_LOG("overrun count entering when fail to alloc value %d", gOverrunCount); + } +} + +/***************************************************************************** + * @fn static err_t low_level_output(struct netif *netif, struct pbuf *p) + * @brief + * This function should does the actual transmission of the packet(s). + * The packet is contained in the pbuf that is passed to the function. + * This pbuf might be chained. + * + * @param[in] netif: the lwip network interface structure + * + * @param[in] p: the packet to send + * + * @return + * ERR_OK if successful + ******************************************************************************/ +#ifdef WF200_WIFI +static err_t low_level_output(struct netif * netif, struct pbuf * p) +{ + struct pbuf * q; + sl_wfx_send_frame_req_t * tx_buffer; + uint8_t * buffer; + uint32_t framelength, asize; + uint32_t bufferoffset; + uint32_t padding; + sl_status_t result; + + for (q = p, framelength = 0; q != NULL; q = q->next) + { + framelength += q->len; + } + if (framelength < LWIP_FRAME_ALIGNMENT) + { /* 60 : Frame alignment for LWIP */ + padding = LWIP_FRAME_ALIGNMENT - framelength; + } + else + { + padding = 0; + } + + /* choose padding of 64 */ + asize = SL_WFX_ROUND_UP(framelength + padding, 64) + sizeof(sl_wfx_send_frame_req_t); + // 12 is size of other data in buffer struct, user shouldn't have to care about this? + if (sl_wfx_host_allocate_buffer((void **) &tx_buffer, SL_WFX_TX_FRAME_BUFFER, asize) != SL_STATUS_OK) + { + SILABS_LOG("*ERR*EN-Out: No mem frame len=%d", framelength); + gOverrunCount++; + SILABS_LOG("overrun count exiting when faied to alloc value %d", gOverrunCount); + return ERR_MEM; + } + buffer = tx_buffer->body.packet_data; + /* copy frame from pbufs to driver buffers */ + for (q = p, bufferoffset = 0; q != NULL; q = q->next) + { + /* Get bytes in current lwIP buffer */ + memcpy((uint8_t *) ((uint8_t *) buffer + bufferoffset), (uint8_t *) ((uint8_t *) q->payload), q->len); + bufferoffset += q->len; + } + /* No requirement to do this - but we should for security */ + if (padding) + { + memset(buffer + bufferoffset, 0, padding); + framelength += padding; + } + /* transmit */ + int i = 0; + result = SL_STATUS_FAIL; + +#ifdef WIFI_DEBUG_ENABLED + SILABS_LOG("WF200: Out %d", (int) framelength); +#endif + + /* send the generated frame over Wifi network */ + while ((result != SL_STATUS_OK) && (i++ < 10)) + { + result = sl_wfx_send_ethernet_frame(tx_buffer, framelength, SL_WFX_STA_INTERFACE, PRIORITY_0); + } + sl_wfx_host_free_buffer(tx_buffer, SL_WFX_TX_FRAME_BUFFER); + + if (result != SL_STATUS_OK) + { + SILABS_LOG("*ERR*Send enet %d", (int) framelength); + return ERR_IF; + } + return ERR_OK; +} + +/***************************************************************************** + * @fn void sl_wfx_host_received_frame_callback(sl_wfx_received_ind_t *rx_buffer) + * @brief + * This function implements the wf200 received frame callback. + * Called from the context of the bus_task (not ISR) + * + * @param[in] rx_buffer: the ethernet frame received by the wf200 + * + * @return + * None + ******************************************************************************/ +void sl_wfx_host_received_frame_callback(sl_wfx_received_ind_t * rx_buffer) +{ + struct netif * netif; + + /* Check packet interface to send to AP or STA interface */ + if ((rx_buffer->header.info & SL_WFX_MSG_INFO_INTERFACE_MASK) == (SL_WFX_STA_INTERFACE << SL_WFX_MSG_INFO_INTERFACE_OFFSET)) + { + + /* Send received frame to station interface */ + if ((netif = wfx_get_netif(SL_WFX_STA_INTERFACE)) != NULL) + { + uint8_t * buffer; + uint16_t len; + + len = rx_buffer->body.frame_length; + buffer = (uint8_t *) &(rx_buffer->body.frame[rx_buffer->body.frame_padding]); + +#ifdef WIFI_DEBUG_ENABLED + SILABS_LOG("WF200: In %d", (int) len); +#endif + + low_level_input(netif, buffer, len); + } + else + { +#ifdef WIFI_DEBUG_ENABLED + SILABS_LOG("WF200: NO-INTF"); +#endif + } + } + else + { +#ifdef WIFI_DEBUG_ENABLED + SILABS_LOG("WF200: Invalid frame IN"); +#endif + } +} + +#else /* For RS911x - using LWIP */ +static SemaphoreHandle_t ethout_sem; +/***************************************************************************** + * @fn static err_t low_level_output(struct netif *netif, struct pbuf *p) + * @brief + * This function is called from LWIP task when LWIP stack + * has some data to be forwarded over WiFi Network + * + * @param[in] netif: lwip network interface + * + * @param[in] p: the packet to send + * + * @return + * ERR_OK if successful + ******************************************************************************/ +static err_t low_level_output(struct netif * netif, struct pbuf * p) +{ + void * rsipkt; + struct pbuf * q; + uint16_t framelength; + + if (xSemaphoreTake(ethout_sem, portMAX_DELAY) != pdTRUE) + { + return ERR_IF; + } +#ifdef WIFI_DEBUG_ENABLED + SILABS_LOG("EN-RSI: Output"); +#endif + if ((netif->flags & (NETIF_FLAG_LINK_UP | NETIF_FLAG_UP)) != (NETIF_FLAG_LINK_UP | NETIF_FLAG_UP)) + { + SILABS_LOG("EN-RSI:NOT UP"); + xSemaphoreGive(ethout_sem); + return ERR_IF; + } + /* Confirm if packet is allocated */ + rsipkt = wfx_rsi_alloc_pkt(); + if (!rsipkt) + { + SILABS_LOG("EN-RSI:No buf"); + xSemaphoreGive(ethout_sem); + return ERR_IF; + } + +#ifdef WIFI_DEBUG_ENABLED + uint8_t * b = (uint8_t *) p->payload; + SILABS_LOG("EN-RSI: Out [%02x:%02x:%02x:%02x:%02x:%02x][%02x:%02x:%02x:%02x:%02x:%02x]type=%02x%02x", b[0], b[1], b[2], b[3], + b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13]); +#endif + /* Generate the packet */ + for (q = p, framelength = 0; q != NULL; q = q->next) + { + wfx_rsi_pkt_add_data(rsipkt, (uint8_t *) (q->payload), (uint16_t) q->len, framelength); + framelength += q->len; + } + if (framelength < LWIP_FRAME_ALIGNMENT) + { + /* Add junk data to the end for frame alignment if framelength is less than 60 */ + wfx_rsi_pkt_add_data(rsipkt, (uint8_t *) (p->payload), LWIP_FRAME_ALIGNMENT - framelength, framelength); + } +#ifdef WIFI_DEBUG_ENABLED + SILABS_LOG("EN-RSI: Sending %d", framelength); +#endif + + /* forward the generated packet to RSI to + * send the data over wifi network + */ + if (wfx_rsi_send_data(rsipkt, framelength)) + { + SILABS_LOG("*ERR*EN-RSI:Send fail"); + xSemaphoreGive(ethout_sem); + return ERR_IF; + } + +#ifdef WIFI_DEBUG_ENABLED + SILABS_LOG("EN-RSI:Xmit %d", framelength); +#endif + xSemaphoreGive(ethout_sem); + + return ERR_OK; +} + +/***************************************************************************** + * @fn void wfx_host_received_sta_frame_cb(uint8_t *buf, int len) + * @brief + * host received frame cb + * + * @param[in] buf: buffer + * + * @param[in] len: length + * + * @return + * None + ******************************************************************************/ +void wfx_host_received_sta_frame_cb(uint8_t * buf, int len) +{ + struct netif * ifp; + + /* get the network interface for STATION interface, + * and forward the received frame buffer to LWIP + */ + if ((ifp = wfx_get_netif(SL_WFX_STA_INTERFACE)) != (struct netif *) 0) + { + low_level_input(ifp, buf, len); + } +} + +#endif /* RS911x - with LWIP */ + +/***************************************************************************** + * @fn err_t sta_ethernetif_init(struct netif *netif) + * @brief + * sta ethernet if initialization + * + * @param[in] netif: the lwip network interface structure + * + * @return + * ERR_OK if successful + ******************************************************************************/ +err_t sta_ethernetif_init(struct netif * netif) +{ + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + /* Set the netif name to identify the interface */ + netif->name[0] = STATION_NETIF0; + netif->name[1] = STATION_NETIF1; + +#if LWIP_IPV4 && LWIP_ARP + netif->output = etharp_output; +#endif /* #if LWIP_IPV4 && LWIP_ARP */ +#if LWIP_IPV6 && LWIP_ETHERNET + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 && LWIP_ETHERNET */ + netif->linkoutput = low_level_output; + + /* initialize the hardware */ + low_level_init(netif); +#ifndef WF200_WIFI + /* Need single output only */ + ethout_sem = xSemaphoreCreateBinaryStatic(&xEthernetIfSemaBuffer); + xSemaphoreGive(ethout_sem); +#endif + return ERR_OK; +} diff --git a/src/platform/silabs/SiWx917/wifi/ethernetif.h b/src/platform/silabs/SiWx917/wifi/ethernetif.h new file mode 100644 index 00000000000000..dfea1ea6ad3540 --- /dev/null +++ b/src/platform/silabs/SiWx917/wifi/ethernetif.h @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "lwip/err.h" +#include "lwip/netif.h" +#ifdef __cplusplus +extern "C" { +#endif +/*************************************************************************** + * @fn err_t sta_ethernetif_init(struct netif *netif) + * @brief + * Sets up the station network interface. + * + * @param netif the lwip network interface structure + * @returns ERR_OK if successful + ******************************************************************************/ +err_t sta_ethernetif_init(struct netif * netif); + +/*************************************************************************** + * @fn err_t ap_ethernetif_init(struct netif *netif + * @brief + * Sets up the AP network interface. + * + * @param netif the lwip network interface structure + * @returns ERR_OK if successful + ******************************************************************************/ +err_t ap_ethernetif_init(struct netif * netif); + +#ifdef WF200_WIFI +void sl_wfx_host_received_frame_callback(sl_wfx_received_ind_t * rx_buffer); +#else +void wfx_host_received_sta_frame_cb(uint8_t * buf, int len); +#endif /* WF200_WIFI */ +#ifdef __cplusplus +} +#endif diff --git a/src/platform/silabs/SiWx917/wifi/lwip_netif.cpp b/src/platform/silabs/SiWx917/wifi/lwip_netif.cpp new file mode 100644 index 00000000000000..e19cf97a7cefd2 --- /dev/null +++ b/src/platform/silabs/SiWx917/wifi/lwip_netif.cpp @@ -0,0 +1,159 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RS911X_SOCKETS +#include +#include +#include + +#include "em_bus.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" + +#include "wfx_host_events.h" +#include "wifi_config.h" + +#include "AppConfig.h" +#include "dhcp_client.h" +#include "ethernetif.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" + +#include +using namespace ::chip; +using namespace ::chip::DeviceLayer; +static struct netif sta_netif; + +#ifdef SL_WFX_CONFIG_SOFTAP +static struct netif ap_netif; +#endif + +/**************************************************************************** + * @fn static void netif_config(struct netif *sta_if, struct netif *ap_if) + * @brief + * netif configuration + * @param[in] sta_if: + * @param[in] ap_if: + * @return None + *****************************************************************************/ +static void netif_config(struct netif * sta_if, struct netif * ap_if) +{ + if (sta_if != NULL) + { +#if LWIP_IPV4 + ip_addr_t sta_ipaddr; + ip_addr_t sta_netmask; + ip_addr_t sta_gw; + + /* Initialize the Station information */ + ip_addr_set_zero_ip4(&sta_ipaddr); + ip_addr_set_zero_ip4(&sta_netmask); + ip_addr_set_zero_ip4(&sta_gw); +#endif /* LWIP_IPV4 */ + + /* Add station interfaces */ + netif_add(sta_if, +#if LWIP_IPV4 + (const ip4_addr_t *) &sta_ipaddr, (const ip4_addr_t *) &sta_netmask, (const ip4_addr_t *) &sta_gw, +#endif /* LWIP_IPV4 */ + NULL, &sta_ethernetif_init, &tcpip_input); + + /* Registers the default network interface */ + netif_set_default(sta_if); + } +} + +/**************************************************************************** + * @fn void wfx_lwip_set_sta_link_up(void) + * @brief + * Set station link status to up. + * @param[in] None + * @return None + *****************************************************************************/ +void wfx_lwip_set_sta_link_up(void) +{ + netifapi_netif_set_up(&sta_netif); + netifapi_netif_set_link_up(&sta_netif); +#if LWIP_IPV4 && LWIP_DHCP + dhcpclient_set_link_state(LINK_UP); +#endif /* LWIP_IPV4 && LWIP_DHCP */ + /* + * Enable IPV6 + */ + +#if LWIP_IPV6_AUTOCONFIG + sta_netif.ip6_autoconfig_enabled = 1; +#endif /* LWIP_IPV6_AUTOCONFIG */ + netif_create_ip6_linklocal_address(&sta_netif, MAC_48_BIT_SET); +} + +/*************************************************************************** + * @fn void wfx_lwip_set_sta_link_down(void) + * @brief + * Set station link status to down. + * @param[in] None + * @return None + *****************************************************************************/ +void wfx_lwip_set_sta_link_down(void) +{ +#if LWIP_IPV4 && LWIP_DHCP + dhcpclient_set_link_state(LINK_DOWN); +#endif /* LWIP_IPV4 && LWIP_DHCP */ + netifapi_netif_set_link_down(&sta_netif); + netifapi_netif_set_down(&sta_netif); +} + +/*************************************************************************** + * @fn void wfx_lwip_start(void) + * @brief + * Initialize the LwIP stack + * @param[in] None + * @return None + *****************************************************************************/ +void wfx_lwip_start(void) +{ + /* Initialize the LwIP stack */ + netif_config(&sta_netif, NULL); +} + +/*************************************************************************** + * @fn struct netif *wfx_get_netif(sl_wfx_interface_t interface) + * @brief + * get the netif + * @param[in] interface: + * @return None + *****************************************************************************/ +struct netif * wfx_get_netif(sl_wfx_interface_t interface) +{ + if (interface == SL_WFX_STA_INTERFACE) + { + return &sta_netif; + } +#ifdef SL_WFX_CONFIG_SOFTAP + else if (interface == SL_WFX_SOFTAP_INTERFACE) + { + return &ap_netif; + } +#endif + return (struct netif *) 0; +} + +#endif /* RS911X_SOCKETS */ diff --git a/src/platform/silabs/SiWx917/wifi/wfx_host_events.h b/src/platform/silabs/SiWx917/wifi/wfx_host_events.h new file mode 100644 index 00000000000000..5a7e8617a661e2 --- /dev/null +++ b/src/platform/silabs/SiWx917/wifi/wfx_host_events.h @@ -0,0 +1,375 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifdef WF200_WIFI +#include "FreeRTOS.h" +#include "event_groups.h" +#include "semphr.h" +#include "task.h" +#include "timers.h" + +#include "sl_wfx_cmd_api.h" +#include "sl_wfx_constants.h" + +typedef struct __attribute__((__packed__)) sl_wfx_get_counters_cnf_body_s +{ + uint32_t status; + uint16_t mib_id; + uint16_t length; + uint32_t rcpi; + uint32_t count_plcp_errors; + uint32_t count_fcs_errors; + uint32_t count_tx_packets; + uint32_t count_rx_packets; + uint32_t count_rx_packet_errors; + uint32_t count_rx_decryption_failures; + uint32_t count_rx_mic_failures; + uint32_t count_rx_no_key_failures; + uint32_t count_tx_multicast_frames; + uint32_t count_tx_frames_success; + uint32_t count_tx_frame_failures; + uint32_t count_tx_frames_retried; + uint32_t count_tx_frames_multi_retried; + uint32_t count_rx_frame_duplicates; + uint32_t count_rts_success; + uint32_t count_rts_failures; + uint32_t count_ack_failures; + uint32_t count_rx_multicast_frames; + uint32_t count_rx_frames_success; + uint32_t count_rx_cmacicv_errors; + uint32_t count_rx_cmac_replays; + uint32_t count_rx_mgmt_ccmp_replays; + uint32_t count_rx_bipmic_errors; + uint32_t count_rx_beacon; + uint32_t count_miss_beacon; + uint32_t reserved[15]; +} sl_wfx_get_counters_cnf_body_t; + +typedef struct __attribute__((__packed__)) sl_wfx_get_counters_cnf_s +{ + /** Common message header. */ + sl_wfx_header_t header; + /** Confirmation message body. */ + sl_wfx_get_counters_cnf_body_t body; +} sl_wfx_get_counters_cnf_t; + +typedef struct __attribute__((__packed__)) sl_wfx_mib_req_body_s +{ + uint16_t mib_id; ///< ID of the MIB to be read. + uint16_t reserved; +} sl_wfx_mib_req_body_t; + +typedef struct __attribute__((__packed__)) sl_wfx_header_mib_s +{ + uint16_t length; ///< Message length in bytes including this uint16_t. + ///< Maximum value is 8188 but maximum Request size is FW dependent and reported in the + ///< ::sl_wfx_startup_ind_body_t::size_inp_ch_buf. + uint8_t id; ///< Contains the message Id indexed by sl_wfx_general_commands_ids_t or sl_wfx_message_ids_t. + uint8_t reserved : 1; + uint8_t interface : 2; + uint8_t seqnum : 3; + uint8_t encrypted : 2; +} sl_wfx_header_mib_t; + +typedef struct __attribute__((__packed__)) sl_wfx_mib_req_s +{ + /** Common message header. */ + sl_wfx_header_mib_t header; + /** Request message body. */ + sl_wfx_mib_req_body_t body; +} sl_wfx_mib_req_t; + +#else /* End WF200 else RS911x */ + +#include "wfx_msgs.h" + +/* Wi-Fi events*/ +#define SL_WFX_STARTUP_IND_ID 1 +#define SL_WFX_CONNECT_IND_ID 2 +#define SL_WFX_DISCONNECT_IND_ID 3 +#define SL_WFX_SCAN_COMPLETE_ID 4 +#define WFX_RSI_SSID_SIZE 64 + +#endif /* WF200 */ + +#ifndef RS911X_SOCKETS +/* LwIP includes. */ +#include "lwip/apps/httpd.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/netifapi.h" +#include "lwip/tcpip.h" + +/* Wi-Fi bitmask events - for the task */ +#define SL_WFX_CONNECT (1 << 1) +#define SL_WFX_DISCONNECT (1 << 2) +#define SL_WFX_START_AP (1 << 3) +#define SL_WFX_STOP_AP (1 << 4) +#define SL_WFX_SCAN_START (1 << 5) +#define SL_WFX_SCAN_COMPLETE (1 << 6) +#define SL_WFX_RETRY_CONNECT (1 << 7) + +#endif /* RS911X_SOCKETS */ + +#include "sl_status.h" + +#ifdef RS911X_WIFI +#define WLAN_TASK_STACK_SIZE 1024 +#define WLAN_TASK_PRIORITY 1 +#define WLAN_DRIVER_TASK_PRIORITY 1 +#define MAX_JOIN_RETRIES_COUNT 5 + +#else /* WF200 */ +#define WLAN_TASK_STACK_SIZE 1024 +#define WLAN_TASK_PRIORITY 1 +#define MAX_JOIN_RETRIES_COUNT 5 +#endif + +// WLAN related Macros +#define ETH_FRAME 0 +#define CMP_SUCCESS 0 +#define BSSID_MAX_STR_LEN 6 +#define MAC_ADDRESS_FIRST_OCTET 6 +#define AP_START_SUCCESS 0 +#define BITS_TO_WAIT 0 +#define CONNECTION_STATUS_SUCCESS 1 +#define IP_STATUS_FAIL 0 +#define GET_IPV6_SUCCESS 1 +#define GET_IPV6_FAIL 0 +#define BEACON_1 0 +#define CHANNEL_LIST (const uint8_t *) 0 +#define CHANNEL_COUNT 0 +#define IE_DATA (const uint8_t *) 0 +#define IE_DATA_LENGTH 0 +#define BSSID_SCAN (const uint8_t *) 0 +#define CHANNEL_0 0 +#define PREVENT_ROAMING 1 +#define DISABLE_PMF_MODE 0 +#define STA_IP_FAIL 0 +#define IP_STATUS_SUCCESS 1 +#define ACTIVE_CHANNEL_TIME_100 100 +#define PASSIVE_CHANNEL_TIME_0 0 +#define PROBE_NUM_REQ_1 1 + +#define PINOUT_CLEAR_STATUS 0 +#define TICKS_TO_WAIT_0 0 +#define TICKS_TO_WAIT_3 3 +#define TICKS_TO_WAIT_1 1 +#define TICKS_TO_WAIT_500 500 + +// TASK and Interrupt Macros +#define SUCCESS_STATUS 1 +#define LINK_UP 1 +#define LINK_DOWN 0 +#define MAC_48_BIT_SET 1 +#define STRUCT_PBUF (struct pbuf *) 0 +#define PRIORITY_0 0 +#define HEX_VALUE_FF 0XFF + +// Timer Delay +#define MAX_XLEN 16 +#define MIN_XLEN 0 +#define PINOUT_CLEAR 0 +#define PINOUT_SET 1 +#define WFX_SPI_NVIC_PRIORITY 5 +#define WFX_GPIO_NVIC_PRIORITY 5 +#define CB_VALUE (DMADRV_Callback_t) 0 + +/* TIMER_TICKS_TO_WAIT Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the start command to be successfully + * sent to the timer command queue. + */ +#define TIMER_TICKS_TO_WAIT_0 0 + +#define CONVERT_SEC_TO_MSEC 1000 +#define CONVERT_USEC_TO_MSEC (1 / 1000) + +#define RSI_RESPONSE_MAX_SIZE 28 +#define RSI_RESPONSE_HOLD_BUFF_SIZE 128 +#define RSI_DRIVER_STATUS 0 +#define OPER_MODE_0 0 +#define COEX_MODE_0 0 +#define RESP_BUFF_SIZE 6 +#define AP_CHANNEL_NO_0 0 +#define SCAN_BITMAP_OPTN_1 1 +#define IP_CONF_RSP_BUFF_LENGTH_4 4 +#define STATION 0 +#define BG_SCAN_RES_SIZE 500 + +#define SPI_CONFIG_SUCCESS 0 +#define WPA3_SECURITY 3 + +typedef enum +{ + WIFI_EVENT, + IP_EVENT, +} wfx_event_base_t; + +typedef enum +{ + IP_EVENT_STA_GOT_IP, + IP_EVENT_GOT_IP6, + IP_EVENT_STA_LOST_IP, +} ip_event_id_t; + +/* Note that these are same as RSI_security */ +typedef enum +{ + WFX_SEC_NONE = 0, + WFX_SEC_WPA = 1, + WFX_SEC_WPA2 = 2, + WFX_SEC_WEP = 3, + WFX_SEC_WPA_EAP = 4, + WFX_SEC_WPA2_EAP = 5, + WFX_SEC_WPA_WPA2_MIXED = 6, + WFX_SEC_WPA_PMK = 7, + WFX_SEC_WPA2_PMK = 8, + WFX_SEC_WPS_PIN = 9, + WFX_SEC_GEN_WPS_PIN = 10, + WFX_SEC_PUSH_BTN = 11, + WFX_SEC_WPA3 = 11, +} wfx_sec_t; + +#define WPA3_SECURITY 3 + +typedef struct +{ + char ssid[32 + 1]; + char passkey[64 + 1]; + uint8_t security; +} wfx_wifi_provision_t; + +typedef enum +{ + WIFI_MODE_NULL = 0, + WIFI_MODE_STA, + WIFI_MODE_AP, + WIFI_MODE_APSTA, + WIFI_MODE_MAX, +} wifi_mode_t; + +typedef struct wfx_wifi_scan_result +{ + char ssid[32 + 1]; + uint8_t security; + uint8_t bssid[6]; + uint8_t chan; + int16_t rssi; /* I suspect this is in dBm - so signed */ +} wfx_wifi_scan_result_t; + +typedef struct wfx_wifi_scan_ext +{ + uint32_t beacon_lost_count; + uint32_t beacon_rx_count; + uint32_t mcast_rx_count; + uint32_t mcast_tx_count; + uint32_t ucast_rx_count; + uint32_t ucast_tx_count; + uint32_t overrun_count; +} wfx_wifi_scan_ext_t; + +#ifdef RS911X_WIFI +/* + * This Sh%t is here to support WFXUtils - and the Matter stuff that uses it + * We took it from the SDK (for WF200) + */ +typedef enum +{ + SL_WFX_NOT_INIT = 0, + SL_WFX_STARTED = 1, + SL_WFX_STA_INTERFACE_CONNECTED = 2, + SL_WFX_AP_INTERFACE_UP = 3, + SL_WFX_SLEEPING = 4, + SL_WFX_POWER_SAVE_ACTIVE = 5, +} sl_wfx_state_t; + +typedef enum +{ + SL_WFX_STA_INTERFACE = 0, ///< Interface 0, linked to the station + SL_WFX_SOFTAP_INTERFACE = 1, ///< Interface 1, linked to the softap +} sl_wfx_interface_t; + +#endif /* RS911X_WIFI */ +#ifdef __cplusplus +extern "C" { +#endif + +void sl_wfx_host_gpio_init(void); +sl_status_t wfx_wifi_start(void); +void wfx_enable_sta_mode(void); +sl_wfx_state_t wfx_get_wifi_state(void); +void wfx_get_wifi_mac_addr(sl_wfx_interface_t interface, sl_wfx_mac_address_t * addr); +void wfx_set_wifi_provision(wfx_wifi_provision_t * wifiConfig); +bool wfx_get_wifi_provision(wfx_wifi_provision_t * wifiConfig); +bool wfx_is_sta_provisioned(void); +bool wfx_is_sta_mode_enabled(void); +int32_t wfx_get_ap_info(wfx_wifi_scan_result_t * ap); +int32_t wfx_get_ap_ext(wfx_wifi_scan_ext_t * extra_info); +int32_t wfx_reset_counts(); + +void wfx_clear_wifi_provision(void); +sl_status_t wfx_connect_to_ap(void); +void wfx_setup_ip6_link_local(sl_wfx_interface_t); +bool wfx_is_sta_connected(void); +sl_status_t wfx_sta_discon(void); +#if CHIP_DEVICE_CONFIG_ENABLE_IPV4 +bool wfx_have_ipv4_addr(sl_wfx_interface_t); +#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ +bool wfx_have_ipv6_addr(sl_wfx_interface_t); +wifi_mode_t wfx_get_wifi_mode(void); +bool wfx_start_scan(char * ssid, void (*scan_cb)(wfx_wifi_scan_result_t *)); /* true returned if successfully started */ +void wfx_cancel_scan(void); + +/* + * Call backs into the Matter Platform code + */ +void wfx_started_notify(void); +void wfx_connected_notify(int32_t status, sl_wfx_mac_address_t * ap); +void wfx_disconnected_notify(int32_t status); +/* Implemented for LWIP */ +void wfx_host_received_sta_frame_cb(uint8_t * buf, int len); +void wfx_lwip_set_sta_link_up(void); +void wfx_lwip_set_sta_link_down(void); +void wfx_lwip_start(void); +struct netif * wfx_get_netif(sl_wfx_interface_t interface); +#if CHIP_DEVICE_CONFIG_ENABLE_IPV4 +void wfx_dhcp_got_ipv4(uint32_t); +#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ +bool wfx_hw_ready(void); +#if CHIP_DEVICE_CONFIG_ENABLE_IPV4 +void wfx_ip_changed_notify(int got_ip); +#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ +void wfx_ipv6_notify(int got_ip); + +#ifdef RS911X_WIFI +/* RSI for LWIP */ +void * wfx_rsi_alloc_pkt(void); +void wfx_rsi_pkt_add_data(void * p, uint8_t * buf, uint16_t len, uint16_t off); +int32_t wfx_rsi_send_data(void * p, uint16_t len); +#endif /* RS911X_WIFI */ + +#ifdef WF200_WIFI +void wfx_bus_start(void); +sl_status_t get_all_counters(void); +void sl_wfx_host_gpio_init(void); +sl_status_t sl_wfx_host_process_event(sl_wfx_generic_message_t * event_payload); +#endif +#ifdef __cplusplus +} +#endif diff --git a/src/platform/silabs/SiWx917/wifi/wfx_msgs.h b/src/platform/silabs/SiWx917/wifi/wfx_msgs.h new file mode 100644 index 00000000000000..edf0aec5828fa7 --- /dev/null +++ b/src/platform/silabs/SiWx917/wifi/wfx_msgs.h @@ -0,0 +1,182 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _WFX_MSGS_H_ +#define _WFX_MSGS_H_ +/* + * Taken from sl_wfx firmware - so I can re-use. + * I need to do a better job than to use this stuff + * in the CPP files of Matter + */ +typedef struct +{ + uint8_t octet[6]; ///< Table to store a MAC address +} sl_wfx_mac_address_t; +/** + * @brief General Message header structure + * + */ +typedef struct __attribute__((__packed__)) sl_wfx_header_s +{ + uint16_t length; ///< Message length in bytes including this uint16_t. + ///< Maximum value is 8188 but maximum Request size is FW dependent and reported in the + ///< ::sl_wfx_startup_ind_body_t::size_inp_ch_buf. + uint8_t id; ///< Contains the message Id indexed by sl_wfx_general_commands_ids_t or sl_wfx_message_ids_t. + uint8_t info; ///< TODO comment missing +} sl_wfx_header_t; + +/** + * @brief Generic message structure for all requests, confirmations and indications + * + */ +typedef struct __attribute__((__packed__)) sl_wfx_generic_message_s +{ + sl_wfx_header_t header; ///< 4 bytes header + uint8_t body[]; ///< variable size payload of the message +} sl_wfx_generic_message_t; +#define SL_WFX_OPN_SIZE 14 +#define SL_WFX_UID_SIZE 8 +#define SL_WFX_DISABLED_CHANNEL_LIST_SIZE 2 +#define SL_WFX_FIRMWARE_LABEL_SIZE 128 +/** + * @brief Startup Indication message. + * This is the first message sent to the host to confirm boot success. + * It gives detailed information on the HW and FW versions and capabilities + */ +typedef struct __attribute__((__packed__)) sl_wfx_startup_ind_body_s +{ + uint32_t + status; ///< Initialization status. A value of zero indicates the boot is completed successfully (see enum sl_wfx_status_t) + uint16_t hardware_id; ///<=RO misc_read_reg7 register value +#if 0 /* Not used in RS911x for now - use stuff here for the port */ + uint8_t opn[SL_WFX_OPN_SIZE]; ///<=OTP part_OPN + uint8_t uid[SL_WFX_UID_SIZE]; ///<=OTP UID + uint16_t num_inp_ch_bufs; ///WFM_STATUS_SUCCESS: the connection request was completed successfully. + *
any other value: the connection request failed. + *
See sl_wfx_fmac_status_t for enumeration values. + */ + uint32_t status; + /** + * @brief MAC address of the connected access point. + */ + uint8_t mac[6]; + /** + * @brief Channel of the connected access point. + * @details 1 - 13: Channel number. + */ + uint16_t channel; + /** + * @brief Beacon Interval of the connected access point. + */ + uint8_t beacon_interval; + /** + * @brief DTIM period of the connected access point. + * @details 1 - 255: DTIM period. + */ + uint8_t dtim_period; + /** + * @brief Maximum PHY data rate supported by the connection. + * @details See sl_wfx_rate_index_t for enumeration values. + */ + uint16_t max_phy_rate; +} sl_wfx_connect_ind_body_t; + +/** + * @brief Indication message used to signal the completion of a connection operation. + * @details The device will send this indication to signal the connection request initiated + * with sl_wfx_connect_req_t has been completed. The indication is also sent when + * the device autonomously roams to another access point. + * @ingroup WFM_GROUP_MODE_IDLE + */ +typedef struct __attribute__((__packed__)) sl_wfx_connect_ind_s +{ + /** Common message header. */ + sl_wfx_header_t header; + /** Indication message body. */ + sl_wfx_connect_ind_body_t body; +} sl_wfx_connect_ind_t; +/** + * @brief Indication message body for sl_wfx_disconnect_ind_t. + */ +typedef struct __attribute__((__packed__)) sl_wfx_disconnect_ind_body_s +{ + /** + * @brief MAC address of the access point. + */ + uint8_t mac[6]; + /** + * @brief Reason for disconnection. + * @details WFM_DISCONNECTED_REASON_UNSPECIFIED: The device disconnected because of an internal error. + *
WFM_DISCONNECTED_REASON_AP_LOST: The device lost the AP beacons for too long. + *
WFM_DISCONNECTED_REASON_REJECTED: The device was disconnected by the AP. + *
WFM_DISCONNECTED_REASON_LEAVING_BSS: Disconnection was requested through the device API. + *
WFM_DISCONNECTED_REASON_WPA_COUNTERMEASURES: WPA countermeasures triggered a disconnection + *
See sl_wfx_disconnected_reason_t for enumeration values. + */ + uint16_t reason; +} sl_wfx_disconnect_ind_body_t; + +/** + * @brief Indication message used to signal the completion of a disconnection operation. + * @details The device will send this indication to signal the disconnection request initiated + * with sl_wfx_disconnect_req_t has been completed. The indication is also sent when + * the device has lost the connection to an access point and has been unable to regain it. + * @ingroup WFM_GROUP_MODE_STA + */ +typedef struct __attribute__((__packed__)) sl_wfx_disconnect_ind_s +{ + /** Common message header. */ + sl_wfx_header_t header; + /** Indication message body. */ + sl_wfx_disconnect_ind_body_t body; +} sl_wfx_disconnect_ind_t; + +#endif /* _WFX_MSGS_H_ */ diff --git a/src/platform/silabs/SiWx917/wifi/wfx_notify.cpp b/src/platform/silabs/SiWx917/wifi/wfx_notify.cpp new file mode 100644 index 00000000000000..9f681e796c6d19 --- /dev/null +++ b/src/platform/silabs/SiWx917/wifi/wfx_notify.cpp @@ -0,0 +1,189 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "em_bus.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" +#include "gpiointerrupt.h" + +#include "AppConfig.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" + +#include "wfx_host_events.h" + +#ifdef RS911X_WIFI +#include "wfx_rsi.h" +#endif + +#include +//#include +#include +#include + +using namespace ::chip; +using namespace ::chip::DeviceLayer; + +/* + * Notifications to the upper-layer + * All done in the context of the RSI/WiFi task (rsi_if.c) + */ + +/*********************************************************************************** + * @fn wfx_started_notify() + * @brief + * Wifi device started notification + * @param[in]: None + * @return None + *************************************************************************************/ +void wfx_started_notify() +{ + sl_wfx_startup_ind_t evt; + sl_wfx_mac_address_t mac; + + SILABS_LOG("%s: started.", __func__); + + memset(&evt, 0, sizeof(evt)); + evt.header.id = SL_WFX_STARTUP_IND_ID; + evt.header.length = sizeof evt; + evt.body.status = 0; + wfx_get_wifi_mac_addr(SL_WFX_STA_INTERFACE, &mac); + memcpy(&evt.body.mac_addr[0], &mac.octet[0], MAC_ADDRESS_FIRST_OCTET); + + PlatformMgrImpl().HandleWFXSystemEvent(WIFI_EVENT, (sl_wfx_generic_message_t *) &evt); +} + +/*********************************************************************************** + * @fn void wfx_connected_notify(int32_t status, sl_wfx_mac_address_t *ap) + * @brief + * For now we are not notifying anything other than AP Mac - + * Other stuff such as DTIM etc. may be required for later + * @param[in] status: + * @param[in] ap: access point + * @return None + *************************************************************************************/ +void wfx_connected_notify(int32_t status, sl_wfx_mac_address_t * ap) +{ + sl_wfx_connect_ind_t evt; + + SILABS_LOG("%s: started.", __func__); + + if (status != SUCCESS_STATUS) + { + SILABS_LOG("%s: error: failed status: %d.", __func__, status); + return; + } + + SILABS_LOG("%s: connected.", __func__); + + memset(&evt, 0, sizeof(evt)); + evt.header.id = SL_WFX_CONNECT_IND_ID; + evt.header.length = sizeof evt; + +#ifdef RS911X_WIFI + evt.body.channel = wfx_rsi.ap_chan; +#endif + memcpy(&evt.body.mac[0], &ap->octet[0], MAC_ADDRESS_FIRST_OCTET); + + PlatformMgrImpl().HandleWFXSystemEvent(WIFI_EVENT, (sl_wfx_generic_message_t *) &evt); +} + +/************************************************************************************** + * @fn void wfx_disconnected_notify(int32_t status) + * @brief + * notification of disconnection + * @param[in] status: + * @return None + ********************************************************************************************/ +void wfx_disconnected_notify(int32_t status) +{ + sl_wfx_disconnect_ind_t evt; + + SILABS_LOG("%s: started.", __func__); + + memset(&evt, 0, sizeof(evt)); + evt.header.id = SL_WFX_DISCONNECT_IND_ID; + evt.header.length = sizeof evt; + evt.body.reason = status; + PlatformMgrImpl().HandleWFXSystemEvent(WIFI_EVENT, (sl_wfx_generic_message_t *) &evt); +} + +/************************************************************************************** + * @fn void wfx_ipv6_notify(int got_ip) + * @brief + * notification of ipv6 + * @param[in] got_ip: + * @return None + ********************************************************************************************/ +void wfx_ipv6_notify(int got_ip) +{ + sl_wfx_generic_message_t eventData; + + SILABS_LOG("%s: started.", __func__); + + memset(&eventData, 0, sizeof(eventData)); + eventData.header.id = got_ip ? IP_EVENT_GOT_IP6 : IP_EVENT_STA_LOST_IP; + eventData.header.length = sizeof(eventData.header); + PlatformMgrImpl().HandleWFXSystemEvent(IP_EVENT, &eventData); + + /* So the other threads can run and have the connectivity OK */ + if (got_ip) + { + /* Should remember this */ + vTaskDelay(1); + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::DnssdServer::Instance().StartServer(/*Dnssd::CommissioningMode::kEnabledBasic*/); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + } +} + +/************************************************************************************** + * @fn void wfx_ip_changed_notify(int got_ip) + * @brief + * notification of ip change + * @param[in] got_ip: + * @return None + ********************************************************************************************/ +void wfx_ip_changed_notify(int got_ip) +{ + sl_wfx_generic_message_t eventData; + + SILABS_LOG("%s: started.", __func__); + + memset(&eventData, 0, sizeof(eventData)); + eventData.header.id = got_ip ? IP_EVENT_STA_GOT_IP : IP_EVENT_STA_LOST_IP; + eventData.header.length = sizeof(eventData.header); + PlatformMgrImpl().HandleWFXSystemEvent(IP_EVENT, &eventData); + + /* So the other threads can run and have the connectivity OK */ + if (got_ip) + { + /* Should remember this */ + vTaskDelay(1); + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::DnssdServer::Instance().StartServer(/*Dnssd::CommissioningMode::kEnabledBasic*/); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + } +} diff --git a/src/platform/silabs/SiWx917/wifi/wifi_config.h b/src/platform/silabs/SiWx917/wifi/wifi_config.h new file mode 100644 index 00000000000000..88ad34b5741649 --- /dev/null +++ b/src/platform/silabs/SiWx917/wifi/wifi_config.h @@ -0,0 +1,71 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +#define USE_DHCP_CLIENT_DEFAULT 1 ///< If defined, DHCP is enabled, otherwise static address below is used + +/************************** Station Static Default ****************************/ +#define STA_IP_ADDR0_DEFAULT (uint8_t) 192 ///< Static IP: IP address value 0 +#define STA_IP_ADDR1_DEFAULT (uint8_t) 168 ///< Static IP: IP address value 1 +#define STA_IP_ADDR2_DEFAULT (uint8_t) 0 ///< Static IP: IP address value 2 +#define STA_IP_ADDR3_DEFAULT (uint8_t) 1 ///< Static IP: IP address value 3 + +/*NETMASK*/ +#define STA_NETMASK_ADDR0_DEFAULT (uint8_t) 255 ///< Static IP: Netmask value 0 +#define STA_NETMASK_ADDR1_DEFAULT (uint8_t) 255 ///< Static IP: Netmask value 1 +#define STA_NETMASK_ADDR2_DEFAULT (uint8_t) 255 ///< Static IP: Netmask value 2 +#define STA_NETMASK_ADDR3_DEFAULT (uint8_t) 0 ///< Static IP: Netmask value 3 + +/*Gateway Address*/ +#define STA_GW_ADDR0_DEFAULT (uint8_t) 0 ///< Static IP: Gateway value 0 +#define STA_GW_ADDR1_DEFAULT (uint8_t) 0 ///< Static IP: Gateway value 1 +#define STA_GW_ADDR2_DEFAULT (uint8_t) 0 ///< Static IP: Gateway value 2 +#define STA_GW_ADDR3_DEFAULT (uint8_t) 0 ///< Static IP: Gateway value 3 + +/************************** Access Point Static Default ****************************/ +// #define AP_IP_ADDR0_DEFAULT (uint8_t) 10 ///< Static IP: IP address value 0 +// #define AP_IP_ADDR1_DEFAULT (uint8_t) 10 ///< Static IP: IP address value 1 +// #define AP_IP_ADDR2_DEFAULT (uint8_t) 0 ///< Static IP: IP address value 2 +// #define AP_IP_ADDR3_DEFAULT (uint8_t) 1 ///< Static IP: IP address value 3 + +/*NETMASK*/ +// #define AP_NETMASK_ADDR0_DEFAULT (uint8_t) 255 ///< Static IP: Netmask value 0 +// #define AP_NETMASK_ADDR1_DEFAULT (uint8_t) 255 ///< Static IP: Netmask value 1 +// #define AP_NETMASK_ADDR2_DEFAULT (uint8_t) 255 ///< Static IP: Netmask value 2 +// #define AP_NETMASK_ADDR3_DEFAULT (uint8_t) 0 ///< Static IP: Netmask value 3 + +/*Gateway Address*/ +// #define AP_GW_ADDR0_DEFAULT (uint8_t) 0 ///< Static IP: Gateway value 0 +// #define AP_GW_ADDR1_DEFAULT (uint8_t) 0 ///< Static IP: Gateway value 1 +// #define AP_GW_ADDR2_DEFAULT (uint8_t) 0 ///< Static IP: Gateway value 2 +// #define AP_GW_ADDR3_DEFAULT (uint8_t) 0 ///< Static IP: Gateway value 3 + +#define WLAN_SSID_DEFAULT "AP_name" ///< wifi ssid for client mode +#define WLAN_PASSKEY_DEFAULT "passkey" ///< wifi password for client mode +#define WLAN_SECURITY_DEFAULT WFM_SECURITY_MODE_WPA2_PSK ///< wifi security mode for client mode: +///< WFM_SECURITY_MODE_OPEN/WFM_SECURITY_MODE_WEP/WFM_SECURITY_MODE_WPA2_WPA1_PSK + +#define SOFTAP_SSID_DEFAULT "silabs_softap" ///< wifi ssid for soft ap mode +#define SOFTAP_PASSKEY_DEFAULT "changeme" ///< wifi password for soft ap mode +#define SOFTAP_SECURITY_DEFAULT WFM_SECURITY_MODE_WPA2_PSK ///< wifi security for soft ap mode: +///< WFM_SECURITY_MODE_OPEN/WFM_SECURITY_MODE_WEP/WFM_SECURITY_MODE_WPA2_WPA1_PSK + +#define SOFTAP_CHANNEL_DEFAULT 6 ///< wifi channel for soft ap + +#endif // DEMO_CONFIG_H diff --git a/src/platform/silabs/SiWx917/wifi_args.gni b/src/platform/silabs/SiWx917/wifi_args.gni new file mode 100644 index 00000000000000..73a6613ecdcb4a --- /dev/null +++ b/src/platform/silabs/SiWx917/wifi_args.gni @@ -0,0 +1,58 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/efr32_sdk.gni") +import("//build_overrides/pigweed.gni") + +import("${chip_root}/examples/platform/silabs/efr32/args.gni") +import("${chip_root}/src/crypto/crypto.gni") + +# ARM architecture flags will be set based on silabs_family. +arm_platform_config = "${efr32_sdk_build_root}/efr32_arm.gni" + +mbedtls_target = "${efr32_sdk_build_root}:efr32_sdk" + +# default to platform crypto implementation but allow commandline override +if (chip_crypto == "") { + chip_crypto = "platform" +} + +# Transitional CommissionableDataProvider not used anymore +# examples/platform/efr32/EFR32DeviceDataProvider is now used. +chip_use_transitional_commissionable_data_provider = false + +#lwip_platform = "external" +lwip_platform = "efr32" +lwip_ipv6 = true +lwip_ipv4 = true +lwip_api = true +lwip_ethernet = true + +chip_device_platform = "efr32" +chip_enable_openthread = false +chip_inet_config_enable_ipv4 = true +chip_inet_config_enable_dns_resolver = false +chip_inet_config_enable_tcp_endpoint = true + +chip_build_tests = false +chip_config_memory_management = "platform" +chip_mdns = "minimal" +chip_enable_pw_rpc = false + +pw_build_LINK_DEPS = [ + "$dir_pw_assert:impl", + "$dir_pw_log:impl", +] diff --git a/third_party/silabs/SiWx917_sdk.gni b/third_party/silabs/SiWx917_sdk.gni new file mode 100644 index 00000000000000..38359a7c8a4063 --- /dev/null +++ b/third_party/silabs/SiWx917_sdk.gni @@ -0,0 +1,825 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/efr32_sdk.gni") +import("//build_overrides/jlink.gni") +import("//build_overrides/mbedtls.gni") + +import("${chip_root}/src/lib/lib.gni") +import("silabs_board.gni") + +declare_args() { + # Location of the efr32 SDK. + efr32_sdk_root = "${chip_root}/third_party/silabs/gecko_sdk" + sdk_support_root = "${chip_root}/third_party/silabs/matter_support" + + # Build openthread with prebuilt silabs lib + use_silabs_thread_lib = false + enable_openthread_cli = true + + kvs_max_entries = 75 + use_external_flash = true + + # Use Silabs factory data provider example. + # Users can implement their own. + use_efr32_factory_data_provider = true + + # Enable Segger System View + use_system_view = false +} + +# Explorer Kit and MGM240L do not have external flash +if (silabs_board == "BRD2703A" || silabs_board == "BRD4319A") { + use_external_flash = false +} + +# Enable LEDs by default +use_wstk_leds = true + +# Board does not support LEDs and Buttons at the same time +if (silabs_board == "BRD4317A" || silabs_board == "BRD4316A" || + silabs_board == "BRD4319A") { + use_wstk_leds = false +} + +assert(efr32_sdk_root != "", "efr32_sdk_root must be specified") + +# Defines an efr32 SDK build target. +# +# Parameters: +# efr32_sdk_root - The location of the erf32 SDK. +# sources - The sources files to build. +template("efr32_sdk") { + if (defined(invoker.efr32_sdk_root)) { + efr32_sdk_root = invoker.efr32_sdk_root + } + + assert(efr32_sdk_root != "", "efr32_sdk_root must be specified") + use_wf200 = false + if (defined(invoker.use_wf200)) { + if (invoker.use_wf200) { + use_wf200 = true + } + } + + sdk_target_name = target_name + + config("${sdk_target_name}_config") { + include_dirs = [] + libs = [] + if (defined(invoker.include_dirs)) { + include_dirs += invoker.include_dirs + } + + # Treat these includes as system includes, so warnings in them are not fatal. + _include_dirs = [ + "${efr32_sdk_root}", + "${efr32_sdk_root}/hardware/kit/common/bsp", + "${efr32_sdk_root}/app/common/util/app_assert/", + "${efr32_sdk_root}/hardware/board/inc", + "${efr32_sdk_root}/hardware/driver/memlcd/inc", + "${efr32_sdk_root}/hardware/driver/memlcd/src/ls013b7dh03", + "${efr32_sdk_root}/platform/bootloader", + "${efr32_sdk_root}/platform/bootloader/config", + "${efr32_sdk_root}/platform/bootloader/config/s2/btl_interface", + "${efr32_sdk_root}/platform/bootloader/api", + "${efr32_sdk_root}/platform/CMSIS/Core/Include", + "${efr32_sdk_root}/platform/CMSIS/RTOS2/Include", + "${efr32_sdk_root}/platform/common/inc", + "${efr32_sdk_root}/platform/driver/button/inc", + "${efr32_sdk_root}/platform/emdrv/common/inc", + "${efr32_sdk_root}/platform/emdrv/gpiointerrupt/inc", + "${efr32_sdk_root}/platform/emdrv/dmadrv/config", + "${efr32_sdk_root}/platform/emdrv/dmadrv/inc", + "${efr32_sdk_root}/platform/emdrv/nvm3/inc", + "${efr32_sdk_root}/platform/emdrv/rtcdrv/inc", + "${efr32_sdk_root}/platform/emlib/inc", + "${efr32_sdk_root}/platform/halconfig/inc/hal-config", + "${efr32_sdk_root}/platform/peripheral/inc", + "${efr32_sdk_root}/platform/radio/rail_lib/common", + "${efr32_sdk_root}/platform/radio/rail_lib/chip/efr32", + "${efr32_sdk_root}/platform/radio/rail_lib/chip/efr32/rf/common/cortex", + "${efr32_sdk_root}/platform/radio/rail_lib/hal", + "${efr32_sdk_root}/platform/radio/rail_lib/hal/efr32", + "${efr32_sdk_root}/platform/radio/rail_lib/protocol/ieee802154", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/rail_util_pti", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/rail_util_rf_path", + "${efr32_sdk_root}/platform/service/device_init/inc", + "${efr32_sdk_root}/platform/service/hfxo_manager/config/", + "${efr32_sdk_root}/platform/service/hfxo_manager/inc", + "${efr32_sdk_root}/platform/service/hfxo_manager/src", + "${efr32_sdk_root}/platform/service/mpu/inc", + "${efr32_sdk_root}/platform/service/power_manager/config/", + "${efr32_sdk_root}/platform/service/power_manager/inc/", + "${efr32_sdk_root}/platform/service/power_manager/src/", + "${efr32_sdk_root}/platform/service/sleeptimer/inc", + "${efr32_sdk_root}/platform/service/sleeptimer/config", + "${efr32_sdk_root}/platform/service/system/inc", + "${efr32_sdk_root}/platform/service/udelay/inc", + "${efr32_sdk_root}/platform/service/legacy_hal/inc", + "${efr32_sdk_root}/platform/service/token_manager/config", + "${efr32_sdk_root}/platform/service/token_manager/inc", + "${efr32_sdk_root}/platform/service/token_manager/test", + "${efr32_sdk_root}/platform/service/token_manager/test/include", + "${efr32_sdk_root}/platform/service/token_manager/test/stack/config", + "${efr32_sdk_root}/platform/service/token_manager/test/stack/include", + "${efr32_sdk_root}/platform/middleware/glib", + "${efr32_sdk_root}/platform/middleware/glib/glib", + "${efr32_sdk_root}/platform/middleware/glib/dmd", + "${efr32_sdk_root}/platform/base/hal/plugin/psstore", + "${efr32_sdk_root}/platform/base/hal/plugin/antenna", + "${efr32_sdk_root}/protocol/bluetooth/inc/", + "${efr32_sdk_root}/app/bluetooth/common/in_place_ota_dfu/", + "${efr32_sdk_root}/util/plugin/plugin-common/fem-control", + "${efr32_sdk_root}/util/silicon_labs/silabs_core/graphics", + "${efr32_sdk_root}/util/silicon_labs/silabs_core/memory_manager", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/include", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/include/psa", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_alt/include", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_protocol_crypto/src", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/inc", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/config/", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/inc", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/inc/public", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/inc", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/", + "${efr32_sdk_root}/util/third_party/freertos/cmsis/Include", + "${efr32_sdk_root}/util/third_party/freertos/kernel/include", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/config", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen", + ] + + # Note that we're setting the mbedTLS and PSA configuration files through a + # define. This means the build system by default does not pick up changes in + # the content of these, only when changing the filename itself. + # To fix this, these files are also manually depended upon in the source set + # declared in efr32_mbedtls_config further down this file. + defines = [ + "MBEDTLS_CONFIG_FILE=\"efr32-chip-mbedtls-config.h\"", + "MBEDTLS_PSA_CRYPTO_CONFIG_FILE=\"efr32-mbedtls-psa-crypto-config.h\"", + "__STARTUP_CLEAR_BSS", + "HARD_FAULT_LOG_ENABLE", + "CORTEXM3_EFM32_MICRO", + "EFR32_LOG_ENABLED=1", + "NVM3_DEFAULT_NVM_SIZE=40960", + "NVM3_DEFAULT_MAX_OBJECT_SIZE=4092", + "KVS_MAX_ENTRIES=${kvs_max_entries}", + "EFR32_OPENTHREAD_API", + "PHY=EMBER_PHY_RAIL", + "CORTEXM3", + "MICRO=EMBER_MICRO_CORTEXM3_EFR32", + "PLAT=EMBER_PLATFORM_CORTEXM3", + "${silabs_mcu}=1", + "${silabs_board}=1", + "__HEAP_SIZE=0", + "SL_CATALOG_FREERTOS_KERNEL_PRESENT=1", + "MBEDTLS_THREADING_C=1", + "MBEDTLS_THREADING_ALT=1", + "SL_THREADING_ALT=1", + "SL_COMPONENT_CATALOG_PRESENT", + "PLATFORM_HEADER=\"platform-header.h\"", + "USE_NVM3=1", + + #"__STACK_SIZE=0", + ] + + if (use_system_view) { + _include_dirs += [ + "${efr32_sdk_root}/util/third_party/segger/systemview/SEGGER", + "${efr32_sdk_root}/util/third_party/segger/systemview/Sample/FreeRTOSV10/Config/Cortex-M", + "${efr32_sdk_root}/util/third_party/segger/systemview/Sample/FreeRTOSV10", + "${efr32_sdk_root}/util/third_party/segger/systemview/Config/", + ] + + defines += [ "SL_SYSTEM_VIEW=1" ] + } + + defines += board_defines + + if (use_wstk_leds) { + _include_dirs += [ "${efr32_sdk_root}/platform/driver/leddrv/inc" ] + + defines += [ "ENABLE_WSTK_LEDS" ] + } + + if (defined(invoker.enable_sleepy_device)) { + if (invoker.enable_sleepy_device) { + defines += [ + "CHIP_DEVICE_CONFIG_ENABLE_SED=1", + "SL_CATALOG_POWER_MANAGER_PRESENT", + "SL_CATALOG_SLEEPTIMER_PRESENT", + ] + } + } + + if (chip_build_libshell) { # matter shell + defines += [ + "ENABLE_CHIP_SHELL", + "OPENTHREAD_CONFIG_CLI_TRANSPORT=OT_CLI_TRANSPORT_CONSOLE", + "CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI=1", + ] + } else { + if (enable_openthread_cli) { # ot-cli only + defines += [ "CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI=1" ] + } + } + + # USART include files + if ((defined(invoker.chip_enable_pw_rpc) && invoker.chip_enable_pw_rpc) || + chip_build_libshell || enable_openthread_cli || + (defined(invoker.chip_enable_wifi) && invoker.chip_enable_wifi) || + (defined(invoker.show_qr_code) && invoker.show_qr_code) || + (defined(invoker.disable_lcd) && !invoker.disable_lcd) || + (defined(invoker.use_external_flash) && use_external_flash)) { + defines += [ "CONFIG_ENABLE_UART" ] + + if (defined(invoker.use_external_flash) && use_external_flash) { + defines += [ "CONFIG_USE_EXTERNAL_FLASH" ] + + _include_dirs += [ "${efr32_sdk_root}/hardware/driver/mx25_flash_shutdown/inc/sl_mx25_flash_shutdown_usart" ] + } + + _include_dirs += [ + "${efr32_sdk_root}/platform/emdrv/uartdrv/inc", + "${efr32_sdk_root}/platform/emdrv/uartdrv/config", + "${efr32_sdk_root}/hardware/driver/memlcd/inc/memlcd_usart", + ] + } + + if (silabs_family == "efr32mg12") { + _include_dirs += [ + "${efr32_sdk_root}/platform/Device/SiliconLabs/EFR32MG12P/Include", + "${efr32_sdk_root}/platform/radio/rail_lib/chip/efr32/efr32xg1x", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM4F", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions/efr32xg1x/config", + "${efr32_sdk_root}/platform/service/device_init/config/s1/", + "${efr32_sdk_root}/platform/emdrv/spidrv/inc", + ] + + libs += [ + "${sdk_support_root}/protocol/bluetooth/lib/EFR32MG12P/GCC/binapploader.o", + "${sdk_support_root}/protocol/bluetooth/lib/EFR32MG12P/GCC/libbluetooth.a", + "${sdk_support_root}/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg12_gcc_release.a", + "${sdk_support_root}/platform/emdrv/nvm3/lib/libnvm3_CM4_gcc.a", + ] + + defines += [ "EFR32MG12" ] + } else if (silabs_family == "efr32mg21") { + _include_dirs += [ + "${efr32_sdk_root}/platform/Device/SiliconLabs/EFR32MG21/Include", + "${efr32_sdk_root}/platform/radio/rail_lib/chip/efr32/efr32xg2x", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM33_NTZ/non_secure", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions/efr32xg21", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions/efr32xg21/config", + "${efr32_sdk_root}/platform/service/device_init/config/s2/", + ] + + libs += [ + "${sdk_support_root}/protocol/bluetooth/lib/EFR32MG21/GCC/binapploader.o", + "${sdk_support_root}/protocol/bluetooth/lib/EFR32MG21/GCC/libbluetooth.a", + "${sdk_support_root}/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg21_gcc_release.a", + "${sdk_support_root}/platform/emdrv/nvm3/lib/libnvm3_CM33_gcc.a", + ] + + defines += [ + "EFR32MG21", + "EFR32_SERIES2_CONFIG1_MICRO", + ] + } else if (silabs_family == "efr32mg24") { + _include_dirs += [ + "${efr32_sdk_root}/platform/Device/SiliconLabs/EFR32MG24/Include", + "${efr32_sdk_root}/platform/radio/rail_lib/chip/efr32/efr32xg2x", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM33_NTZ/non_secure", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions/efr32xg24", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions/efr32xg24/config", + "${efr32_sdk_root}/platform/service/device_init/config/s2/", + "${efr32_sdk_root}/platform/emdrv/spidrv/inc", + ] + + libs += [ + "${sdk_support_root}/protocol/bluetooth/lib/EFR32MG24/GCC/libapploader.a", + "${sdk_support_root}/protocol/bluetooth/lib/EFR32MG24/GCC/libbluetooth.a", + "${sdk_support_root}/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg24_gcc_release.a", + "${sdk_support_root}/platform/emdrv/nvm3/lib/libnvm3_CM33_gcc.a", + ] + + defines += [ + "EFR32MG24", + "EFR32_SERIES2_CONFIG4_MICRO", + ] + } else if (silabs_family == "mgm24") { + _include_dirs += [ + "${efr32_sdk_root}/platform/Device/SiliconLabs/MGM24/Include", + "${efr32_sdk_root}/platform/radio/rail_lib/chip/efr32/efr32xg2x", + "${efr32_sdk_root}/platform/radio/rail_lib/protocol/ble", + "${efr32_sdk_root}/platform/radio/rail_lib/protocol/ieee802154", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM33_NTZ/non_secure", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions/efr32xg24", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions/efr32xg24/config", + "${efr32_sdk_root}/platform/service/device_init/config/s2/", + ] + + libs += [ + "${sdk_support_root}/protocol/bluetooth/lib/EFR32MG24/GCC/libapploader.a", + "${sdk_support_root}/protocol/bluetooth/lib/EFR32MG24/GCC/libbluetooth.a", + "${sdk_support_root}/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg24_gcc_release.a", + "${sdk_support_root}/platform/emdrv/nvm3/lib/libnvm3_CM33_gcc.a", + ] + + if (silabs_mcu == "MGM240PB32VNA") { + libs += [ "${sdk_support_root}/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb32vna_gcc.a" ] + } else if (silabs_mcu == "MGM240PB22VNA") { + libs += [ "${sdk_support_root}/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb22vna_gcc.a" ] + } else if (silabs_mcu == "MGM240L022RNF") { + libs += [ "${sdk_support_root}/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022rnf_gcc.a" ] + } + + defines += [ + "MGM24", + "EFR32_SERIES2_CONFIG4_MICRO", + ] + } + + if (use_wf200) { + _include_dirs += [ + "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver", + "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/bus", + "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/firmware", + "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/pds/brd8022a", + "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/secure_link", + ] + } + + cflags = [] + foreach(include_dir, _include_dirs) { + cflags += [ "-isystem" + rebase_path(include_dir, root_build_dir) ] + } + + cflags += [ + "-Wno-maybe-uninitialized", + "-Wno-shadow", + ] + + if (silabs_family == "efr32mg24" || silabs_family == "mgm24") { + cflags += [ "-mcmse" ] + } + + if (defined(invoker.use_rs911x)) { + if (invoker.use_rs911x == true) { + #add compilation flags for rs991x build. This will be addressed directly in wiseconnect sdk in the next version release of that sdk + cflags += invoker.rs911x_cflags + } + } + + if (defined(invoker.defines)) { + defines += invoker.defines + } + } + + source_set("efr32_mbedtls_config") { + # We're setting the mbedTLS config flags here as the efr32_sdk target + # acts as the mbedTLS target for EFR32 builds. We need this for the build + # system to recompile mbedTLS (= the SDK) when the mbedTLS config gets + # edited. + sources = [ + "${chip_root}/src/platform/silabs/EFR32/efr32-chip-mbedtls-config.h", + "${chip_root}/src/platform/silabs/EFR32/efr32-mbedtls-psa-crypto-config.h", + ] + + public_deps = [ "${chip_root}/src/crypto:crypto_buildconfig" ] + } + + source_set(sdk_target_name) { + sources = [ + "${chip_root}/third_party/mbedtls/repo/include/mbedtls/platform.h", + "${efr32_sdk_root}/app/bluetooth/common/in_place_ota_dfu/sl_bt_in_place_ota_dfu.c", + "${efr32_sdk_root}/hardware/board/src/sl_board_control_gpio.c", + "${efr32_sdk_root}/hardware/board/src/sl_board_init.c", + "${efr32_sdk_root}/platform/CMSIS/RTOS2/Source/os_systick.c", + "${efr32_sdk_root}/platform/bootloader/api/btl_interface.c", + "${efr32_sdk_root}/platform/bootloader/api/btl_interface_storage.c", + "${efr32_sdk_root}/platform/bootloader/security/sha/crypto_sha.c", + "${efr32_sdk_root}/platform/common/src/sl_slist.c", + "${efr32_sdk_root}/platform/driver/button/src/sl_button.c", + "${efr32_sdk_root}/platform/driver/button/src/sl_simple_button.c", + "${efr32_sdk_root}/platform/emdrv/dmadrv/src/dmadrv.c", + "${efr32_sdk_root}/platform/emdrv/gpiointerrupt/src/gpiointerrupt.c", + "${efr32_sdk_root}/platform/emdrv/nvm3/src/nvm3_default.c", + "${efr32_sdk_root}/platform/emdrv/nvm3/src/nvm3_hal_flash.c", + "${efr32_sdk_root}/platform/emdrv/nvm3/src/nvm3_lock.c", + "${efr32_sdk_root}/platform/emlib/src/em_adc.c", + "${efr32_sdk_root}/platform/emlib/src/em_cmu.c", + "${efr32_sdk_root}/platform/emlib/src/em_core.c", + "${efr32_sdk_root}/platform/emlib/src/em_crypto.c", + "${efr32_sdk_root}/platform/emlib/src/em_emu.c", + "${efr32_sdk_root}/platform/emlib/src/em_gpio.c", + "${efr32_sdk_root}/platform/emlib/src/em_ldma.c", + "${efr32_sdk_root}/platform/emlib/src/em_msc.c", + "${efr32_sdk_root}/platform/emlib/src/em_prs.c", + "${efr32_sdk_root}/platform/emlib/src/em_rmu.c", + "${efr32_sdk_root}/platform/emlib/src/em_rtcc.c", + "${efr32_sdk_root}/platform/emlib/src/em_se.c", + "${efr32_sdk_root}/platform/emlib/src/em_system.c", + "${efr32_sdk_root}/platform/emlib/src/em_timer.c", + "${efr32_sdk_root}/platform/peripheral/src/peripheral_sysrtc.c", + "${efr32_sdk_root}/platform/radio/rail_lib/hal/efr32/hal_efr.c", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions/pa_conversions_efr32.c", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/rail_util_pti/sl_rail_util_pti.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_lfrco.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_nvic.c", + "${efr32_sdk_root}/platform/service/hfxo_manager/src/sl_hfxo_manager.c", + "${efr32_sdk_root}/platform/service/legacy_hal/src/token_legacy.c", + "${efr32_sdk_root}/platform/service/mpu/src/sl_mpu.c", + "${efr32_sdk_root}/platform/service/power_manager/src/sl_power_manager.c", + "${efr32_sdk_root}/platform/service/power_manager/src/sl_power_manager_debug.c", + "${efr32_sdk_root}/platform/service/power_manager/src/sl_power_manager_hal_s0_s1.c", + "${efr32_sdk_root}/platform/service/power_manager/src/sl_power_manager_hal_s2.c", + "${efr32_sdk_root}/platform/service/sleeptimer/src/sl_sleeptimer.c", + "${efr32_sdk_root}/platform/service/sleeptimer/src/sl_sleeptimer_hal_rtcc.c", + "${efr32_sdk_root}/platform/service/sleeptimer/src/sl_sleeptimer_hal_sysrtc.c", + "${efr32_sdk_root}/platform/service/system/src/sl_system_init.c", + "${efr32_sdk_root}/platform/service/system/src/sl_system_kernel.c", + "${efr32_sdk_root}/platform/service/system/src/sl_system_process_action.c", + "${efr32_sdk_root}/platform/service/token_manager/src/sl_token_def.c", + "${efr32_sdk_root}/platform/service/token_manager/src/sl_token_manager.c", + "${efr32_sdk_root}/platform/service/token_manager/src/sl_token_manufacturing.c", + "${efr32_sdk_root}/platform/service/udelay/src/sl_udelay.c", + "${efr32_sdk_root}/platform/service/udelay/src/sl_udelay_armv6m_gcc.S", + "${efr32_sdk_root}/protocol/bluetooth/src/sl_bt_mbedtls_context.c", + "${efr32_sdk_root}/protocol/bluetooth/src/sl_bt_rtos_adaptation.c", + "${efr32_sdk_root}/protocol/bluetooth/src/sl_bt_stack_init.c", + "${efr32_sdk_root}/protocol/bluetooth/src/sli_bt_advertiser_config.c", + "${efr32_sdk_root}/protocol/bluetooth/src/sli_bt_connection_config.c", + "${efr32_sdk_root}/util/silicon_labs/silabs_core/memory_manager/sl_malloc.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/aes.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/aesni.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/asn1parse.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/asn1write.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/base64.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/bignum.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/camellia.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ccm.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/chacha20.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/chachapoly.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/cipher_wrap.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/cmac.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/constant_time.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ctr_drbg.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/debug.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/des.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/dhm.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ecdh.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ecdsa.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ecjpake.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ecp.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ecp_curves.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/entropy.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/entropy_poll.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/gcm.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/hkdf.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/hmac_drbg.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/md.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/md5.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/oid.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/pem.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/pk.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/pk_wrap.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/pkcs12.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/pkcs5.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/pkparse.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/pkwrite.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/platform.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/platform_util.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/poly1305.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_aead.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_client.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_driver_wrappers.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_ecp.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_hash.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_rsa.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_se.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_slot_management.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_crypto_storage.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/psa_its_file.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ripemd160.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/rsa.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/sha1.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/sha256.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/sha512.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ssl_cache.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ssl_ciphersuites.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ssl_cli.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ssl_cookie.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ssl_msg.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ssl_srv.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ssl_ticket.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ssl_tls.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/ssl_tls13_keys.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/threading.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/timing.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/version.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/x509.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/x509_create.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/x509_crl.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/x509_crt.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/x509_csr.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/x509write_crt.c", + "${efr32_sdk_root}/util/third_party/crypto/mbedtls/library/x509write_csr.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/aes_aes.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/crypto_aes.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/crypto_ecp.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/error.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/mbedtls_ccm.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/mbedtls_cmac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/mbedtls_ecdsa_ecdh.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/mbedtls_sha.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/sl_entropy_hardware.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/sl_mbedtls.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/version_features.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_protocol_crypto/src/sli_protocol_crypto_crypto.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_protocol_crypto/src/sli_protocol_crypto_radioaes.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/crypto_management.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sl_psa_its_nvm3.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_crypto_transparent_driver_aead.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_crypto_transparent_driver_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_crypto_transparent_driver_hash.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_crypto_transparent_driver_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_crypto_trng_driver.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_psa_driver_common.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_psa_driver_init.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_psa_trng.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_builtin_keys.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_signature.c", + "${efr32_sdk_root}/util/third_party/freertos/cmsis/Source/cmsis_os2.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/croutine.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/event_groups.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/list.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/queue.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/stream_buffer.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/tasks.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/timers.c", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen/gatt_db.c", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen/sl_bluetooth.c", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen/sl_board_default_init.c", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen/sl_device_init_clocks.c", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen/sl_event_handler.c", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen/sl_simple_button_instances.c", + ] + + if (use_system_view) { + sources += [ + "${efr32_sdk_root}/util/third_party/segger/systemview/SEGGER/SEGGER_SYSVIEW.c", + "${efr32_sdk_root}/util/third_party/segger/systemview/Sample/FreeRTOSV10/Config/Cortex-M/SEGGER_SYSVIEW_Config_FreeRTOS.c", + "${efr32_sdk_root}/util/third_party/segger/systemview/Sample/FreeRTOSV10/SEGGER_SYSVIEW_FreeRTOS.c", + ] + } + + if (use_wstk_leds) { + sources += [ + "${efr32_sdk_root}/platform/driver/leddrv/src/sl_led.c", + "${efr32_sdk_root}/platform/driver/leddrv/src/sl_pwm_led.c", + "${efr32_sdk_root}/platform/driver/leddrv/src/sl_simple_led.c", + "${efr32_sdk_root}/platform/driver/leddrv/src/sl_simple_rgb_pwm_led.c", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen/sl_simple_led_instances.c", + ] + } + + # SPI is only used for Wifi + if (defined(invoker.chip_enable_wifi) && invoker.chip_enable_wifi) { + sources += [ + "${efr32_sdk_root}/platform/emdrv/spidrv/src/spidrv.c", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen/sl_spidrv_init.c", + ] + } + + if (defined(invoker.enable_sleepy_device)) { + if (invoker.enable_sleepy_device) { + sources += [ "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/SiliconLabs/tick_power_manager.c" ] + } + } + + if (defined(enable_fem)) { + sources += [ + "${efr32_sdk_root}/util/plugin/plugin-common/fem-control/fem-control.c", + ] + } + + # USART sources files + if ((defined(invoker.chip_enable_pw_rpc) && invoker.chip_enable_pw_rpc) || + chip_build_libshell || enable_openthread_cli || + (defined(invoker.chip_enable_wifi) && invoker.chip_enable_wifi) || + (defined(invoker.show_qr_code) && invoker.show_qr_code) || + (defined(invoker.disable_lcd) && !invoker.disable_lcd) || + (defined(invoker.use_external_flash) && use_external_flash)) { + sources += [ + "${efr32_sdk_root}/hardware/driver/memlcd/src/memlcd_usart/sl_memlcd_spi.c", + "${efr32_sdk_root}/platform/emdrv/uartdrv/src/uartdrv.c", + "${efr32_sdk_root}/platform/emlib/src/em_eusart.c", + "${efr32_sdk_root}/platform/emlib/src/em_leuart.c", + "${efr32_sdk_root}/platform/emlib/src/em_usart.c", + "${sdk_support_root}/matter/efr32/${silabs_family}/${silabs_board}/autogen/sl_uartdrv_init.c", + ] + + if (defined(invoker.use_external_flash) && use_external_flash) { + sources += [ "${efr32_sdk_root}/hardware/driver/mx25_flash_shutdown/src/sl_mx25_flash_shutdown_usart/sl_mx25_flash_shutdown.c" ] + } + } + + if ((defined(invoker.show_qr_code) && invoker.show_qr_code) || + (defined(invoker.disable_lcd) && !invoker.disable_lcd)) { + sources += [ + "${efr32_sdk_root}/hardware/driver/memlcd/src/sl_memlcd.c", + "${efr32_sdk_root}/hardware/driver/memlcd/src/sl_memlcd_display.c", + "${efr32_sdk_root}/platform/middleware/glib/dmd/display/dmd_memlcd.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/bmp.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/glib.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/glib_bitmap.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/glib_circle.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/glib_font_narrow_6x8.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/glib_font_normal_8x8.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/glib_font_number_16x20.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/glib_line.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/glib_polygon.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/glib_rectangle.c", + "${efr32_sdk_root}/platform/middleware/glib/glib/glib_string.c", + ] + } + + if (use_wf200) { + sources += [ + "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/bus/sl_wfx_bus.c", + "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/bus/sl_wfx_bus_spi.c", + "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/secure_link/sl_wfx_secure_link.c", + "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/sl_wfx.c", + ] + } + + if (silabs_family == "efr32mg12") { + sources += [ + "${efr32_sdk_root}/platform/Device/SiliconLabs/EFR32MG12P/Source/startup_efr32mg12p.c", + "${efr32_sdk_root}/platform/Device/SiliconLabs/EFR32MG12P/Source/system_efr32mg12p.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_dcdc_s1.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_emu_s1.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_hfxo_s1.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_lfxo_s1.c", + "${efr32_sdk_root}/protocol/bluetooth/src/sl_apploader_util_s1.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM4F/port.c", + ] + } else if (silabs_family == "efr32mg21") { + sources += [ + "${efr32_sdk_root}/platform/Device/SiliconLabs/EFR32MG21/Source/startup_efr32mg21.c", + "${efr32_sdk_root}/platform/Device/SiliconLabs/EFR32MG21/Source/system_efr32mg21.c", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/rail_util_rf_path/sl_rail_util_rf_path.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_emu_s2.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_hfrco.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_hfxo_s2.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_lfxo_s2.c", + "${efr32_sdk_root}/platform/service/hfxo_manager/src/sl_hfxo_manager_hal_s2.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_entropy.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_hash.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_key_derivation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_key_handling.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_signature.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_util.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_alt/source/sl_se_management.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/se_aes.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/se_gcm.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/se_jpake.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_protocol_crypto/src/sli_radioaes_management.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_aead.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_key_derivation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_key_management.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_driver_aead.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_driver_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_driver_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_key_derivation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_hash.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_key_derivation.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM33_NTZ/non_secure/port.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c", + ] + } else if (silabs_family == "efr32mg24") { + sources += [ + "${efr32_sdk_root}/platform/Device/SiliconLabs/EFR32MG24/Source/startup_efr32mg24.c", + "${efr32_sdk_root}/platform/Device/SiliconLabs/EFR32MG24/Source/system_efr32mg24.c", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions/pa_curves_efr32.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_dcdc_s2.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_emu_s2.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_hfxo_s2.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_lfxo_s2.c", + "${efr32_sdk_root}/platform/service/hfxo_manager/src/sl_hfxo_manager_hal_s2.c", + "${efr32_sdk_root}/protocol/bluetooth/src/sl_apploader_util_s2.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_attestation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_entropy.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_hash.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_key_derivation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_key_handling.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_signature.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_util.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/se_aes.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/se_jpake.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_protocol_crypto/src/sli_radioaes_management.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_aead.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_key_derivation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_key_management.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_driver_aead.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_driver_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_driver_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_key_derivation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_aead.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_hash.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_key_derivation.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM33_NTZ/non_secure/port.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c", + ] + } else if (silabs_family == "mgm24") { + sources += [ + "${efr32_sdk_root}/platform/Device/SiliconLabs/MGM24/Source/startup_mgm24.c", + "${efr32_sdk_root}/platform/Device/SiliconLabs/MGM24/Source/system_mgm24.c", + "${efr32_sdk_root}/platform/radio/rail_lib/plugin/pa-conversions/pa_curves_efr32.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_dcdc_s2.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_emu_s2.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_hfxo_mgm24.c", + "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_lfxo_s2.c", + "${efr32_sdk_root}/platform/service/hfxo_manager/src/sl_hfxo_manager_hal_s2.c", + "${efr32_sdk_root}/protocol/bluetooth/src/sl_apploader_util_s2.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_attestation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_entropy.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_hash.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_key_derivation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_key_handling.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_signature.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/se_manager/src/sl_se_manager_util.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/se_aes.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_mbedtls_support/src/se_jpake.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_protocol_crypto/src/sli_radioaes_management.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_aead.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_key_derivation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_key_management.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_driver_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_driver_aead.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_driver_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_driver_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_opaque_key_derivation.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_aead.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_cipher.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_hash.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_driver_mac.c", + "${efr32_sdk_root}/util/third_party/crypto/sl_component/sl_psa_driver/src/sli_se_transparent_key_derivation.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM33_NTZ/non_secure/port.c", + "${efr32_sdk_root}/util/third_party/freertos/kernel/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c", + ] + } + + if (silabs_board == "BRD4186A" || silabs_board == "BRD4186C" || + silabs_board == "BRD4187A" || silabs_board == "BRD4187C") { + sources += [ "${efr32_sdk_root}/platform/service/device_init/src/sl_device_init_dpll_s2.c" ] + } + + public_deps = [ + ":efr32_mbedtls_config", + "${segger_rtt_root}:segger_rtt", + "${segger_rtt_root}:segger_rtt_printf", + "${segger_rtt_root}:segger_rtt_syscalls", + ] + + if (defined(invoker.sources)) { + sources += invoker.sources + } + + public_configs = [ ":${sdk_target_name}_config" ] + } +}